--- cyrus-sasl-2.1.15/plugins/digestmd5.c.can-2005-0373 2003-03-30 15:17:06.000000000 -0700 +++ cyrus-sasl-2.1.15/plugins/digestmd5.c 2005-03-11 09:32:38.855599311 -0700 @@ -133,6 +133,10 @@ #define SP (32) #define DEL (127) +#define NEED_ESCAPING "\"\\" + +static char *quote (char *str); + struct context; /* function definitions for cipher encode/decode */ @@ -183,6 +187,11 @@ reauth_entry_t *e; /* fixed-size hash table of entries */ } reauth_cache_t; +/* global context for reauth use */ +typedef struct digest_glob_context { + reauth_cache_t *reauth; +} digest_glob_context_t; + /* context that stores info */ typedef struct context { int state; /* state in the authentication we are in */ @@ -491,21 +500,42 @@ ret = _plug_buf_alloc(utils, str, buflen, *curlen + 1 + namesize + 2 + valuesize + 2); if(ret != SASL_OK) return ret; - - *curlen = *curlen + 1 + namesize + 2 + valuesize + 2; - - strcat(*str, ","); - strcat(*str, name); + + if (*curlen > 0) { + strcat(*str, ","); + strcat(*str, name); + } else { + strcpy(*str, name); + } if (need_quotes) { strcat(*str, "=\""); - strcat(*str, (char *) value); /* XXX. What about quoting??? */ + + /* Check if the value needs quoting */ + if (strpbrk ((char *)value, NEED_ESCAPING) != NULL) { + char * quoted = quote ((char *) value); + valuesize = strlen(quoted); + /* As the quoted string is bigger, make sure we have enough + space now */ + ret = _plug_buf_alloc(utils, str, buflen, + *curlen + 1 + namesize + 2 + valuesize + 2); + if (ret == SASL_OK) { + strcat(*str, quoted); + free (quoted); + } else { + free (quoted); + return ret; + } + } else { + strcat(*str, (char *) value); + } strcat(*str, "\""); } else { strcat(*str, "="); strcat(*str, (char *) value); } + *curlen = *curlen + 1 + namesize + 2 + valuesize + 2; return SASL_OK; } @@ -544,7 +574,8 @@ } /* NULL - error (unbalanced quotes), - otherwise pointer to the first character after value */ + otherwise pointer to the first character after the value. + The function performs work in place. */ static char *unquote (char *qstr) { char *endvalue; @@ -585,11 +616,48 @@ endvalue++; } else { /* not qouted value (token) */ + /* qstr already contains output */ endvalue = skip_token(qstr,0); }; return endvalue; -} +} + +/* Unlike unquote, this function returns an allocated quoted copy */ +static char *quote (char *str) +{ + char *p; + char *outp; + char *result; + int num_to_escape; /* How many characters need escaping */ + + if (!str) return NULL; + + num_to_escape = 0; + p = strpbrk (str, NEED_ESCAPING); + while (p != NULL) { + num_to_escape++; + p = strpbrk (p + 1, NEED_ESCAPING); + } + + if (num_to_escape == 0) { + return (strdup (str)); + } + + result = malloc (strlen(str) + num_to_escape + 1); + for (p = str, outp = result; *p; p++) { + if (*p == '"' || *p == '\\') { + *outp = '\\'; + outp++; + } + *outp = *p; + outp++; + } + + *outp = '\0'; + + return (result); +} static void get_pair(char **in, char **name, char **value) { @@ -1738,7 +1806,9 @@ static void digestmd5_common_mech_free(void *glob_context, const sasl_utils_t *utils) { - reauth_cache_t *reauth_cache = (reauth_cache_t *) glob_context; + digest_glob_context_t *my_glob_context = + (digest_glob_context_t *) glob_context; + reauth_cache_t *reauth_cache = my_glob_context->reauth; size_t n; if (!reauth_cache) return; @@ -1750,6 +1820,7 @@ if (reauth_cache->mutex) utils->mutex_free(reauth_cache->mutex); utils->free(reauth_cache); + my_glob_context->reauth = NULL; } /***************************** Server Section *****************************/ @@ -1762,6 +1833,8 @@ sasl_ssf_t limitssf, requiressf; /* application defined bounds */ } server_context_t; +static digest_glob_context_t server_glob_context; + static void DigestCalcHA1FromSecret(context_t * text, const sasl_utils_t * utils, @@ -1953,7 +2026,7 @@ text->state = 1; text->i_am = SERVER; - text->reauth = glob_context; + text->reauth = ((digest_glob_context_t *) glob_context)->reauth; *conn_context = text; return SASL_OK; @@ -2032,13 +2105,17 @@ return SASL_FAIL; } - resplen = strlen(nonce) + strlen("nonce") + 5; - result = _plug_buf_alloc(sparams->utils, &(text->out_buf), - &(text->out_buf_len), resplen); - if(result != SASL_OK) return result; - - sprintf(text->out_buf, "nonce=\"%s\"", nonce); - + resplen = 0; + text->out_buf = NULL; + text->out_buf_len = 0; + if (add_to_challenge(sparams->utils, + &text->out_buf, &text->out_buf_len, &resplen, + "nonce", (unsigned char *) nonce, + TRUE) != SASL_OK) { + SETERROR(sparams->utils, "internal error: add_to_challenge failed"); + return SASL_FAIL; + } + /* add to challenge; if we chose not to specify a realm, we won't * send one to the client */ if (realm && add_to_challenge(sparams->utils, @@ -2830,7 +2907,7 @@ | SASL_SEC_NOANONYMOUS | SASL_SEC_MUTUAL_AUTH, /* security_flags */ SASL_FEAT_ALLOWS_PROXY, /* features */ - NULL, /* glob_context */ + &server_glob_context, /* glob_context */ &digestmd5_server_mech_new, /* mech_new */ &digestmd5_server_mech_step, /* mech_step */ &digestmd5_server_mech_dispose, /* mech_dispose */ @@ -2886,7 +2963,7 @@ memset(reauth_cache->e, 0, reauth_cache->size * sizeof(reauth_entry_t)); } - digestmd5_server_plugins[0].glob_context = reauth_cache; + ((digest_glob_context_t *) digestmd5_server_plugins[0].glob_context)->reauth = reauth_cache; *out_version = SASL_SERVER_PLUG_VERSION; *pluglist = digestmd5_server_plugins; @@ -2908,6 +2985,8 @@ unsigned int server_maxbuf; } client_context_t; +static digest_glob_context_t client_glob_context; + /* calculate H(A1) as per spec */ static void DigestCalcHA1(context_t * text, @@ -3054,7 +3133,7 @@ char maxbufstr[64]; char *response = NULL; unsigned resplen = 0; - int result; + int result = SASL_OK; switch (ctext->protection) { case DIGEST_PRIVACY: @@ -3116,14 +3195,17 @@ &text->response_value); - resplen = strlen(oparams->authid) + strlen("username") + 5; - result =_plug_buf_alloc(params->utils, &(text->out_buf), - &(text->out_buf_len), - resplen); - if (result != SASL_OK) goto FreeAllocatedMem; - - sprintf(text->out_buf, "username=\"%s\"", oparams->authid); - + resplen = 0; + text->out_buf = NULL; + text->out_buf_len = 0; + if (add_to_challenge(params->utils, + &text->out_buf, &text->out_buf_len, &resplen, + "username", (unsigned char *) oparams->authid, + TRUE) != SASL_OK) { + result = SASL_FAIL; + goto FreeAllocatedMem; + } + if (add_to_challenge(params->utils, &text->out_buf, &text->out_buf_len, &resplen, "realm", (unsigned char *) text->realm, @@ -3712,7 +3794,7 @@ text->state = 1; text->i_am = CLIENT; - text->reauth = glob_context; + text->reauth = ((digest_glob_context_t *) glob_context)->reauth; *conn_context = text; @@ -3896,7 +3978,7 @@ if (strcmp(text->response_value, value) != 0) { params->utils->seterror(params->utils->conn, 0, "DIGEST-MD5: This server wants us to believe that he knows shared secret"); - result = SASL_FAIL; + result = SASL_BADSERV; } else { oparams->doneflag = 1; oparams->param_version = 0; @@ -4070,7 +4152,7 @@ | SASL_SEC_MUTUAL_AUTH, /* security_flags */ SASL_FEAT_ALLOWS_PROXY, /* features */ NULL, /* required_prompts */ - NULL, /* glob_context */ + &client_glob_context, /* glob_context */ &digestmd5_client_mech_new, /* mech_new */ &digestmd5_client_mech_step, /* mech_step */ &digestmd5_client_mech_dispose, /* mech_dispose */ @@ -4112,7 +4194,7 @@ return SASL_NOMEM; memset(reauth_cache->e, 0, reauth_cache->size * sizeof(reauth_entry_t)); - digestmd5_client_plugins[0].glob_context = reauth_cache; + ((digest_glob_context_t *) digestmd5_client_plugins[0].glob_context)->reauth = reauth_cache; *out_version = SASL_CLIENT_PLUG_VERSION; *pluglist = digestmd5_client_plugins;