/* 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
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)
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
* 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,
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;
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),
&list_len,
&server_can_cb);
if (result != 0)
- return result;
+ goto done;
- /* If we have CB and the server supports it, we should use it */
- 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 */
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;
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 */
/* 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;
/* 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
m = m->next;
}
} else {
- mech_list = strdup (c_mech_list);
+ mech_list = strdup (c_mech_list);
cur_mech = mech_list;
cur_mech = p;
}
- free (mech_list);
+ free (mech_list);
}
info_cb (NULL, SASL_INFO_LIST_END, info_cb_rock);