diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 712706865..32ca6290f 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -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 diff --git a/src/tool_getparam.c b/src/tool_getparam.c index b44b9c020..55750c911 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -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); } }