break;
} while (1);
+ 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
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),
if (result != 0)
goto done;
- if (SASL_CB_PRESENT(c_conn->cparams)) {
- if (server_can_cb == 0 && SASL_CB_CRITICAL(c_conn->cparams)) {
- result = SASL_BADBINDING;
- goto done;
- } else {
- cbindingdisp = SASL_CB_DISP_WANT;
- }
- } else {
- cbindingdisp = SASL_CB_DISP_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;
}
- /*
- * Include channel bindings if present and the server supports
- * them or we are not negotiating mechanisms.
- */
- if (SASL_CB_PRESENT(c_conn->cparams) && (plus || list_len == 1)) {
+ if (SASL_CB_PRESENT(c_conn->cparams) && plus) {
cbindingdisp = SASL_CB_DISP_USED;
}
void usage(void)
{
- fprintf(stderr, "usage: client [-c] [-p port] [-s service] [-m mech] host\n");
+ fprintf(stderr, "usage: client [-c|-C] [-p port] [-s service] [-m mech] host\n");
exit(EX_USAGE);
}
int cb_flag = 0;
sasl_channel_binding_t cb;
- while ((c = getopt(argc, argv, "cp:s:m:")) != EOF) {
+ while ((c = getopt(argc, argv, "Ccp:s:m:")) != EOF) {
switch(c) {
+ case 'C':
+ cb_flag = 2; /* channel bindings are critical */
+ break;
+
case 'c':
- cb_flag = 1;
+ cb_flag = 1; /* channel bindings are optional */
break;
case 'p':
if (cb_flag) {
cb.name = "sasl-sample";
+ cb.critical = cb_flag > 1;
cb.data = "this is a test of channel binding";
cb.len = strlen(cb.data);
void usage(void)
{
- fprintf(stderr, "usage: server [-c] [-h hostname] [-p port] [-s service] [-m mech]\n");
+ fprintf(stderr, "usage: server [-C] [-h hostname] [-p port] [-s service] [-m mech]\n");
exit(EX_USAGE);
}
sasl_conn_t *conn;
int cb_flag = 0;
- while ((c = getopt(argc, argv, "ch:p:s:m:")) != EOF) {
+ while ((c = getopt(argc, argv, "Cch:p:s:m:")) != EOF) {
switch(c) {
+ case 'C':
+ cb_flag = 2; /* channel bindings are critical */
+ break;
+
case 'c':
- cb_flag = 1;
+ cb_flag = 1; /* channel bindings are present */
break;
case 'h':
if (r != SASL_OK) saslfail(r, "allocating connection state");
cb.name = "sasl-sample";
- cb.critical = cb_flag;
+ cb.critical = cb_flag > 1;
cb.data = "this is a test of channel binding";
cb.len = strlen(cb.data);
- sasl_setprop(conn, SASL_CHANNEL_BINDING, &cb);
+ if (cb_flag)
+ sasl_setprop(conn, SASL_CHANNEL_BINDING, &cb);
/* set external properties here
sasl_setprop(conn, SASL_SSF_EXTERNAL, &extprops); */