Commit 865d4138 authored by Jared Jennings's avatar Jared Jennings Committed by Kamil Dudka
Browse files

curl -E: allow to escape ':' in cert nickname

parent 35874298
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ This release includes the following changes:
 o usercertinmem.c: add example showing user cert in memory
 o url: Added smtp and pop3 hostnames to the protocol detection list
 o imap/pop3/smtp: Added support for enabling the SASL initial response [8]
 o curl -E: allow to use ':' in certificate nicknames [10]
 o 

This release includes the following bugfixes:
@@ -67,4 +68,4 @@ References to bug reports and discussions on issues:
 [7] = http://curl.haxx.se/bug/view.cgi?id=1218
 [8] = http://curl.haxx.se/mail/lib-2012-03/0114.html
 [9] = http://curl.haxx.se/mail/lib-2013-05/0000.html
 [10]
 [10] = http://curl.haxx.se/bug/view.cgi?id=1196
+100 −23
Original line number Diff line number Diff line
@@ -286,6 +286,99 @@ static const struct feat feats[] = {
  {"TLS-SRP",        CURL_VERSION_TLSAUTH_SRP}
};

/* https://sourceforge.net/p/curl/bugs/1196/ */
static void parse_cert_parameter(const char *cert_parameter,
                                 char **certname,
                                 char **passphrase)
{
  size_t param_length = strlen(cert_parameter);
  size_t parsed_chars = 0;
  size_t span;
  const char *param_place = NULL;
  char *certname_place = NULL;
  /* most trivial assumption: cert_parameter is empty */
  if(param_length == 0) {
    *certname = NULL;
    *passphrase = NULL;
    return;
  }
  /* next less trivial: cert_parameter contains no colon nor backslash; this
   * means no passphrase was given and no characters escaped */
  if(!strpbrk(cert_parameter, ":\\")) {
    *certname = strdup(cert_parameter);
    *passphrase = NULL;
    return;
  }
  /* deal with escaped chars; find unescaped colon if it exists */
  *certname = (char *) malloc(param_length + 1);
  *passphrase = NULL;
  param_place = cert_parameter;
  certname_place = *certname;
  param_place = cert_parameter;
  while(*param_place) {
    span = strcspn(param_place, ":\\");
    strncpy(certname_place, param_place, span);
    param_place += span;
    certname_place += span;
    *certname_place = '\0';
    /* we just ate all the non-special chars. now we're on either a special
     * char or the end of the string. */
    switch(*param_place) {
    case '\0':
      break;
    case '\\':
      param_place++;
      switch(*param_place) {
        case '\0':
          *certname_place++ = '\\';
          break;
        case '\\':
          *certname_place++ = '\\';
          param_place++;
          break;
        case ':':
          *certname_place++ = ':';
          param_place++;
          break;
        default:
          *certname_place++ = '\\';
          *certname_place++ = *param_place;
          param_place++;
          break;
      }
      break;
    case ':':
      /* Since we live in a world of weirdness and confusion, the win32
         dudes can use : when using drive letters and thus c:\file:password
         needs to work. In order not to break compatibility, we still use : as
         separator, but we try to detect when it is used for a file name! On
         windows. */
#ifdef WIN32
      if(param_place &&
          (param_place == &cert_parameter[1]) &&
          (cert_parameter[2] == '\\' || cert_parameter[2] == '/') &&
          (ISALPHA(cert_parameter[0])) ) {
        /* colon in the second column, followed by a backslash, and the
           first character is an alphabetic letter:

           this is a drive letter colon */
        *certname_place++ = ':';
        param_place++;
        break;
      }
#endif
      /* escaped colons and Windows drive letter colons were handled
       * above; if we're still here, this is a separating colon */
      param_place++;
      if(strlen(param_place) > 0) {
        *passphrase = strdup(param_place);
      }
      return;
      break;
    }
  }
}

ParameterError getparameter(char *flag,    /* f or -long-flag */
                            char *nextarg, /* NULL if unset */
                            bool *usedarg, /* set to TRUE if the arg
@@ -1207,30 +1300,14 @@ ParameterError getparameter(char *flag, /* f or -long-flag */
        break;
      default: /* certificate file */
      {
        char *ptr = strchr(nextarg, ':');
        /* Since we live in a world of weirdness and confusion, the win32
           dudes can use : when using drive letters and thus
           c:\file:password needs to work. In order not to break
           compatibility, we still use : as separator, but we try to detect
           when it is used for a file name! On windows. */
#ifdef WIN32
        if(ptr &&
           (ptr == &nextarg[1]) &&
           (nextarg[2] == '\\' || nextarg[2] == '/') &&
           (ISALPHA(nextarg[0])) )
          /* colon in the second column, followed by a backslash, and the
             first character is an alphabetic letter:

             this is a drive letter colon */
          ptr = strchr(&nextarg[3], ':'); /* find the next one instead */
#endif
        if(ptr) {
          /* we have a password too */
          *ptr = '\0';
          ptr++;
          GetStr(&config->key_passwd, ptr);
        char *certname, *passphrase;
        parse_cert_parameter(nextarg, &certname, &passphrase);
        if(certname) {
          GetStr(&config->cert, certname);
        }
        if(passphrase) {
          GetStr(&config->key_passwd, passphrase);
        }
        GetStr(&config->cert, nextarg);
        cleanarg(nextarg);
      }
      }