Add experimental GSS-EAP mechanism
authorLuke Howard <lukeh@padl.com>
Fri, 24 Sep 2010 14:52:14 +0000 (16:52 +0200)
committerLuke Howard <lukeh@padl.com>
Fri, 24 Sep 2010 14:52:14 +0000 (16:52 +0200)
include/md5global.h
include/saslplug.h
lib/common.c
plugins/gssapi.c
sample/Makefile.am
sample/Makefile.in
sample/sample-server.c
sample/server.c

index fbd7455..414bac6 100644 (file)
@@ -18,11 +18,11 @@ typedef unsigned char *POINTER;
 typedef signed char INT1;              /*  8 bits */
 typedef short INT2;                    /* 16 bits */
 typedef int INT4;                      /* 32 bits */
-/* There is no 64 bit type */
+typedef long INT8;                     /* 64 bits */
 typedef unsigned char UINT1;           /*  8 bits */
 typedef unsigned short UINT2;          /* 16 bits */
 typedef unsigned int UINT4;            /* 32 bits */
-/* There is no 64 bit type */
+typedef unsigned long UINT8;           /* 64 bits */
 
 /* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
 If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
index 61d0a33..fecb7de 100755 (executable)
@@ -193,8 +193,8 @@ typedef struct sasl_out_params {
     void *client_creds;
 
     /* for additions which don't require a version upgrade; set to 0 */
-    void *spare_ptr2;
-    void *spare_ptr3;
+    void *gss_peer_name;
+    void *gss_local_name;
     void *spare_ptr4;
     int (*spare_fptr1)();
     int (*spare_fptr2)();
