X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=lib%2Fclient.c;h=58aeb0dfa2fa349fc9910404a7e318fd31528fec;hb=3055b24f28d15371f02dfc0dff751c93fb413c3e;hp=b4ea7aab2f0156145bfc909cc91052a6deb76fe8;hpb=5151f14f5b644b1fe2ad02bc4f2c30a945edb145;p=cyrus-sasl.git diff --git a/lib/client.c b/lib/client.c index b4ea7aa..58aeb0d 100644 --- a/lib/client.c +++ b/lib/client.c @@ -185,7 +185,7 @@ client_idle(sasl_conn_t *conn) /* initialize the SASL client drivers * callbacks -- base callbacks for all client connections * returns: - * SASL_OK -- Success + * SASL_OK -- Success * SASL_NOMEM -- Not enough memory * SASL_BADVERS -- Mechanism version mismatch * SASL_BADPARAM -- error in config file @@ -409,33 +409,45 @@ _sasl_client_order_mechs(const sasl_utils_t *utils, int *server_can_cb) { char *list, *listp; - size_t i; - const char *p, *start = NULL; + size_t i, mechslen, start; *count = 0; *server_can_cb = 0; - listp = list = utils->malloc(strlen(mechs) + 1); + if (mechs == NULL || mechs[0] == '\0') + return SASL_NOMECH; + + mechslen = strlen(mechs); + + listp = list = utils->malloc(mechslen + 1); if (list == NULL) return SASL_NOMEM; + /* xxx confirm this with rfc 2222 + * SASL mechanism allowable characters are "AZaz-_" + * seperators can be any other characters and of any length + * even variable lengths between + * + * Apps should be encouraged to simply use space or comma space + * though + */ +#define ismechchar(c) (isalnum((c)) || (c) == '_' || (c) == '-') do { - for (start = p = mechs, i = 0; *p != '\0'; p++) { - if (isspace(*p) || p[1] == '\0') { - size_t len = p - start; - - if (p[1] == '\0') - len++; - - if (_mech_plus_p(start, len) == has_cb_data) { - memcpy(listp, start, len); + for (i = start = 0; i <= mechslen; i++) { + if (!ismechchar(mechs[i])) { + const char *mechp = &mechs[start]; + size_t len = i - start; + + if (len != 0 && + _mech_plus_p(mechp, len) == has_cb_data) { + memcpy(listp, mechp, len); listp[len] = '\0'; listp += len + 1; (*count)++; if (*server_can_cb == 0 && has_cb_data) *server_can_cb = 1; } - start = p + 1; + start = ++i; } } if (has_cb_data) @@ -444,19 +456,55 @@ _sasl_client_order_mechs(const sasl_utils_t *utils, break; } while (1); - *listp = '\0'; + if (*count == 0) { + utils->free(list); + return SASL_NOMECH; + } + *ordered_mechs = list; return SASL_OK; } +static inline int +_sasl_cbinding_disp(sasl_client_params_t *cparams, + int mech_nego, + int server_can_cb, + unsigned int *cbindingdisp) +{ + /* + * If negotiating mechanisms, then we fail immediately if the + * client requires channel binding and the server does not + * advertise support. Otherwise we send "y" (which later will + * become "p" if we select a supporting mechanism). + * + * If the client explicitly selected a mechanism, then we only + * send channel bindings if they're marked critical. + */ + + *cbindingdisp = SASL_CB_DISP_NONE; + + if (SASL_CB_PRESENT(cparams)) { + if (mech_nego) { + if (!server_can_cb && SASL_CB_CRITICAL(cparams)) + return SASL_NOMECH; + else + *cbindingdisp = SASL_CB_DISP_WANT; + } else if (SASL_CB_CRITICAL(cparams)) { + *cbindingdisp = SASL_CB_DISP_USED; + } + } + + return SASL_OK; +} + /* select a mechanism for a connection * mechlist -- mechanisms server has available (punctuation ignored) - * secret -- optional secret from previous session + * secret -- optional secret from previous session * output: * prompt_need -- on SASL_INTERACT, list of prompts needed to continue * clientout -- the initial client response to send to the server - * mech -- set to mechanism name + * mech -- set to mechanism name * * Returns: * SASL_OK -- success @@ -465,14 +513,6 @@ _sasl_client_order_mechs(const sasl_utils_t *utils, * SASL_INTERACT -- user interaction needed to fill in prompt_need list */ -/* xxx confirm this with rfc 2222 - * SASL mechanism allowable characters are "AZaz-_" - * seperators can be any other characters and of any length - * even variable lengths between - * - * Apps should be encouraged to simply use space or comma space - * though - */ int sasl_client_start(sasl_conn_t *conn, const char *mechlist, sasl_interact_t **prompt_need, @@ -486,6 +526,7 @@ int sasl_client_start(sasl_conn_t *conn, size_t i, list_len; sasl_ssf_t bestssf = 0, minssf = 0; int result, server_can_cb = 0; + unsigned int cbindingdisp; if(_sasl_client_active==0) return SASL_NOTINIT; @@ -510,6 +551,7 @@ int sasl_client_start(sasl_conn_t *conn, minssf = conn->props.min_ssf - conn->external.ssf; } + /* Order mechanisms so -PLUS are preferred */ result = _sasl_client_order_mechs(c_conn->cparams->utils, mechlist, SASL_CB_PRESENT(c_conn->cparams), @@ -517,12 +559,17 @@ int sasl_client_start(sasl_conn_t *conn, &list_len, &server_can_cb); if (result != 0) - return result; + goto done; - if (SASL_CB_PRESENT(c_conn->cparams) && server_can_cb) - c_conn->cparams->chanbindingflag = SASL_CB_FLAG_WANT; - else - c_conn->cparams->chanbindingflag = SASL_CB_FLAG_NONE; + /* + * Determine channel binding disposition based on whether we + * are doing mechanism negotiation and whether server supports + * channel bindings. + */ + result = _sasl_cbinding_disp(c_conn->cparams, (list_len > 1), + server_can_cb, &cbindingdisp); + if (result != 0) + goto done; for (i = 0, name = ordered_mechs; i < list_len; i++) { /* foreach in client list */ @@ -608,9 +655,9 @@ int sasl_client_start(sasl_conn_t *conn, break; } - /* Prefer server advertised CB mechanisms */ - if (SASL_CB_PRESENT(c_conn->cparams) && plus) - c_conn->cparams->chanbindingflag = SASL_CB_FLAG_USED; + if (SASL_CB_PRESENT(c_conn->cparams) && plus) { + cbindingdisp = SASL_CB_DISP_USED; + } if (mech) { *mech = m->m.plug->mech_name; @@ -642,6 +689,7 @@ int sasl_client_start(sasl_conn_t *conn, c_conn->cparams->external_ssf = conn->external.ssf; c_conn->cparams->props = conn->props; + c_conn->cparams->cbindingdisp = cbindingdisp; c_conn->mech = bestm; /* init that plugin */ @@ -653,14 +701,14 @@ int sasl_client_start(sasl_conn_t *conn, /* do a step -- but only if we can do a client-send-first */ dostep: if(clientout) { - if(c_conn->mech->m.plug->features & SASL_FEAT_SERVER_FIRST) { - *clientout = NULL; - *clientoutlen = 0; - result = SASL_CONTINUE; - } else { - result = sasl_client_step(conn, NULL, 0, prompt_need, - clientout, clientoutlen); - } + if(c_conn->mech->m.plug->features & SASL_FEAT_SERVER_FIRST) { + *clientout = NULL; + *clientoutlen = 0; + result = SASL_CONTINUE; + } else { + result = sasl_client_step(conn, NULL, 0, prompt_need, + clientout, clientoutlen); + } } else result = SASL_CONTINUE; @@ -673,13 +721,13 @@ int sasl_client_start(sasl_conn_t *conn, /* do a single authentication step. * serverin -- the server message received by the client, MUST have a NUL - * sentinel, not counted by serverinlen + * sentinel, not counted by serverinlen * output: * prompt_need -- on SASL_INTERACT, list of prompts needed to continue * clientout -- the client response to send to the server * * returns: - * SASL_OK -- success + * SASL_OK -- success * SASL_INTERACT -- user interaction needed to fill in prompt_need list * SASL_BADPROT -- server protocol incorrect/cancelled * SASL_BADSERV -- server failed mutual auth @@ -1057,7 +1105,7 @@ int sasl_client_plugin_info ( m = m->next; } } else { - mech_list = strdup (c_mech_list); + mech_list = strdup (c_mech_list); cur_mech = mech_list; @@ -1083,7 +1131,7 @@ int sasl_client_plugin_info ( cur_mech = p; } - free (mech_list); + free (mech_list); } info_cb (NULL, SASL_INFO_LIST_END, info_cb_rock);