X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Fmod_auth_gssapi.c;h=99bef7fba1b7c764ee22eb49d87d9d31a0997950;hb=574d469f451f2c68809c56a3a8c905a7800df33d;hp=e6fb2091824f9407df5f2160f70acf8a44ed197f;hpb=60509195fb41173ba8e6cfac8bf800935ebb86ad;p=mod_auth_gssapi.git diff --git a/src/mod_auth_gssapi.c b/src/mod_auth_gssapi.c index e6fb209..99bef7f 100644 --- a/src/mod_auth_gssapi.c +++ b/src/mod_auth_gssapi.c @@ -29,16 +29,20 @@ #include #include +#include #include #include #include #include -module AP_MODULE_DECLARE_DATA mag_module; +module AP_MODULE_DECLARE_DATA auth_gssapi_module; + +APR_DECLARE_OPTIONAL_FN(int, ssl_is_https, (conn_rec *)); struct mag_config { bool ssl_only; bool map_to_local; + bool gss_conn_ctx; gss_key_value_set_desc cred_store; }; @@ -83,6 +87,59 @@ static char *mag_error(request_rec *req, const char *msg, return apr_psprintf(req->pool, "%s: [%s (%s)]", msg, msg_maj, msg_min); } +static APR_OPTIONAL_FN_TYPE(ssl_is_https) *mag_is_https = NULL; + +static int mag_post_config(apr_pool_t *cfg, apr_pool_t *log, + apr_pool_t *temp, server_rec *s) +{ + /* FIXME: create mutex to deal with connections and contexts ? */ + mag_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https); + + return OK; +} + + +struct mag_conn { + apr_pool_t *parent; + gss_ctx_id_t ctx; + bool established; + char *user_name; + char *gss_name; +}; + +static int mag_pre_connection(conn_rec *c, void *csd) +{ + struct mag_conn *mc; + + mc = apr_pcalloc(c->pool, sizeof(struct mag_conn)); + if (!mc) return DECLINED; + + mc->parent = c->pool; + ap_set_module_config(c->conn_config, &auth_gssapi_module, (void*)mc); + return OK; +} + +static apr_status_t mag_conn_destroy(void *ptr) +{ + struct mag_conn *mc = (struct mag_conn *)ptr; + uint32_t min; + + if (mc->ctx) { + (void)gss_delete_sec_context(&min, &mc->ctx, GSS_C_NO_BUFFER); + mc->established = false; + } + return APR_SUCCESS; +} + +static bool mag_conn_is_https(conn_rec *c) +{ + if (mag_is_https) { + if (mag_is_https(c)) return true; + } + + return false; +} + static int mag_auth(request_rec *req) { const char *type; @@ -92,6 +149,7 @@ static int mag_auth(request_rec *req) char *auth_header_value; int ret = HTTP_UNAUTHORIZED; gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; + gss_ctx_id_t *pctx; gss_buffer_desc input = GSS_C_EMPTY_BUFFER; gss_buffer_desc output = GSS_C_EMPTY_BUFFER; gss_buffer_desc name = GSS_C_EMPTY_BUFFER; @@ -104,17 +162,42 @@ static int mag_auth(request_rec *req) char *clientname; gss_OID mech_type = GSS_C_NO_OID; gss_buffer_desc lname = GSS_C_EMPTY_BUFFER; + struct mag_conn *mc = NULL; type = ap_auth_type(req); if ((type == NULL) || (strcasecmp(type, "GSSAPI") != 0)) { return DECLINED; } - cfg = ap_get_module_config(req->per_dir_config, &mag_module); + cfg = ap_get_module_config(req->per_dir_config, &auth_gssapi_module); if (cfg->ssl_only) { - ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, - "FIXME: check for ssl!"); + if (!mag_conn_is_https(req->connection)) { + ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, + "Not a TLS connection, refusing to authenticate!"); + goto done; + } + } + + if (cfg->gss_conn_ctx) { + mc = (struct mag_conn *)ap_get_module_config( + req->connection->conn_config, + &auth_gssapi_module); + if (!mc) { + return DECLINED; + } + if (mc->established) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, req, + "Connection bound pre-authentication found."); + apr_table_set(req->subprocess_env, "GSS_NAME", mc->gss_name); + req->ap_auth_type = apr_pstrdup(req->pool, "Negotiate"); + req->user = apr_pstrdup(req->pool, mc->user_name); + ret = OK; + goto done; + } + pctx = &mc->ctx; + } else { + pctx = &ctx; } auth_header = apr_table_get(req->headers_in, "Authorization"); @@ -132,9 +215,7 @@ static int mag_auth(request_rec *req) if (!input.value) goto done; input.length = apr_base64_decode(input.value, auth_header_value); - /* FIXME: this works only with "one-roundtrip" gssapi auth for now, - * should work with Krb, will fail with NTLMSSP */ - maj = gss_accept_sec_context(&min, &ctx, GSS_C_NO_CREDENTIAL, + maj = gss_accept_sec_context(&min, pctx, GSS_C_NO_CREDENTIAL, &input, GSS_C_NO_CHANNEL_BINDINGS, &client, &mech_type, &output, &flags, NULL, &delegated_cred); @@ -145,21 +226,19 @@ static int mag_auth(request_rec *req) goto done; } - if (output.length) { - replen = apr_base64_encode_len(output.length) + 1; - reply = apr_pcalloc(req->pool, 10 + replen); - if (!reply) goto done; - memcpy(reply, "Negotiate ", 10); - apr_base64_encode(&reply[10], output.value, output.length); - reply[replen] = '\0'; - apr_table_add(req->err_headers_out, "WWW-Authenticate", reply); - } + /* register the context in the connection pool, so it can be freed + * when the connection is terminated */ + apr_pool_userdata_set(mc, "mag_conn_ptr", mag_conn_destroy, mc->parent); - maj = gss_display_name(&min, client, &name, NULL); - if (GSS_ERROR(maj)) { - ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, - mag_error(req, "gss_accept_sec_context() failed", - maj, min)); + if (maj == GSS_S_CONTINUE_NEEDED) { + if (!cfg->gss_conn_ctx) { + ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, + "Mechanism needs continuation but " + "GSSConnectionContext is off."); + gss_delete_sec_context(&min, pctx, GSS_C_NO_BUFFER); + gss_release_buffer(&min, &output); + output.length = 0; + } goto done; } @@ -176,6 +255,13 @@ static int mag_auth(request_rec *req) req->ap_auth_type = apr_pstrdup(req->pool, "Negotiate"); /* Always set the GSS name in an env var */ + maj = gss_display_name(&min, client, &name, NULL); + if (GSS_ERROR(maj)) { + ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, + mag_error(req, "gss_accept_sec_context() failed", + maj, min)); + goto done; + } clientname = apr_pstrndup(req->pool, name.value, name.length); apr_table_set(req->subprocess_env, "GSS_NAME", clientname); @@ -190,17 +276,35 @@ static int mag_auth(request_rec *req) } else { req->user = clientname; } + + if (mc) { + mc->user_name = apr_pstrdup(mc->parent, req->user); + mc->gss_name = apr_pstrdup(mc->parent, clientname); + mc->established = true; + } + ret = OK; done: if (ret == HTTP_UNAUTHORIZED) { - apr_table_add(req->err_headers_out, "WWW-Authenticate", "Negotiate"); + if (output.length != 0) { + replen = apr_base64_encode_len(output.length) + 1; + reply = apr_pcalloc(req->pool, 10 + replen); + if (reply) { + memcpy(reply, "Negotiate ", 10); + apr_base64_encode(&reply[10], output.value, output.length); + apr_table_add(req->err_headers_out, + "WWW-Authenticate", reply); + } + } else { + apr_table_add(req->err_headers_out, + "WWW-Authenticate", "Negotiate"); + } } gss_release_cred(&min, &delegated_cred); gss_release_buffer(&min, &output); gss_release_name(&min, &client); gss_release_buffer(&min, &name); - gss_delete_sec_context(&min, &ctx, GSS_C_NO_BUFFER); gss_release_buffer(&min, &lname); return ret; } @@ -230,6 +334,13 @@ static const char *mag_map_to_local(cmd_parms *parms, void *mconfig, int on) return NULL; } +static const char *mag_conn_ctx(cmd_parms *parms, void *mconfig, int on) +{ + struct mag_config *cfg = (struct mag_config *)mconfig; + cfg->gss_conn_ctx = on ? true : false; + return NULL; +} + static const char *mag_cred_store(cmd_parms *parms, void *mconfig, const char *w) { @@ -281,6 +392,8 @@ static const command_rec mag_commands[] = { "Work only if connection is SSL Secured"), AP_INIT_FLAG("GSSLocalName", mag_map_to_local, NULL, OR_AUTHCFG, "Work only if connection is SSL Secured"), + AP_INIT_FLAG("GSSConnectionContext", mag_conn_ctx, NULL, OR_AUTHCFG, + "Authentication is valid for the life of the connection"), AP_INIT_ITERATE("GSSCredStore", mag_cred_store, NULL, OR_AUTHCFG, "Credential Store"), { NULL } @@ -290,6 +403,8 @@ static void mag_register_hooks(apr_pool_t *p) { ap_hook_check_user_id(mag_auth, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_post_config(mag_post_config, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_pre_connection(mag_pre_connection, NULL, NULL, APR_HOOK_MIDDLE); } module AP_MODULE_DECLARE_DATA auth_gssapi_module =