@@ -254,7 +254,7 @@ typedef struct sasl_client_params {
     sasl_ssf_t external_ssf;   /* external SSF active */
 
     /* for additions which don't require a version upgrade; set to 0 */
-    void *spare_ptr1;
+    void *gss_creds;
     void *spare_ptr2;
     void *spare_ptr3;
     void *spare_ptr4;
@@ -550,7 +550,7 @@ typedef struct sasl_server_params {
     struct propctx *propctx;
 
     /* for additions which don't require a version upgrade; set to 0 */
-    void *spare_ptr1;
+    void *gss_creds;
     void *spare_ptr2;
     void *spare_ptr3;
     void *spare_ptr4;
index 6a1ae35..42a0b7b 100644 (file)
@@ -970,6 +970,18 @@ int sasl_getprop(sasl_conn_t *conn, int propnum, const void **pvalue)
       else
          *((const char **)pvalue) = conn->oparams.client_creds;
       break;
+  case SASL_GSS_PEER_NAME:
+      if(! conn->oparams.gss_peer_name)
+         result = SASL_NOTDONE;
+      else
+         *((const char **)pvalue) = conn->oparams.gss_peer_name;
+      break;
+  case SASL_GSS_LOCAL_NAME:
+      if(! conn->oparams.gss_peer_name)
+         result = SASL_NOTDONE;
+      else
+         *((const char **)pvalue) = conn->oparams.gss_local_name;
+      break;
   case SASL_SSF_EXTERNAL:
       *((const sasl_ssf_t **)pvalue) = &conn->external.ssf;
       break;
@@ -1190,6 +1202,12 @@ int sasl_setprop(sasl_conn_t *conn, int propnum, const void *value)
       }
       break;
 
+  case SASL_GSS_CREDS:
+    if (conn->type == SASL_CONN_SERVER)
+        ((sasl_server_conn_t *)conn)->sparams->gss_creds = (void *)value;
+    else
+        ((sasl_client_conn_t *)conn)->cparams->gss_creds = (void *)value;
+    break;
   default:
       sasl_seterror(conn, 0, "Unknown parameter type");
       result = SASL_BADPARAM;
index d19a6c2..0e6cf2b 100644 (file)
@@ -51,6 +51,7 @@
 #include <gssapi/gssapi.h>
 #endif
 
+#include <gssapi/gssapi_ext.h>
 #ifdef WIN32
 #  include <winsock2.h>
 
@@ -139,10 +140,18 @@ static void *gss_mutex = NULL;
 #define GSS_UNLOCK_MUTEX(utils)
 #endif
 
+static gss_OID_desc gss_spnego_mechanism_oid_desc =
+        {6, (void *)"\x2b\x06\x01\x05\x05\x02"};
+static gss_OID_desc gss_krb5_mechanism_oid_desc =
+        {9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"};
+static gss_OID_desc gss_eap_mechanism_oid_desc =
+        {9, (void *)"\x2b\x06\x01\x04\x01\xa9\x4a\x15\x01" };
+
 typedef struct context {
     int state;
     
     gss_ctx_id_t gss_ctx;
+
     gss_name_t   client_name;
     gss_name_t   server_name;
     gss_cred_id_t server_creds;
@@ -168,6 +177,9 @@ typedef struct context {
     
     char *authid; /* hold the authid between steps - server */
     const char *user;   /* hold the userid between steps - client */
+
+    gss_OID mech;
+    int rfc2222_gss : 1;
 } context_t;
 
 enum {
@@ -190,7 +202,7 @@ sasl_gss_seterror_(const sasl_utils_t *utils, OM_uint32 maj, OM_uint32 min,
     OM_uint32 msg_ctx;
     int ret;
     char *out = NULL;
-    size_t len, curlen = 0;
+    unsigned int len, curlen = 0;
     const char prefix[] = "GSSAPI Error: ";
     
     len = sizeof(prefix);
@@ -599,11 +611,12 @@ static void gssapi_common_mech_free(void *global_context __attribute__((unused))
 /*****************************  Server Section  *****************************/
 
 static int 
-gssapi_server_mech_new(void *glob_context __attribute__((unused)), 
-                      sasl_server_params_t *params,
-                      const char *challenge __attribute__((unused)), 
-                      unsigned challen __attribute__((unused)),
-                      void **conn_context)
+_gssapi_server_mech_new(void *glob_context __attribute__((unused)), 
+                       sasl_server_params_t *params,
+                       const char *challenge __attribute__((unused)), 
+                       unsigned challen __attribute__((unused)),
+                       int rfc2222_gss,
+                       void **conn_context)
 {
     context_t *text;
     
@@ -619,6 +632,7 @@ gssapi_server_mech_new(void *glob_context __attribute__((unused)),
     text->server_creds = GSS_C_NO_CREDENTIAL;
     text->client_creds = GSS_C_NO_CREDENTIAL;
     text->state = SASL_GSSAPI_STATE_AUTHNEG;
+    text->rfc2222_gss = rfc2222_gss;
     
     *conn_context = text;
     
@@ -626,6 +640,28 @@ gssapi_server_mech_new(void *glob_context __attribute__((unused)),
 }
 
 static int 
+gssapi_server_mech_new(void *glob_context,
+                      sasl_server_params_t *params,
+                      const char *challenge,
+                      unsigned challen,
+                      void **conn_context)
+{
+    return _gssapi_server_mech_new(glob_context, params, challenge,
+                                   challen, 1, conn_context);
+}
+
+static int 
+gss_spnego_server_mech_new(void *glob_context,
+                          sasl_server_params_t *params,
+                          const char *challenge,
+                          unsigned challen,
+                          void **conn_context)
+{
+    return _gssapi_server_mech_new(glob_context, params, challenge,
+                                   challen, 0, conn_context);
+}
+
+static int 
 gssapi_server_mech_step(void *conn_context,
                        sasl_server_params_t *params,
                        const char *clientin,
@@ -640,7 +676,9 @@ gssapi_server_mech_step(void *conn_context,
     OM_uint32 maj_stat = 0, min_stat = 0;
     OM_uint32 max_input;
     gss_buffer_desc name_token;
-    int ret, out_flags = 0 ;
+    int ret;
+    OM_uint32 out_flags = 0 ;
+    int layerchoice = 0;
     
     input_token = &real_input_token;
     output_token = &real_output_token;
@@ -778,11 +816,15 @@ gssapi_server_mech_step(void *conn_context,
        }
        
        if (maj_stat == GSS_S_COMPLETE) {
-           /* Switch to ssf negotiation */
-           text->state = SASL_GSSAPI_STATE_SSFCAP;
-       }
-       
-       return SASL_CONTINUE;
+            if (text->rfc2222_gss) {
+               /* Switch to ssf negotiation */
+               text->state = SASL_GSSAPI_STATE_SSFCAP;
+                return SASL_CONTINUE;
+            }
+       } else {
+           return SASL_CONTINUE;
+        }
+        /* Fall-through for non-RFC 2222 mechanisms such as GSS-SPNEGO */
 
     case SASL_GSSAPI_STATE_SSFCAP: {
        unsigned char sasldata[4];
@@ -920,7 +962,7 @@ gssapi_server_mech_step(void *conn_context,
        if (name_without_realm.value) {
            params->utils->free(name_without_realm.value);
        }       
-       
+
        /* we have to decide what sort of encryption/integrity/etc.,
           we support */
        if (params->props.max_ssf < params->external_ssf) {
@@ -933,7 +975,20 @@ gssapi_server_mech_step(void *conn_context,
        } else {
            text->requiressf = params->props.min_ssf - params->external_ssf;
        }
-       
+
+        if (!text->rfc2222_gss) {
+            if (out_flags & GSS_C_CONF_FLAG)
+                layerchoice = 4;
+            else if (out_flags & GSS_C_INTEG_FLAG)
+                layerchoice = 2;
+            else
+                layerchoice = 1;
+
+            text->limitssf = 128; /* XXX */
+
+            goto select_layers;
+        }
+
        /* build up our security properties token */
         if (params->props.maxbufsize > 0xFFFFFF) {
             /* make sure maxbufsize isn't too large */
@@ -1016,8 +1071,6 @@ gssapi_server_mech_step(void *conn_context,
     }
 
     case SASL_GSSAPI_STATE_SSFREQ: {
-       int layerchoice;
-       
        real_input_token.value = (void *)clientin;
        real_input_token.length = clientinlen;
        
@@ -1037,6 +1090,8 @@ gssapi_server_mech_step(void *conn_context,
        }
        
        layerchoice = (int)(((char *)(output_token->value))[0]);
+select_layers:
+
        if (layerchoice == 1 && text->requiressf == 0) { /* no encryption */
            oparams->encode = NULL;
            oparams->decode = NULL;
@@ -1066,42 +1121,42 @@ gssapi_server_mech_step(void *conn_context,
            sasl_gss_free_context_contents(text);
            return SASL_FAIL;
        }
-       
-       if (output_token->length > 4) {
+
+        if (output_token->length == 4 || !text->rfc2222_gss) {
+           /* null authzid */
            int ret;
            
            ret = params->canon_user(params->utils->conn,
-                                    ((char *) output_token->value) + 4,
-                                    (output_token->length - 4) * sizeof(char),
-                                    SASL_CU_AUTHZID, oparams);
+                                    text->authid,
+                                    0, /* strlen(text->authid) */
+                                    SASL_CU_AUTHZID | SASL_CU_AUTHID,
+                                    oparams);
            
            if (ret != SASL_OK) {
                sasl_gss_free_context_contents(text);
                return ret;
-           }
+           }       
+       } else if (output_token->length > 4) {
+           int ret;
            
            ret = params->canon_user(params->utils->conn,
-                                    text->authid,
-                                    0, /* strlen(text->authid) */
-                                    SASL_CU_AUTHID, oparams);
+                                    ((char *) output_token->value) + 4,
+                                    (output_token->length - 4) * sizeof(char),
+                                    SASL_CU_AUTHZID, oparams);
+           
            if (ret != SASL_OK) {
                sasl_gss_free_context_contents(text);
                return ret;
            }
-       } else if(output_token->length == 4) {
-           /* null authzid */
-           int ret;
            
            ret = params->canon_user(params->utils->conn,
                                     text->authid,
                                     0, /* strlen(text->authid) */
-                                    SASL_CU_AUTHZID | SASL_CU_AUTHID,
-                                    oparams);
-           
+                                    SASL_CU_AUTHID, oparams);
            if (ret != SASL_OK) {
                sasl_gss_free_context_contents(text);
                return ret;
-           }       
+           }
        } else {
            SETERROR(text->utils,
                     "token too short");
@@ -1121,10 +1176,17 @@ gssapi_server_mech_step(void *conn_context,
            oparams->client_creds = NULL;
        }
 
-        oparams->maxoutbuf =
-           (((unsigned char *) output_token->value)[1] << 16) |
-            (((unsigned char *) output_token->value)[2] << 8) |
-            (((unsigned char *) output_token->value)[3] << 0);
+       oparams->gss_peer_name = text->client_name;
+       oparams->gss_local_name = text->server_name;
+
+        if (text->rfc2222_gss) {
+            oparams->maxoutbuf =
+               (((unsigned char *) output_token->value)[1] << 16) |
+                (((unsigned char *) output_token->value)[2] << 8) |
+                (((unsigned char *) output_token->value)[3] << 0);
+        } else {
+            oparams->maxoutbuf = 0xFFFFFF;
+        }
 
        if (oparams->mech_ssf) {
            maj_stat = gss_wrap_size_limit( &min_stat,
@@ -1142,7 +1204,7 @@ gssapi_server_mech_step(void *conn_context,
                oparams->maxoutbuf = max_input;
            }    
        }
-       
+
        GSS_LOCK_MUTEX(params->utils);
        gss_release_buffer(&min_stat, output_token);
        GSS_UNLOCK_MUTEX(params->utils);
@@ -1190,6 +1252,46 @@ static sasl_server_plug_t gssapi_server_plugins[] =
        NULL,                           /* idle */
        NULL,                           /* mech_avail */
        NULL                            /* spare */
+    },
+    {
+       "GSS-SPNEGO",                   /* mech_name */
+       K5_MAX_SSF,                     /* max_ssf */
+       SASL_SEC_NOPLAINTEXT
+       | SASL_SEC_NOACTIVE
+       | SASL_SEC_NOANONYMOUS
+       | SASL_SEC_MUTUAL_AUTH          /* security_flags */
+       | SASL_SEC_PASS_CREDENTIALS,
+       SASL_FEAT_WANT_CLIENT_FIRST
+       | SASL_FEAT_ALLOWS_PROXY,       /* features */
+       NULL,                           /* glob_context */
+       &gss_spnego_server_mech_new,    /* mech_new */
+       &gssapi_server_mech_step,       /* mech_step */
+       &gssapi_common_mech_dispose,    /* mech_dispose */
+       &gssapi_common_mech_free,       /* mech_free */
+       NULL,                           /* setpass */
+       NULL,                           /* user_query */
+       NULL,                           /* idle */
+       NULL,                           /* mech_avail */
+       NULL                            /* spare */
+    },
+    {
+       "GSS-EAP",                      /* mech_name */
+       256,                            /* max_ssf */
+       SASL_SEC_NOPLAINTEXT
+       | SASL_SEC_NOACTIVE
+       | SASL_SEC_MUTUAL_AUTH,         /* security_flags */
+       SASL_FEAT_WANT_CLIENT_FIRST
+       | SASL_FEAT_ALLOWS_PROXY,       /* features */
+       NULL,                           /* glob_context */
+       &gssapi_server_mech_new,        /* mech_new */
+       &gssapi_server_mech_step,       /* mech_step */
+       &gssapi_common_mech_dispose,    /* mech_dispose */
+       &gssapi_common_mech_free,       /* mech_free */
+       NULL,                           /* setpass */
+       NULL,                           /* user_query */
+       NULL,                           /* idle */
+       NULL,                           /* mech_avail */
+       NULL                            /* spare */
     }
 };
 
@@ -1243,7 +1345,7 @@ int gssapiv2_server_plug_init(
     
     *out_version = SASL_SERVER_PLUG_VERSION;
     *pluglist = gssapi_server_plugins;
-    *plugcount = 1;  
+    *plugcount = sizeof(gssapi_server_plugins)/sizeof(gssapi_server_plugins[0]);
 
 #ifdef GSS_USE_MUTEXES
     if (!gss_mutex) {
@@ -1259,9 +1361,11 @@ int gssapiv2_server_plug_init(
 
 /*****************************  Client Section  *****************************/
 
-static int gssapi_client_mech_new(void *glob_context __attribute__((unused)), 
-                                 sasl_client_params_t *params,
-                                 void **conn_context)
+static int _gssapi_client_mech_new(void *glob_context __attribute__((unused)), 
+                                  sasl_client_params_t *params,
+                                  gss_OID mech,
+                                  int rfc2222_gss,
+                                  void **conn_context)
 {
     context_t *text;
     
@@ -1277,12 +1381,38 @@ static int gssapi_client_mech_new(void *glob_context __attribute__((unused)),
     text->client_name = GSS_C_NO_NAME;
     text->server_creds = GSS_C_NO_CREDENTIAL;
     text->client_creds  = GSS_C_NO_CREDENTIAL;
+    text->mech = mech;
+    text->rfc2222_gss = rfc2222_gss;
 
     *conn_context = text;
     
     return SASL_OK;
 }
 
+static int gssapi_client_mech_new(void *glob_context,
+                                      sasl_client_params_t *params,
+                                      void **conn_context)
+{
+    return _gssapi_client_mech_new(glob_context, params, &gss_krb5_mechanism_oid_desc,
+                                   1, conn_context);
+}
+
+static int gss_spnego_client_mech_new(void *glob_context,
+                                     sasl_client_params_t *params,
+                                     void **conn_context)
+{
+    return _gssapi_client_mech_new(glob_context, params, &gss_spnego_mechanism_oid_desc,
+                                   0, conn_context);
+}
+
+static int gss_eap_client_mech_new(void *glob_context,
+                                  sasl_client_params_t *params,
+                                  void **conn_context)
+{
+    return _gssapi_client_mech_new(glob_context, params, &gss_eap_mechanism_oid_desc,
+                                   1, conn_context);
+}
+
 static int gssapi_client_mech_step(void *conn_context,
                                   sasl_client_params_t *params,
                                   const char *serverin,
@@ -1296,16 +1426,18 @@ static int gssapi_client_mech_step(void *conn_context,
     gss_buffer_t input_token, output_token;
     gss_buffer_desc real_input_token, real_output_token;
     OM_uint32 maj_stat = 0, min_stat = 0;
-    OM_uint32 max_input;
+    OM_uint32 max_input, out_flags;
     gss_buffer_desc name_token;
-    int ret;
+    int ret, serverhas = 0;
     OM_uint32 req_flags = 0, out_req_flags = 0;
+    sasl_security_properties_t *secprops = &(params->props);
+
     input_token = &real_input_token;
     output_token = &real_output_token;
     output_token->value = NULL;
     input_token->value = NULL; 
     input_token->length = 0;
-    
     *clientout = NULL;
     *clientoutlen = 0;
     
@@ -1315,6 +1447,7 @@ static int gssapi_client_mech_step(void *conn_context,
        /* try to get the userid */
        if (text->user == NULL) {
            int user_result = SASL_OK;
+           int pass_result = SASL_OK;
            
            user_result = _plug_get_userid(params->utils, &text->user,
                                           prompt_need);
@@ -1329,22 +1462,63 @@ static int gssapi_client_mech_step(void *conn_context,
                params->utils->free(*prompt_need);
                *prompt_need = NULL;
            }
-                   
+
+            if (params->gss_creds == GSS_C_NO_CREDENTIAL) {
+               unsigned int free_password = 0;
+               sasl_secret_t *password = NULL;
+
+               pass_result = _plug_get_password(params->utils, &password,
+                                                &free_password, prompt_need);
+               if (pass_result == SASL_OK) {
+                   gss_buffer_desc pwBuf;
+                   gss_buffer_desc nameBuf;
+                   gss_OID_set_desc mechs;
+
+                   nameBuf.length = strlen(text->user);
+                   nameBuf.value = (void *)text->user;
+                   pwBuf.length = password->len;
+                   pwBuf.value = password->data;
+                   mechs.count = 1;
+                   mechs.elements = text->mech;
+
+                   GSS_LOCK_MUTEX(params->utils);
+                   maj_stat = gss_import_name(&min_stat, &nameBuf,
+                                              GSS_C_NT_USER_NAME, &text->client_name);
+                   if (maj_stat == GSS_S_COMPLETE) {
+                       maj_stat = gss_acquire_cred_with_password(&min_stat,
+                                                                 text->client_name,
+                                                                 &pwBuf, GSS_C_INDEFINITE,
+                                                                 &mechs, GSS_C_INITIATE,
+                                                                 &text->client_creds,
+                                                                  NULL, NULL);
+                       if (GSS_ERROR(maj_stat)) {
+                           if (free_password) _plug_free_secret(params->utils, &password);
+                           sasl_gss_seterror(text->utils, maj_stat, min_stat);
+                           GSS_UNLOCK_MUTEX(params->utils);
+                           sasl_gss_free_context_contents(text);
+                           return SASL_FAIL;
+                       }
+                   }
+                   GSS_UNLOCK_MUTEX(params->utils);
+                   if (free_password) _plug_free_secret(params->utils, &password);
+               }
+           }
            /* if there are prompts not filled in */
-           if (user_result == SASL_INTERACT) {
-               /* make the prompt list */
+           if (user_result == SASL_INTERACT && text->mech != &gss_krb5_mechanism_oid_desc) {
                int result =
-                   _plug_make_prompts(params->utils, prompt_need,
-                                      user_result == SASL_INTERACT ?
-                                      "Please enter your authorization name" : NULL, NULL,
-                                      NULL, NULL,
-                                      NULL, NULL,
-                                      NULL, NULL, NULL,
-                                      NULL, NULL, NULL);
+               _plug_make_prompts(params->utils, prompt_need,
+                                  user_result == SASL_INTERACT ?
+                                  "Please enter your authorization name" : NULL,
+                                  NULL,
+                                  NULL, NULL,
+                                  pass_result == SASL_INTERACT ?
+                                  "Please enter your password" : NULL, NULL,
+                                  NULL, NULL, NULL,
+                                  NULL, NULL, NULL);
                if (result != SASL_OK) return result;
-               
                return SASL_INTERACT;
            }
+
        }
            
        if (text->server_name == GSS_C_NO_NAME) { /* only once */
@@ -1416,10 +1590,11 @@ static int gssapi_client_mech_step(void *conn_context,
 
        GSS_LOCK_MUTEX(params->utils);
        maj_stat = gss_init_sec_context(&min_stat,
-                                       GSS_C_NO_CREDENTIAL,
+                                        params->gss_creds ? params->gss_creds :
+                                            text->client_creds,
                                        &text->gss_ctx,
                                        text->server_name,
-                                       GSS_C_NO_OID,
+                                       text->mech,
                                        req_flags,
                                        0,
                                        GSS_C_NO_CHANNEL_BINDINGS,
@@ -1469,6 +1644,8 @@ static int gssapi_client_mech_step(void *conn_context,
        
        if (maj_stat == GSS_S_COMPLETE) {
            GSS_LOCK_MUTEX(params->utils);
+           if (text->client_name != GSS_C_NO_NAME)
+               gss_release_name(&min_stat, &text->client_name);
            maj_stat = gss_inquire_context(&min_stat,
                                           text->gss_ctx,
                                           &text->client_name,
@@ -1476,7 +1653,7 @@ static int gssapi_client_mech_step(void *conn_context,
                                           NULL,       /* lifetime */
                                           NULL,       /* mech */
                                           /* FIX ME: Should check the resulting flags here */
-                                          NULL,       /* flags */
+                                          &out_flags,       /* flags */
                                           NULL,       /* local init */
                                           NULL);      /* open */
            GSS_UNLOCK_MUTEX(params->utils);
@@ -1524,19 +1701,31 @@ static int gssapi_client_mech_step(void *conn_context,
            gss_release_buffer(&min_stat, &name_token);
            GSS_UNLOCK_MUTEX(params->utils);
            
+           oparams->gss_peer_name = text->server_name;
+           oparams->gss_local_name = text->client_name;
+
            if (ret != SASL_OK) return ret;
-           
-           /* Switch to ssf negotiation */
-           text->state = SASL_GSSAPI_STATE_SSFCAP;
-       }
        
-       return SASL_CONTINUE;
+            if (text->rfc2222_gss) {
+               /* Switch to ssf negotiation */
+               text->state = SASL_GSSAPI_STATE_SSFCAP;
+                return SASL_CONTINUE;
+            } else {
+                serverhas = 1;
+                if (out_flags & GSS_C_INTEG_FLAG)
+                    serverhas |= 2;
+                if (out_flags & GSS_C_CONF_FLAG)
+                    serverhas |= 4;
+                goto select_layers;
+            }
+       } else {
+           return SASL_CONTINUE;
+        }
 
     case SASL_GSSAPI_STATE_SSFCAP: {
-       sasl_security_properties_t *secprops = &(params->props);
        unsigned int alen, external = params->external_ssf;
        sasl_ssf_t need, allowed;
-       char serverhas, mychoice;
+       char mychoice;
        
        real_input_token.value = (void *) serverin;
        real_input_token.length = serverinlen;
@@ -1560,7 +1749,11 @@ static int gssapi_client_mech_step(void *conn_context,
            }
            return SASL_FAIL;
        }
+
+       /* bit mask of server support */
+       serverhas = ((char *)output_token->value)[0];
        
+select_layers:
        /* taken from kerberos.c */
        if (secprops->min_ssf > (K5_MAX_SSF + external)) {
            return SASL_TOOWEAK;
@@ -1581,9 +1774,6 @@ static int gssapi_client_mech_step(void *conn_context,
            need = 0;
        }
        
-       /* bit mask of server support */
-       serverhas = ((char *)output_token->value)[0];
-       
        /* if client didn't set use strongest layer available */
        if (allowed >= K5_MAX_SSF && need <= K5_MAX_SSF && (serverhas & 4)) {
            /* encryption */
@@ -1609,11 +1799,15 @@ static int gssapi_client_mech_step(void *conn_context,
            sasl_gss_free_context_contents(text);
            return SASL_TOOWEAK;
        }
-       
-        oparams->maxoutbuf =
-           (((unsigned char *) output_token->value)[1] << 16) |
-            (((unsigned char *) output_token->value)[2] << 8) |
-            (((unsigned char *) output_token->value)[3] << 0);
+
+        if (text->rfc2222_gss) {
+            oparams->maxoutbuf =
+               (((unsigned char *) output_token->value)[1] << 16) |
+                (((unsigned char *) output_token->value)[2] << 8) |
+                (((unsigned char *) output_token->value)[3] << 0);
+       } else {
+            oparams->maxoutbuf = 0xFFFFFF;
+        }
 
        if(oparams->mech_ssf) {
             maj_stat = gss_wrap_size_limit( &min_stat,
@@ -1635,6 +1829,18 @@ static int gssapi_client_mech_step(void *conn_context,
        GSS_LOCK_MUTEX(params->utils);
        gss_release_buffer(&min_stat, output_token);
        GSS_UNLOCK_MUTEX(params->utils);
+
+        if (!text->rfc2222_gss) {
+            text->state = SASL_GSSAPI_STATE_AUTHENTICATED;
+       
+            oparams->doneflag = 1;
+       
+            /* used by layers */
+            _plug_decode_init(&text->decode_context, text->utils,
+                             (params->props.maxbufsize > 0xFFFFFF) ? 0xFFFFFF :
+                             params->props.maxbufsize);
+            return SASL_OK;
+        }
        
        /* oparams->user is always set, due to canon_user requirements.
         * Make sure the client actually requested it though, by checking
@@ -1740,7 +1946,7 @@ static int gssapi_client_mech_step(void *conn_context,
     return SASL_FAIL; /* should never get here */
 }
 
-static const long gssapi_required_prompts[] = {
+static const unsigned long gssapi_required_prompts[] = {
     SASL_CB_LIST_END
 };  
 
@@ -1766,7 +1972,49 @@ static sasl_client_plug_t gssapi_client_plugins[] =
        NULL,                           /* idle */
        NULL,                           /* spare */
        NULL                            /* spare */
-    }
+    },
+    {
+       "GSS-SPNEGO",                   /* mech_name */
+       K5_MAX_SSF,                     /* max_ssf */
+       SASL_SEC_NOPLAINTEXT
+       | SASL_SEC_NOACTIVE
+       | SASL_SEC_NOANONYMOUS
+       | SASL_SEC_MUTUAL_AUTH 
+       | SASL_SEC_PASS_CREDENTIALS,    /* security_flags */
+       SASL_FEAT_NEEDSERVERFQDN
+       | SASL_FEAT_WANT_CLIENT_FIRST
+       | SASL_FEAT_ALLOWS_PROXY,       /* features */
+       gssapi_required_prompts,        /* required_prompts */
+       NULL,                           /* glob_context */
+       &gss_spnego_client_mech_new,    /* mech_new */
+       &gssapi_client_mech_step,       /* mech_step */
+       &gssapi_common_mech_dispose,    /* mech_dispose */
+       &gssapi_common_mech_free,       /* mech_free */
+       NULL,                           /* idle */
+       NULL,                           /* spare */
+       NULL                            /* spare */
+    },
+    {
+       "GSS-EAP",                      /* mech_name */
+       128,                            /* max_ssf */
+       SASL_SEC_NOPLAINTEXT
+       | SASL_SEC_NOACTIVE
+       | SASL_SEC_NOANONYMOUS
+       | SASL_SEC_MUTUAL_AUTH 
+       | SASL_SEC_PASS_CREDENTIALS,    /* security_flags */
+       SASL_FEAT_NEEDSERVERFQDN
+       | SASL_FEAT_WANT_CLIENT_FIRST
+       | SASL_FEAT_ALLOWS_PROXY,       /* features */
+       gssapi_required_prompts,        /* required_prompts */
+       NULL,                           /* glob_context */
+       &gss_eap_client_mech_new,       /* mech_new */
+       &gssapi_client_mech_step,       /* mech_step */
+       &gssapi_common_mech_dispose,    /* mech_dispose */
+       &gssapi_common_mech_free,       /* mech_free */
+       NULL,                           /* idle */
+       NULL,                           /* spare */
+       NULL                            /* spare */
+    },
 };
 
 int gssapiv2_client_plug_init(const sasl_utils_t *utils __attribute__((unused)), 
@@ -1782,7 +2030,7 @@ int gssapiv2_client_plug_init(const sasl_utils_t *utils __attribute__((unused)),
     
     *out_version = SASL_CLIENT_PLUG_VERSION;
     *pluglist = gssapi_client_plugins;
-    *plugcount = 1;
+    *plugcount = sizeof(gssapi_client_plugins)/sizeof(gssapi_client_plugins[0]);
 
 #ifdef GSS_USE_MUTEXES
     if(!gss_mutex) {
@@ -1795,4 +2043,3 @@ int gssapiv2_client_plug_init(const sasl_utils_t *utils __attribute__((unused)),
     
     return SASL_OK;
 }
-
index 0e18483..6490723 100644 (file)
@@ -54,10 +54,10 @@ sample_server_SOURCES = sample-server.c
 server_SOURCES = server.c common.c common.h
 client_SOURCES = client.c common.c common.h
 
-server_LDADD = ../lib/libsasl2.la $(LIB_SOCKET)
-client_LDADD = ../lib/libsasl2.la $(LIB_SOCKET)
+server_LDADD = ../lib/libsasl2.la $(GSSAPIBASE_LIBS) $(GSSAPI_LIBS) $(LIB_SOCKET)
+client_LDADD = ../lib/libsasl2.la $(GSSAPIBASE_LIBS) $(GSSAPI_LIBS) $(LIB_SOCKET)
 
-sample_client_LDADD = ../lib/libsasl2.la $(LIB_SOCKET)
-sample_server_LDADD = ../lib/libsasl2.la $(LIB_SOCKET)
+sample_client_LDADD = ../lib/libsasl2.la $(GSSAPIBASE_LIBS) $(GSSAPI_LIBS) $(LIB_SOCKET)
+sample_server_LDADD = ../lib/libsasl2.la $(GSSAPIBASE_LIBS) $(GSSAPI_LIBS) $(LIB_SOCKET)
 
 EXTRA_DIST = NTMakefile
index f1a87d7..0c4facc 100644 (file)
@@ -244,11 +244,11 @@ sample_server_SOURCES = sample-server.c
 server_SOURCES = server.c common.c common.h
 client_SOURCES = client.c common.c common.h
 
-server_LDADD = ../lib/libsasl2.la $(LIB_SOCKET)
-client_LDADD = ../lib/libsasl2.la $(LIB_SOCKET)
+server_LDADD = ../lib/libsasl2.la $(GSSAPIBASE_LIBS) $(GSSAPI_LIBS) $(LIB_SOCKET)
+client_LDADD = ../lib/libsasl2.la $(GSSAPIBASE_LIBS) $(GSSAPI_LIBS) $(LIB_SOCKET)
 
-sample_client_LDADD = ../lib/libsasl2.la $(LIB_SOCKET)
-sample_server_LDADD = ../lib/libsasl2.la $(LIB_SOCKET)
+sample_client_LDADD = ../lib/libsasl2.la $(GSSAPIBASE_LIBS) $(GSSAPI_LIBS) $(LIB_SOCKET)
+sample_server_LDADD = ../lib/libsasl2.la $(GSSAPIBASE_LIBS) $(GSSAPI_LIBS) $(LIB_SOCKET)
 
 EXTRA_DIST = NTMakefile
 subdir = sample
index a2b35a0..169bfe8 100644 (file)
@@ -628,3 +628,4 @@ main(int argc, char *argv[])
 
   return (EXIT_SUCCESS);
 }
+
index e0af99c..b721054 100644 (file)
@@ -58,6 +58,8 @@
 #include <netdb.h>
 
 #include <sasl.h>
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_ext.h>
 
 #include "common.h"
 
 #undef      IPV6_V6ONLY
 #endif
 
+static OM_uint32
+enumerateAttributes(OM_uint32 *minor,
+                    gss_name_t name,
+                    int noisy);
+
 /* create a socket listening on port 'port' */
 /* if af is PF_UNSPEC more than one socket may be returned */
 /* the returned list is dynamically allocated, so caller needs to free it */
@@ -170,6 +177,7 @@ int mysasl_negotiate(FILE *in, FILE *out, sasl_conn_t *conn)
     int len;
     int r = SASL_FAIL;
     const char *userid;
+    gss_name_t peer = GSS_C_NO_NAME;
     
     /* generate the capability list */
     if (mech) {
@@ -273,6 +281,12 @@ int mysasl_negotiate(FILE *in, FILE *out, sasl_conn_t *conn)
     r = sasl_getprop(conn, SASL_USERNAME, (const void **) &userid);
     printf("successful authentication '%s'\n", userid);
 
+    r = sasl_getprop(conn, SASL_GSS_PEER_NAME, (const void **) &peer);
+    if (peer != GSS_C_NO_NAME) {
+        OM_uint32 minor;
+        enumerateAttributes(&minor, peer, 1);
+    }
+
     return 0;
 }
 
@@ -426,3 +440,117 @@ int main(int argc, char *argv[])
 
     sasl_done();
 }
+
+static void displayStatus_1(m, code, type)
+    char *m;
+    OM_uint32 code;
+    int type;
+{
+    OM_uint32 maj_stat, min_stat;
+    gss_buffer_desc msg;
+    OM_uint32 msg_ctx;
+
+    msg_ctx = 0;
+    while (1) {
+        maj_stat = gss_display_status(&min_stat, code,
+                                      type, GSS_C_NULL_OID,
+                                      &msg_ctx, &msg);
+        fprintf(stderr, "%s: %s\n", m, (char *)msg.value);
+        (void) gss_release_buffer(&min_stat, &msg);
+
+        if (!msg_ctx)
+            break;
+    }
+}
+
+static void displayStatus(msg, maj_stat, min_stat)
+    char *msg;
+    OM_uint32 maj_stat;
+    OM_uint32 min_stat;
+{
+    displayStatus_1(msg, maj_stat, GSS_C_GSS_CODE);
+    displayStatus_1(msg, min_stat, GSS_C_MECH_CODE);
+}
+
+static void
+dumpAttribute(OM_uint32 *minor,
+              gss_name_t name,
+              gss_buffer_t attribute,
+              int noisy)
+{
+    OM_uint32 major, tmp;
+    gss_buffer_desc value;
+    gss_buffer_desc display_value;
+    int authenticated = 0;
+    int complete = 0;
+    int more = -1;
+    unsigned int i;
+
+    while (more != 0) {
+        value.value = NULL;
+        display_value.value = NULL;
+
+        major = gss_get_name_attribute(minor,
+                                       name,
+                                       attribute,
+                                       &authenticated,
+                                       &complete,
+                                       &value,
+                                       &display_value,
+                                       &more);
+        if (GSS_ERROR(major)) {
+            displayStatus("gss_get_name_attribute", major, *minor);
+            break;
+        }
+
+        printf("Attribute %.*s %s %s\n\n%.*s\n",
+               (int)attribute->length, (char *)attribute->value,
+               authenticated ? "Authenticated" : "",
+               complete ? "Complete" : "",
+               (int)display_value.length, (char *)display_value.value);
+
+        if (noisy) {
+            for (i = 0; i < value.length; i++) {
+                if ((i % 32) == 0)
+                    printf("\n");
+                printf("%02x", ((char *)value.value)[i] & 0xFF);
+            }
+            printf("\n\n");
+        }
+
+        gss_release_buffer(&tmp, &value);
+        gss_release_buffer(&tmp, &display_value);
+    }
+}
+
+static OM_uint32
+enumerateAttributes(OM_uint32 *minor,
+                    gss_name_t name,
+                    int noisy)
+{
+    OM_uint32 major, tmp;
+    int name_is_MN;
+    gss_OID mech = GSS_C_NO_OID;
+    gss_buffer_set_t attrs = GSS_C_NO_BUFFER_SET;
+    unsigned int i;
+
+    major = gss_inquire_name(minor,
+                             name,
+                             &name_is_MN,
+                             &mech,
+                             &attrs);
+    if (GSS_ERROR(major)) {
+        displayStatus("gss_inquire_name", major, *minor);
+        return major;
+    }
+
+    if (attrs != GSS_C_NO_BUFFER_SET) {
+        for (i = 0; i < attrs->count; i++)
+            dumpAttribute(minor, name, &attrs->elements[i], noisy);
+    }
+
+    gss_release_oid(&tmp, &mech);
+    gss_release_buffer_set(&tmp, &attrs);
+
+    return major;
+}