complete moving logic to server
authorLuke Howard <lukeh@padl.com>
Mon, 27 Sep 2010 00:26:10 +0000 (02:26 +0200)
committerLuke Howard <lukeh@padl.com>
Mon, 27 Sep 2010 00:26:10 +0000 (02:26 +0200)
lib/client.c
lib/common.c
lib/server.c
plugins/gs2.c
sample/server.c

index 4c35519..2f627c1 100644 (file)
@@ -390,6 +390,72 @@ static int have_prompts(sasl_conn_t *conn,
   return 1; /* we have all the prompts */
 }
 
   return 1; /* we have all the prompts */
 }
 
+static int
+_mech_plus_p(const char *mech, size_t len)
+{
+    return (len > 5 && strncasecmp(&mech[len - 5], "-PLUS", 5) == 0);
+}
+
+/*
+ * Order PLUS mechanisms first. Returns NUL separated list of
+ * *count items.
+ */
+static int
+_sasl_client_order_mechs(const sasl_utils_t *utils,
+                         const char *mechs,
+                         int has_cb_data,
+                         char **ordered_mechs,
+                         size_t *count,
+                         int *server_can_cb)
+{
+    char *list, *listp;
+    size_t i;
+    const char *p, *start  = NULL;
+
+    *count = 0;
+    *server_can_cb = 0;
+
+    listp = list = utils->malloc(strlen(mechs) + 1);
+    if (list == NULL)
+        return SASL_NOMEM;
+
+    if (has_cb_data) {
+        for (start = p = mechs, i = 0; *p != '\0'; p++) {
+            if (isspace(*p) || p[1] == '\0') {
+                size_t len = p - start + 1;
+
+                if (_mech_plus_p(start, len)) {
+                    memcpy(listp, start, len);
+                    listp[len] = '\0';
+                    listp += len + 1;
+                    (*count)++;
+                    *server_can_cb = 1;
+                }
+                start = p + 1;
+            }
+        }
+    }
+
+    for (start = p = mechs, i = 0; *p != '\0'; p++) {
+        if (isspace(*p) || p[1] == '\0') {
+            size_t len = p - start + 1;
+
+            if (!_mech_plus_p(start, len)) {
+                memcpy(listp, start, len);
+                listp[len] = '\0';
+                listp += len + 1;
+                (*count)++;
+            }
+            start = p + 1;
+        }
+    }
+
+    *listp = '\0';
+    *ordered_mechs = list;
+
+    return SASL_OK;
+}
+
 /* select a mechanism for a connection
  *  mechlist      -- mechanisms server has available (punctuation ignored)
  *  secret        -- optional secret from previous session
 /* select a mechanism for a connection
  *  mechlist      -- mechanisms server has available (punctuation ignored)
  *  secret        -- optional secret from previous session
@@ -421,12 +487,11 @@ int sasl_client_start(sasl_conn_t *conn,
                      const char **mech)
 {
     sasl_client_conn_t *c_conn= (sasl_client_conn_t *) conn;
                      const char **mech)
 {
     sasl_client_conn_t *c_conn= (sasl_client_conn_t *) conn;
-    char name[SASL_MECHNAMEMAX + 1];
+    char *ordered_mechs = NULL, *name;
     cmechanism_t *m=NULL,*bestm=NULL;
     cmechanism_t *m=NULL,*bestm=NULL;
-    size_t pos=0,place;
-    size_t list_len;
+    size_t i, list_len;
     sasl_ssf_t bestssf = 0, minssf = 0;
     sasl_ssf_t bestssf = 0, minssf = 0;
-    int result;
+    int result, server_can_cb = 0;
 
     if(_sasl_client_active==0) return SASL_NOTINIT;
 
 
     if(_sasl_client_active==0) return SASL_NOTINIT;
 
@@ -451,33 +516,22 @@ int sasl_client_start(sasl_conn_t *conn,
        minssf = conn->props.min_ssf - conn->external.ssf;
     }
 
        minssf = conn->props.min_ssf - conn->external.ssf;
     }
 
-    c_conn->cparams->chanbindingflag = SASL_CB_FLAG_NONE;
-
-    /* parse mechlist */
-    list_len = strlen(mechlist);
-
-    while (pos<list_len)
-    {
-       place=0;
-       while ((pos<list_len) && (isalnum((unsigned char)mechlist[pos])
-                                 || mechlist[pos] == '_'
-                                 || mechlist[pos] == '-')) {
-           name[place]=mechlist[pos];
-           pos++;
-           place++;
-           if (SASL_MECHNAMEMAX < place) {
-               place--;
-               while(pos<list_len && (isalnum((unsigned char)mechlist[pos])
-                                      || mechlist[pos] == '_'
-                                      || mechlist[pos] == '-'))
-                   pos++;
-           }
-       }
-       pos++;
-       name[place]=0;
-
-       if (! place) continue;
+    result = _sasl_client_order_mechs(c_conn->cparams->utils,
+                                      mechlist,
+                                      SASL_CB_PRESENT(c_conn->cparams),
+                                      &ordered_mechs,
+                                      &list_len,
+                                      &server_can_cb);
+    if (result != 0)
+        return result;
+
+    /* 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;
 
 
+    for (i = 0, name = ordered_mechs; i < list_len; i++) {
        /* foreach in client list */
        for (m = cmechlist->mech_list; m != NULL; m = m->next) {
            int myflags, plus;
        /* foreach in client list */
        for (m = cmechlist->mech_list; m != NULL; m = m->next) {
            int myflags, plus;
@@ -556,12 +610,9 @@ int sasl_client_start(sasl_conn_t *conn,
                break;
            }
 
                break;
            }
 
-            if (SASL_CB_PRESENT(c_conn->cparams)) {
-                if (plus)
-                    c_conn->cparams->chanbindingflag = SASL_CB_FLAG_USED;
-                else
-                    c_conn->cparams->chanbindingflag = SASL_CB_FLAG_WANT;
-            }
+            /* Prefer server advertised CB mechanisms */
+            if (SASL_CB_PRESENT(c_conn->cparams) && plus)
+                c_conn->cparams->chanbindingflag = SASL_CB_FLAG_USED;
 
            if (mech) {
                *mech = m->m.plug->mech_name;
 
            if (mech) {
                *mech = m->m.plug->mech_name;
@@ -570,6 +621,7 @@ int sasl_client_start(sasl_conn_t *conn,
            bestm = m;
            break;
        }
            bestm = m;
            break;
        }
+        name += strlen(name) + 1;
     }
 
     if (bestm == NULL) {
     }
 
     if (bestm == NULL) {
@@ -616,6 +668,8 @@ int sasl_client_start(sasl_conn_t *conn,
        result = SASL_CONTINUE;
 
  done:
        result = SASL_CONTINUE;
 
  done:
+    if (ordered_mechs != NULL)
+        c_conn->cparams->utils->free(ordered_mechs);
     RETURN(conn, result);
 }
 
     RETURN(conn, result);
 }
 
index 9a8e8ce..620395a 100644 (file)
@@ -1213,9 +1213,9 @@ int sasl_setprop(sasl_conn_t *conn, int propnum, const void *value)
 
     if (conn->type == SASL_CONN_SERVER) {
         ((sasl_server_conn_t *)conn)->sparams->chanbindingtype = cb->type;
 
     if (conn->type == SASL_CONN_SERVER) {
         ((sasl_server_conn_t *)conn)->sparams->chanbindingtype = cb->type;
-        ((sasl_server_conn_t *)conn)->sparams->chanbindingcrit = cb->critical;
         ((sasl_server_conn_t *)conn)->sparams->chanbindingdata = cb->data;
         ((sasl_server_conn_t *)conn)->sparams->chanbindinglen = cb->len;
         ((sasl_server_conn_t *)conn)->sparams->chanbindingdata = cb->data;
         ((sasl_server_conn_t *)conn)->sparams->chanbindinglen = cb->len;
+        ((sasl_server_conn_t *)conn)->sparams->chanbindingcrit = cb->critical;
     } else {
         ((sasl_client_conn_t *)conn)->cparams->chanbindingtype = cb->type;
         ((sasl_client_conn_t *)conn)->cparams->chanbindingdata = cb->data;
     } else {
         ((sasl_client_conn_t *)conn)->cparams->chanbindingtype = cb->type;
         ((sasl_client_conn_t *)conn)->cparams->chanbindingdata = cb->data;
index 4cdf456..f4a50bd 100644 (file)
@@ -1462,7 +1462,7 @@ int sasl_server_step(sasl_conn_t *conn,
         } else if (conn->oparams.chanbindingflag == SASL_CB_FLAG_WANT &&
             SASL_CB_PRESENT(s_conn->sparams)) {
             sasl_seterror(conn, 0,
         } else if (conn->oparams.chanbindingflag == SASL_CB_FLAG_WANT &&
             SASL_CB_PRESENT(s_conn->sparams)) {
             sasl_seterror(conn, 0,
-                          "client incorrectly determined server had no channel binding");
+                          "client incorrectly assumed server had no channel binding");
             ret = SASL_BADAUTH;
         } else if (conn->oparams.user == NULL || conn->oparams.authid == NULL) {
            sasl_seterror(conn, 0,
             ret = SASL_BADAUTH;
         } else if (conn->oparams.user == NULL || conn->oparams.authid == NULL) {
            sasl_seterror(conn, 0,
@@ -1567,25 +1567,34 @@ int _sasl_server_listmech(sasl_conn_t *conn,
   for (lup = 0; lup < mechlist->mech_length; lup++) {
       /* currently, we don't use the "user" parameter for anything */
       if (mech_permitted(conn, listptr) == SASL_OK) {
   for (lup = 0; lup < mechlist->mech_length; lup++) {
       /* currently, we don't use the "user" parameter for anything */
       if (mech_permitted(conn, listptr) == SASL_OK) {
-         if (pcount != NULL)
+          /*
+           * If the server would never succeed in the authentication of 
+           * he non-PLUS-variant due to policy reasons, it MUST advertise
+           * only the PLUS-variant.
+           */
+          if (!s_conn->sparams->chanbindingcrit) {
+            if (pcount != NULL)
              (*pcount)++;
              (*pcount)++;
-
-         /* print separator */
-         if (flag) {
-             strcat(conn->mechlist_buf, mysep);
-         } else {
-             flag = 1;
-         }
-
-         /* now print the mechanism name */
-         strcat(conn->mechlist_buf, listptr->m.plug->mech_name);
-
-         /* advertise -PLUS variant if mechanism and application support CB */
+            if (flag)
+              strcat(conn->mechlist_buf, mysep);
+            else
+              flag = 1;
+           strcat(conn->mechlist_buf, listptr->m.plug->mech_name);
+          }
+          /*
+           * If the server cannot support channel binding, it SHOULD
+           * advertise only the non-PLUS-variant. Here, supporting channel
+           * binding means the underlying SASL mechanism supports it and
+           * the application has set some channel binding data.
+           */
          if ((listptr->m.plug->features & SASL_FEAT_CHANNEL_BINDING) &&
              SASL_CB_PRESENT(s_conn->sparams)) {
            if (pcount != NULL)
                (*pcount)++;
          if ((listptr->m.plug->features & SASL_FEAT_CHANNEL_BINDING) &&
              SASL_CB_PRESENT(s_conn->sparams)) {
            if (pcount != NULL)
                (*pcount)++;
-           strcat(conn->mechlist_buf, mysep);
+            if (flag)
+              strcat(conn->mechlist_buf, mysep);
+            else
+              flag = 1;
            strcat(conn->mechlist_buf, listptr->m.plug->mech_name);
            strcat(conn->mechlist_buf, "-PLUS");
          }
            strcat(conn->mechlist_buf, listptr->m.plug->mech_name);
            strcat(conn->mechlist_buf, "-PLUS");
          }
index fefa9af..85f2c30 100644 (file)
@@ -62,9 +62,9 @@
 #include "gs2_token.h"
 
 #define GS2_CB_FLAG_MASK    0x0F
 #include "gs2_token.h"
 
 #define GS2_CB_FLAG_MASK    0x0F
-#define GS2_CB_FLAG_P       SASL_CB_FLAG_USED
-#define GS2_CB_FLAG_N       SASL_CB_FLAG_NONE
-#define GS2_CB_FLAG_Y       SASL_CB_FLAG_WANT
+#define GS2_CB_FLAG_P       0x01
+#define GS2_CB_FLAG_N       0x02
+#define GS2_CB_FLAG_Y       0x03
 #define GS2_NONSTD_FLAG     0x10
 
 typedef struct context {
 #define GS2_NONSTD_FLAG     0x10
 
 typedef struct context {
@@ -487,7 +487,7 @@ gs2_server_mech_step(void *conn_context,
         oparams->chanbindingflag = SASL_CB_FLAG_USED;
         break;
     case GS2_CB_FLAG_Y:
         oparams->chanbindingflag = SASL_CB_FLAG_USED;
         break;
     case GS2_CB_FLAG_Y:
-        oparams->chanbindingflag == SASL_CB_FLAG_WANT;
+        oparams->chanbindingflag = SASL_CB_FLAG_WANT;
         break;
     }
 
         break;
     }
 
index 2b4f72d..fec6355 100644 (file)
@@ -322,9 +322,14 @@ int main(int argc, char *argv[])
     int *l, maxfd=0;
     int r, i;
     sasl_conn_t *conn;
     int *l, maxfd=0;
     int r, i;
     sasl_conn_t *conn;
+    int cb_flag = 0;
 
 
-    while ((c = getopt(argc, argv, "p:s:m:")) != EOF) {
+    while ((c = getopt(argc, argv, "cp:s:m:")) != EOF) {
        switch(c) {
        switch(c) {
+       case 'c':
+           cb_flag = 1;
+           break;
+
        case 'p':
            port = optarg;
            break;
        case 'p':
            port = optarg;
            break;
@@ -441,7 +446,7 @@ int main(int argc, char *argv[])
        if (r != SASL_OK) saslfail(r, "allocating connection state");
 
         cb.type = "sasl-sample";
        if (r != SASL_OK) saslfail(r, "allocating connection state");
 
         cb.type = "sasl-sample";
-        cb.critical = 0;
+        cb.critical = cb_flag;
         cb.data = "this is a test of channel binding";
         cb.len = strlen(cb.data);
 
         cb.data = "this is a test of channel binding";
         cb.len = strlen(cb.data);