Code for gssweb module check_user hook.
authorMargaret Wasserman <margaret@margaret-moonshot3.painless-security.com>
Wed, 9 Jul 2014 21:32:28 +0000 (17:32 -0400)
committerMargaret Wasserman <margaret@margaret-moonshot3.painless-security.com>
Wed, 9 Jul 2014 21:32:28 +0000 (17:32 -0400)
gss.c
gss.h
mod_auth_gssweb.c

diff --git a/gss.c b/gss.c
index 86de45d..d176de6 100644 (file)
--- a/gss.c
+++ b/gss.c
@@ -63,7 +63,7 @@ gss_get_conn_ctx(request_rec *r)
     char key[1024];
     gss_conn_ctx ctx = NULL;
 
-    snprintf(key, sizeof(key), "mod_auth_gssapi:conn_ctx");
+    snprintf(key, sizeof(key), "mod_auth_gssweb:conn_ctx");
     apr_pool_userdata_get((void **)&ctx, key, r->connection->pool);
     /* XXX LOG */
     if (ctx == NULL) {
diff --git a/gss.h b/gss.h
index 6fde4b8..cc055f8 100644 (file)
--- a/gss.h
+++ b/gss.h
@@ -52,13 +52,16 @@ typedef struct {
 } gss_auth_config;
 
 typedef struct gss_conn_ctx_t {
-    gss_ctx_id_t context;
-    enum {
-       GSS_CTX_EMPTY,
-       GSS_CTX_IN_PROGRESS,
-       GSS_CTX_ESTABLISHED,
-    } state;
-    char *user;
+  gss_ctx_id_t context;
+  enum {
+    GSS_CTX_EMPTY,
+    GSS_CTX_IN_PROGRESS,
+    GSS_CTX_FAILED,
+    GSS_CTX_ESTABLISHED,
+  } state;
+  char *user;
+  gss_buffer_desc *output_token;
+  unsigned int nonce;
 } *gss_conn_ctx;
 
 void
index 8b93d12..2648246 100644 (file)
@@ -57,39 +57,30 @@ gssweb_authenticate_user(request_rec *r)
     char *negotiate_ret_value = NULL;
     gss_conn_ctx conn_ctx = NULL;
     int ret;
+    OM_uint32 major_status, minor_status, minor_status2;
+    gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
+    gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
+    const char *posted_token = NULL;
+    int ret;
+    gss_name_t client_name = GSS_C_NO_NAME;
+    gss_cred_id_t delegated_cred = GSS_C_NO_CREDENTIAL;
+    gss_cred_id_t server_creds = GSS_C_NO_CREDENTIAL;
+    OM_uint32 ret_flags = 0;
+    unsigned int nonce;
 
     gss_log(APLOG_MARK, APLOG_DEBUG, 0, r, "Entering GSSWeb authentication");
    
-    /* get the type specified in Apache configuration */
+    /* Check if this is for our auth type */
     type = ap_auth_type(r);
     if (type == NULL || strcasecmp(type, "GSSWeb") != 0) {
         gss_log(APLOG_MARK, APLOG_DEBUG, 0, r,
-               "AuthType '%s' is not for us, bailing out",
+               "AuthType '%s' is not GSSWeb, bailing out",
                (type) ? type : "(NULL)");
 
         return DECLINED;
     }
 
-    /* get what the user sent us in the HTTP header */
-    auth_line = apr_table_get(r->headers_in, (r->proxyreq == PROXYREQ_PROXY)
-                                           ? "Proxy-Authorization"
-                                           : "Authorization");
-    if (auth_line == NULL) {
-        gss_log(APLOG_MARK, APLOG_DEBUG, 0, r,
-               "Client hasn't sent an authorization header, giving up");
-        set_http_headers(r, conf, "\0");
-        return HTTP_UNAUTHORIZED;
-    }
-
-    auth_type = ap_getword_white(r->pool, &auth_line);
-    if (strcasecmp(auth_type, "gssweb") != 0) {
-        gss_log(APLOG_MARK, APLOG_DEBUG, 0, r,
-               "Unsupported authentication type (%s) requested by client",
-               (auth_type) ? auth_type : "(NULL)");
-        set_http_headers(r, conf, "\0");
-        return HTTP_UNAUTHORIZED;
-    }
-
+    /* Set up a GSS context for this request, if there isn't one already */
     conn_ctx = gss_get_conn_ctx(r);
     if (conn_ctx == NULL) {
        gss_log(APLOG_MARK, APLOG_ERR, 0, r,
@@ -97,35 +88,102 @@ gssweb_authenticate_user(request_rec *r)
        return HTTP_INTERNAL_SERVER_ERROR;
     }
 
-    /* optimizing hack */
-    if (conn_ctx->state == GSS_CTX_ESTABLISHED && auth_line == NULL) {
-       r->user = apr_pstrdup(r->pool, conn_ctx->user);
-       r->ap_auth_type = "Negotiate";
-       return OK;
+    /* Set-up the output filter, if we haven't already */
+    if (GSS_CTX_EMPTY == conn_ctx->state) {
+
+      // TBD -- Set-up the output filter 
     }
 
-    /* XXXX subrequests ignored, only successful accesses taken into account! */
-    if (!ap_is_initial_req(r) && conn_ctx->state == GSS_CTX_ESTABLISHED) {
-       r->user = apr_pstrdup(r->pool, conn_ctx->user);
-       r->ap_auth_type = "Negotiate";
-       return OK;
+    /* Read the token and nonce from the POST */
+    //TBD -- gss_log the values
+
+    /* If the nonce is set and doesn't match, start over */
+    if ((0 != conn_ctx_nonce) && (conn_ctx->nonce != nonce) {
+       if (GSS_C_NO_CONTEXT != conn_ctx->context) {
+         gss_delete_sec_context(&minor_status, &conn_ctx->context, GSS_C_NO_BUFFER);
+       }
+       conn_ctx->context = GSS_C_NO_CONTEXT;
+       conn_ctx->state = GSS_CTX_EMPTY;
+       conn_ctx->user = NULL;
+       if (NULL != conn_ctx->output_token) {
+         // TBD -- release the output token
+       }
+       conn_ctx->output_token = NULL;
+      }
+      conn_ctx->nonce = nonce;
+      
+    /* If the output filter reported an internal server error, return it */
+    if (GSS_CTX_ERROR == conn_ctx->state) {
+      ret = HTTP_INTERNAL_SERVER_ERROR;
+      gss_log(APLOG_MARK, APLOG_ERR, 0, r,
+             "Output filter returned internal server error, reporting.");
+      goto end;
     }
 
-    ret = gss_authenticate(r, conf, conn_ctx,
-                          auth_line, &negotiate_ret_value);
-    if (ret == HTTP_UNAUTHORIZED || ret == OK) {
-        /* LOG?? */
-        set_http_headers(r, conf, negotiate_ret_value);
+    /* Acquire server credentials */
+    ret = get_gss_creds(r, conf, &server_creds);
+    if (ret)
+      goto end;
+
+    /* Decode input token */
+    input_token.length = apr_base64_decode(input_token.value, posted_token);
+
+    /* Call gss_accept_sec_context */
+    major_status = gss_accept_sec_context(&minor_status,
+                                         &ctx->context,
+                                         server_creds,
+                                         &input_token,
+                                         GSS_C_NO_CHANNEL_BINDINGS,
+                                         NULL,
+                                         NULL,
+                                         &output_token,
+                                         &ret_flags,
+                                         NULL,
+                                         &delegated_cred);
+    gss_log(APLOG_MARK, APLOG_DEBUG, 0, r,
+           "Client %s us their credential",
+           (ret_flags & GSS_C_DELEG_FLAG) ? "delegated" : "didn't delegate");
+
+    if (GSS_ERROR(major_status)) {
+      gss_log(APLOG_MARK, APLOG_ERR, 0, r,
+             "%s", get_gss_error(r, major_status, minor_status,
+                                 "Failed to establish authentication"));
+      gss_delete_sec_context(&minor_status, &ctx->context, GSS_C_NO_BUFFER);
+      ctx->context = GSS_C_NO_CONTEXT;
+      ctx->state = GSS_CTX_EMPTY;
+      ret = HTTP_UNAUTHORIZED;
+      goto end;
     }
 
-    if (ret == OK) {
-       r->user = apr_pstrdup(r->pool, conn_ctx->user);
-       r->ap_auth_type = "Negotiate";
+    /* Store the token & nonce in the stored context */
+    conn_ctx.output_token = &output_token;
+    conn_ctx.nonce = nonce;
+
+    /* If we aren't done yet, go around again */
+    if (major_status & GSS_S_CONTINUE_NEEDED) {
+      ctx->state = GSS_CTX_IN_PROGRESS;
+      ret = HTTP_UNAUTHORIZED;
+      goto end;
     }
 
-    /* debug LOG ??? */
+    ctx->state = GSS_CTX_ESTABLISHED;
+    ret = OK;
+
+ end:
+  if (delegated_cred)
+     gss_release_cred(&minor_status, &delegated_cred);
+
+  if (output_token.length) 
+     gss_release_buffer(&minor_status, &output_token);
+
+  if (client_name != GSS_C_NO_NAME)
+     gss_release_name(&minor_status, &client_name);
+
+  if (server_creds != GSS_C_NO_CREDENTIAL)
+     gss_release_cred(&minor_status, &server_creds);
+
+  return ret;
 
-    return ret;
 }
 
 static void