move more CB selection logic to libsasl
authorLuke Howard <lukeh@padl.com>
Sun, 26 Sep 2010 22:41:50 +0000 (00:41 +0200)
committerLuke Howard <lukeh@padl.com>
Sun, 26 Sep 2010 22:41:50 +0000 (00:41 +0200)
include/sasl.h
include/saslplug.h
lib/auxprop.c
lib/client.c
lib/common.c
lib/saslint.h
lib/server.c
sample/client.c
sample/server.c

index 714f0ca..b082057 100755 (executable)
@@ -791,14 +791,14 @@ LIBSASL_API int sasl_getprop(sasl_conn_t *conn, int propnum,
  * is particularly useful for servers that respond to multiple names. */
 #define        SASL_GSS_LOCAL_NAME     20
 
-typedef struct sasl_channel_bindings {
+typedef struct sasl_channel_binding {
     char *type;
     int critical;
     unsigned long len;
     unsigned char *data;
-} sasl_channel_bindings;
+} sasl_channel_binding;
 
-#define SASL_CHANNEL_BINDINGS   21
+#define SASL_CHANNEL_BINDING    21
 
 /* set property in SASL connection state
  * returns:
index 321e79f..ea5368e 100755 (executable)
@@ -255,8 +255,8 @@ typedef struct sasl_client_params {
 
     /* for additions which don't require a version upgrade; set to 0 */
     void *gss_creds;
-    void *chanbindingstype;
-    void *chanbindingsdata;
+    void *chanbindingtype;
+    void *chanbindingdata;
     void *spare_ptr4;
 
     /* Canonicalize a user name from on-wire to internal format
@@ -292,9 +292,9 @@ typedef struct sasl_client_params {
 #define SASL_CB_FLAG_NONE   0       /* client did not support CB */
 #define SASL_CB_FLAG_USED   1       /* client supports and used CB */
 #define SASL_CB_FLAG_WANT   2       /* client supports CB, thinks server does not */
-
-    int chanbindingsflag;
-    int chanbindingslen;
+    int chanbindingflag;
+#define SASL_CB_PRESENT(params) ((params)->chanbindingtype != NULL && (params)->chanbindinglen)
+    int chanbindinglen;
     int spare_int3;
 
     /* flags field as passed to sasl_client_new */
@@ -337,7 +337,7 @@ typedef struct sasl_client_params {
 #define SASL_FEAT_GSS_FRAMING       0x0040
 
 /* Underlying mechanism supports channel binding */
-#define SASL_FEAT_CHANNEL_BINDINGS  0x0080
+#define SASL_FEAT_CHANNEL_BINDING  0x0080
 
 /* client plug-in features */
 #define SASL_FEAT_NEEDSERVERFQDN 0x0001
@@ -561,13 +561,13 @@ typedef struct sasl_server_params {
 
     /* for additions which don't require a version upgrade; set to 0 */
     void *gss_creds;
-    void *chanbindingstype;
-    void *chanbindingsdata;
+    void *chanbindingtype;
+    void *chanbindingdata;
     void *spare_ptr4;
     int (*spare_fptr1)();
     int (*spare_fptr2)();
-    int chanbindingscrit;
-    int chanbindingslen;
+    int chanbindingcrit;
+    int chanbindinglen;
     int spare_int3;
 
     /* flags field as passed to sasl_server_new */
index a3f54c0..1be6c2a 100644 (file)
@@ -46,6 +46,7 @@
 #include <sasl.h>
 #include <prop.h>
 #include <ctype.h>
+#include <stdio.h>
 #include "saslint.h"
 
 struct proppool 
index c42d6f5..4c35519 100644 (file)
@@ -390,19 +390,6 @@ static int have_prompts(sasl_conn_t *conn,
   return 1; /* we have all the prompts */
 }
 
-static inline int sasl_is_plus_mech(const char *mech)
-{
-    size_t len = strlen(mech);
-    const char *p;
-
-    if (len < 5)
-        return 0;
-
-    p = &mech[len - 5];
-
-    return (strcmp(p, "-PLUS") == 0);
-}
-
 /* select a mechanism for a connection
  *  mechlist      -- mechanisms server has available (punctuation ignored)
  *  secret        -- optional secret from previous session
@@ -464,6 +451,8 @@ int sasl_client_start(sasl_conn_t *conn,
        minssf = conn->props.min_ssf - conn->external.ssf;
     }
 
+    c_conn->cparams->chanbindingflag = SASL_CB_FLAG_NONE;
+
     /* parse mechlist */
     list_len = strlen(mechlist);
 
@@ -491,11 +480,10 @@ int sasl_client_start(sasl_conn_t *conn,
 
        /* foreach in client list */
        for (m = cmechlist->mech_list; m != NULL; m = m->next) {
-           int myflags;
-           
-           /* Is this the mechanism the server is suggesting? */
-           if (strcasecmp(m->m.plug->mech_name, name))
-               continue; /* no */
+           int myflags, plus;
+
+            if (!_sasl_is_equal_mech(name, m->m.plug->mech_name, &plus))
+                continue;
 
            /* Do we have the prompts for it? */
            if (!have_prompts(conn, m->m.plug))
@@ -530,16 +518,6 @@ int sasl_client_start(sasl_conn_t *conn,
                break;
            }
 
-           /* If client requires channel binding, prefer -PLUS mech */
-           if (c_conn->cparams->chanbindingslen != 0) {
-               if (sasl_is_plus_mech(name))
-                   c_conn->cparams->chanbindingsflag = SASL_CB_FLAG_USED;
-               else
-                   c_conn->cparams->chanbindingsflag = SASL_CB_FLAG_WANT;
-           } else {
-               c_conn->cparams->chanbindingsflag = SASL_CB_FLAG_NONE;
-           }
-
 #ifdef PREFER_MECH
            if (strcasecmp(m->m.plug->mech_name, PREFER_MECH) &&
                bestm && m->m.plug->max_ssf <= bestssf) {
@@ -578,6 +556,13 @@ int sasl_client_start(sasl_conn_t *conn,
                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;
+            }
+
            if (mech) {
                *mech = m->m.plug->mech_name;
            }
@@ -967,6 +952,16 @@ _sasl_print_mechanism (
            printf ("%cNEED_SERVER_FQDN", delimiter);
            delimiter = '|';
        }
+
+       if (m->plug->features & SASL_FEAT_GSS_FRAMING) {
+           printf ("%cGSS_FRAMING", delimiter);
+           delimiter = '|';
+       }
+
+       if (m->plug->features & SASL_FEAT_CHANNEL_BINDING) {
+           printf ("%cCHANNEL_BINDING", delimiter);
+           delimiter = '|';
+       }
     }
 
 /* Delay loading is not supported for the client side plugins:
index 1bf804d..9a8e8ce 100644 (file)
@@ -1208,20 +1208,18 @@ int sasl_setprop(sasl_conn_t *conn, int propnum, const void *value)
     else
         ((sasl_client_conn_t *)conn)->cparams->gss_creds = (void *)value;
     break;
-  case SASL_CHANNEL_BINDINGS: {
-    struct sasl_channel_bindings *cb = (struct sasl_channel_bindings *)value;
+  case SASL_CHANNEL_BINDING: {
+    struct sasl_channel_binding *cb = (struct sasl_channel_binding *)value;
 
     if (conn->type == SASL_CONN_SERVER) {
-        int cb_flag;
-
-        ((sasl_server_conn_t *)conn)->sparams->chanbindingstype = cb->type;
-        ((sasl_server_conn_t *)conn)->sparams->chanbindingscrit = cb->critical;
-        ((sasl_server_conn_t *)conn)->sparams->chanbindingsdata = cb->data;
-        ((sasl_server_conn_t *)conn)->sparams->chanbindingslen = cb->len;
+        ((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;
     } else {
-        ((sasl_client_conn_t *)conn)->cparams->chanbindingstype = cb->type;
-        ((sasl_client_conn_t *)conn)->cparams->chanbindingsdata = cb->data;
-        ((sasl_client_conn_t *)conn)->cparams->chanbindingslen = cb->len;
+        ((sasl_client_conn_t *)conn)->cparams->chanbindingtype = cb->type;
+        ((sasl_client_conn_t *)conn)->cparams->chanbindingdata = cb->data;
+        ((sasl_client_conn_t *)conn)->cparams->chanbindinglen = cb->len;
     }
     break;
   }
@@ -2333,6 +2331,24 @@ int sasl_listmech(sasl_conn_t *conn,
     PARAMERROR(conn);
 }
 
+int _sasl_is_equal_mech(const char *req_mech,
+                        const char *plug_mech,
+                        int *plus)
+{
+    size_t len = strlen(req_mech);
+    size_t n;
+
+    if (len > 5 &&
+        strcasecmp(&req_mech[len - 5], "-PLUS") == 0) {
+        n = len - 5;
+        *plus = 1;
+    } else {
+        n = len;
+        *plus = 0;
+    }
+
+    return (strncasecmp(req_mech, plug_mech, n) == 0);
+}
 
 #ifndef WIN32
 static char *
index b1c20ef..1af2415 100644 (file)
@@ -301,6 +301,10 @@ extern int (*_sasl_server_cleanup_hook)(void);
 extern sasl_allocation_utils_t _sasl_allocation_utils;
 extern sasl_mutex_utils_t _sasl_mutex_utils;
 
+extern int _sasl_is_equal_mech(const char *req_mech,
+                               const char *plug_mech,
+                               int *plus);
+
 /*
  * checkpw.c
  */
index 1533c10..3013019 100644 (file)
@@ -1214,6 +1214,7 @@ int sasl_server_start(sasl_conn_t *conn,
     int result;
     context_list_t *cur, **prev;
     mechanism_t *m;
+    int plus = 0;
 
     if (_sasl_server_active==0) return SASL_NOTINIT;
 
@@ -1230,13 +1231,11 @@ int sasl_server_start(sasl_conn_t *conn,
     if(serverout) *serverout = NULL;
     if(serveroutlen) *serveroutlen = 0;
 
-    while (m!=NULL)
-    {
-       if ( strcasecmp(mech, m->m.plug->mech_name)==0)
-       {
+    while (m != NULL) {
+       if (_sasl_is_equal_mech(mech, m->m.plug->mech_name, &plus))
            break;
-       }
-       m=m->next;
+
+       m = m->next;
     }
   
     if (m==NULL) {
@@ -1511,6 +1510,7 @@ int _sasl_server_listmech(sasl_conn_t *conn,
   size_t resultlen;
   int flag;
   const char *mysep;
+  sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn;  /* cast */
 
   /* if there hasn't been a sasl_sever_init() fail */
   if (_sasl_server_active==0) return SASL_NOTINIT;
@@ -1535,8 +1535,9 @@ int _sasl_server_listmech(sasl_conn_t *conn,
       INTERROR(conn, SASL_NOMECH);
 
   resultlen = (prefix ? strlen(prefix) : 0)
-            + (strlen(mysep) * (mechlist->mech_length - 1))
-           + mech_names_len()
+            + (strlen(mysep) * (mechlist->mech_length - 1) * 2)
+           + (mech_names_len() * 2) /* including -PLUS variant */
+           + (mechlist->mech_length * (sizeof("-PLUS") - 1))
             + (suffix ? strlen(suffix) : 0)
            + 1;
   ret = _buf_alloc(&conn->mechlist_buf,
@@ -1567,6 +1568,16 @@ int _sasl_server_listmech(sasl_conn_t *conn,
 
          /* now print the mechanism name */
          strcat(conn->mechlist_buf, listptr->m.plug->mech_name);
+
+         /* advertise -PLUS variant if mechanism and application support CB */
+         if ((listptr->m.plug->features & SASL_FEAT_CHANNEL_BINDING) &&
+             SASL_CB_PRESENT(s_conn->sparams)) {
+           if (pcount != NULL)
+               (*pcount)++;
+           strcat(conn->mechlist_buf, mysep);
+           strcat(conn->mechlist_buf, listptr->m.plug->mech_name);
+           strcat(conn->mechlist_buf, "-PLUS");
+         }
       }
 
       listptr = listptr->next;
@@ -2046,6 +2057,16 @@ _sasl_print_mechanism (
            printf ("%cNEED_GETSECRET", delimiter);
            delimiter = '|';
        }
+
+        if (m->plug->features & SASL_FEAT_GSS_FRAMING) {
+           printf ("%cGSS_FRAMING", delimiter);
+           delimiter = '|';
+       }
+
+        if (m->plug->features & SASL_FEAT_CHANNEL_BINDING) {
+           printf ("%cCHANNEL_BINDING", delimiter);
+           delimiter = '|';
+       }
     }
 
     if (m->f) {
index d1b02d4..ec0514f 100644 (file)
@@ -321,7 +321,7 @@ int mysasl_negotiate(FILE *in, FILE *out, sasl_conn_t *conn)
 
 void usage(void)
 {
-    fprintf(stderr, "usage: client [-p port] [-s service] [-m mech] host\n");
+    fprintf(stderr, "usage: client [-c] [-p port] [-s service] [-m mech] host\n");
     exit(EX_USAGE);
 }
 
@@ -341,10 +341,15 @@ int main(int argc, char *argv[])
     int salen;
     int niflags, error;
     struct sockaddr_storage local_ip, remote_ip;
-    sasl_channel_bindings cb;
+    int cb_flag = 0;
+    sasl_channel_binding cb;
 
-    while ((c = getopt(argc, argv, "p:s:m:")) != EOF) {
+    while ((c = getopt(argc, argv, "cp:s:m:")) != EOF) {
        switch(c) {
+       case 'c':
+           cb_flag = 1;
+           break;
+
        case 'p':
            port = optarg;
            break;
@@ -420,12 +425,13 @@ int main(int argc, char *argv[])
     r = sasl_client_new(service, host, localaddr, remoteaddr, NULL, 0, &conn);
     if (r != SASL_OK) saslfail(r, "allocating connection state");
 
-    cb.type = "sasl-sample";
-    cb.critical = 0;
-    cb.data = "this is a test of channel bindings";
-    cb.len = strlen(cb.data);
+    if (cb_flag) {
+        cb.type = "sasl-sample";
+        cb.data = "this is a test of channel binding";
+        cb.len = strlen(cb.data);
 
-    sasl_setprop(conn, SASL_CHANNEL_BINDINGS, &cb);
+        sasl_setprop(conn, SASL_CHANNEL_BINDING, &cb);
+    }
 
     /* set external properties here
        sasl_setprop(conn, SASL_SSF_EXTERNAL, &extprops); */
index 0ba17a8..2b4f72d 100644 (file)
@@ -368,7 +368,7 @@ int main(int argc, char *argv[])
        int nfds, fd = -1;
        FILE *in, *out;
        fd_set readfds;
-       sasl_channel_bindings cb;
+       sasl_channel_binding cb;
 
        FD_ZERO(&readfds);
        for (i = 1; i <= l[0]; i++)
@@ -442,10 +442,10 @@ int main(int argc, char *argv[])
 
         cb.type = "sasl-sample";
         cb.critical = 0;
-        cb.data = "this is a test of channel bindings";
+        cb.data = "this is a test of channel binding";
         cb.len = strlen(cb.data);
 
-        sasl_setprop(conn, SASL_CHANNEL_BINDINGS, &cb);
+        sasl_setprop(conn, SASL_CHANNEL_BINDING, &cb);
 
        /* set external properties here
           sasl_setprop(conn, SASL_SSF_EXTERNAL, &extprops); */