Fix CB support when client selects mechanism explicitly
authorLuke Howard <lukeh@padl.com>
Tue, 28 Sep 2010 15:31:07 +0000 (17:31 +0200)
committerLuke Howard <lukeh@padl.com>
Tue, 28 Sep 2010 15:31:07 +0000 (17:31 +0200)
lib/client.c
sample/client.c
sample/server.c

index 0783906..58aeb0d 100644 (file)
@@ -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;
            }
 
index c6e5b98..00bbb41 100644 (file)
@@ -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);
 
index 3731e02..0b5a274 100644 (file)
@@ -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); */