From 3055b24f28d15371f02dfc0dff751c93fb413c3e Mon Sep 17 00:00:00 2001 From: Luke Howard Date: Tue, 28 Sep 2010 17:31:07 +0200 Subject: [PATCH] Fix CB support when client selects mechanism explicitly --- lib/client.c | 63 +++++++++++++++++++++++++++++++++++++++++++-------------- sample/client.c | 11 +++++++--- sample/server.c | 15 +++++++++----- 3 files changed, 66 insertions(+), 23 deletions(-) diff --git a/lib/client.c b/lib/client.c index 0783906..58aeb0d 100644 --- a/lib/client.c +++ b/lib/client.c @@ -456,11 +456,48 @@ _sasl_client_order_mechs(const sasl_utils_t *utils, 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 @@ -514,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), @@ -523,16 +561,15 @@ int sasl_client_start(sasl_conn_t *conn, 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 */ @@ -618,11 +655,7 @@ int sasl_client_start(sasl_conn_t *conn, 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; } diff --git a/sample/client.c b/sample/client.c index c6e5b98..00bbb41 100644 --- a/sample/client.c +++ b/sample/client.c @@ -321,7 +321,7 @@ int mysasl_negotiate(FILE *in, FILE *out, sasl_conn_t *conn) 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); } @@ -344,10 +344,14 @@ int main(int argc, char *argv[]) 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': @@ -427,6 +431,7 @@ int main(int argc, char *argv[]) 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); diff --git a/sample/server.c b/sample/server.c index 3731e02..0b5a274 100644 --- a/sample/server.c +++ b/sample/server.c @@ -185,7 +185,7 @@ int *listensock(const char *port, const int af) 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); } @@ -325,10 +325,14 @@ int main(int argc, char *argv[]) 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': @@ -454,11 +458,12 @@ int main(int argc, char *argv[]) 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); */ -- 2.1.4