X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Fmod_auth_gssapi.c;h=9e3eca344bd7be2e89cab86247bae3021cc2371c;hb=66857a8e364591a3f28f47a61f893b400721e1a6;hp=9296135ae29b4736a386c2be596f23839e373301;hpb=b36fe3602ed6c44499c61f2570aa6f92e9d5f314;p=mod_auth_gssapi.git diff --git a/src/mod_auth_gssapi.c b/src/mod_auth_gssapi.c index 9296135..9e3eca3 100644 --- a/src/mod_auth_gssapi.c +++ b/src/mod_auth_gssapi.c @@ -25,19 +25,25 @@ #include #include #include +#include #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 save_creds; + bool map_to_local; + bool gss_conn_ctx; + gss_key_value_set_desc cred_store; }; static char *mag_status(request_rec *req, int type, uint32_t err) @@ -81,6 +87,35 @@ static char *mag_error(request_rec *req, const char *msg, return apr_psprintf(req->pool, "%s: [%s (%s)]", msg, msg_maj, msg_min); } +struct mag_conn { + 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; + + ap_set_module_config(c->conn_config, &auth_gssapi_module, (void*)mc); + return OK; +} + +static APR_OPTIONAL_FN_TYPE(ssl_is_https) *mag_is_https = NULL; + +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; @@ -99,15 +134,45 @@ static int mag_auth(request_rec *req) uint32_t maj, min; char *reply; size_t replen; + 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); - /* FIXME: Checks for ssl only configuration */ + if (cfg->ssl_only) { + 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; + } else { + ctx = mc->ctx; + } + } auth_header = apr_table_get(req->headers_in, "Authorization"); if (!auth_header) goto done; @@ -124,11 +189,9 @@ 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, &input, GSS_C_NO_CHANNEL_BINDINGS, - &client, NULL, &output, &flags, NULL, + &client, &mech_type, &output, &flags, NULL, &delegated_cred); if (GSS_ERROR(maj)) { ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, @@ -137,16 +200,26 @@ 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); + if (mc) { + mc->ctx = ctx; + ctx = GSS_C_NO_CONTEXT; + } + + if (maj == GSS_S_CONTINUE_NEEDED) goto done; + +#ifdef HAVE_GSS_STORE_CRED_INTO + if (cfg->cred_store && delegated_cred != GSS_C_NO_CREDENTIAL) { + gss_key_value_set_desc store = {0, NULL}; + /* FIXME: run substtutions */ + + maj = gss_store_cred_into(&min, delegated_cred, GSS_C_INITIATE, + GSS_C_NULL_OID, 1, 1, &store, NULL, NULL); } +#endif + + 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, @@ -154,22 +227,52 @@ static int mag_auth(request_rec *req) maj, min)); goto done; } + clientname = apr_pstrndup(req->pool, name.value, name.length); + apr_table_set(req->subprocess_env, "GSS_NAME", clientname); + + if (cfg->map_to_local) { + maj = gss_localname(&min, client, mech_type, &lname); + if (maj != GSS_S_COMPLETE) { + ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, + mag_error(req, "gss_localname() failed", maj, min)); + goto done; + } + req->user = apr_pstrndup(req->pool, lname.value, lname.length); + } else { + req->user = clientname; + } - /* FIXME: save creds */ + if (mc) { + mc->user_name = apr_pstrdup(req->connection->pool, req->user); + mc->gss_name = apr_pstrdup(req->connection->pool, clientname); + mc->established = true; + } - req->ap_auth_type = "Negotiate"; - req->user = apr_pstrndup(req->pool, name.value, name.length); 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); + reply[replen] = '\0'; + 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; } @@ -191,18 +294,75 @@ static const char *mag_ssl_only(cmd_parms *parms, void *mconfig, int on) return NULL; } -static const char *mag_save_creds(cmd_parms *parms, void *mconfig, int on) +static const char *mag_map_to_local(cmd_parms *parms, void *mconfig, int on) { struct mag_config *cfg = (struct mag_config *)mconfig; - cfg->save_creds = on ? true : false; + cfg->map_to_local = on ? true : false; + 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) +{ + struct mag_config *cfg = (struct mag_config *)mconfig; + gss_key_value_element_desc *elements; + uint32_t count; + size_t size; + const char *p; + char *value; + char *key; + + p = strchr(w, ':'); + if (!p) { + ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server, + "%s [%s]", "Invalid syntax for GSSCredStore option", w); + return NULL; + } + + key = apr_pstrndup(parms->pool, w, (p-w)); + value = apr_pstrdup(parms->pool, p + 1); + if (!key || !value) { + ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server, + "%s", "OOM handling GSSCredStore option"); + return NULL; + } + + size = sizeof(gss_key_value_element_desc) * cfg->cred_store.count + 1; + elements = apr_palloc(parms->pool, size); + if (!elements) { + ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, parms->server, + "%s", "OOM handling GSSCredStore option"); + return NULL; + } + + for (count = 0; count < cfg->cred_store.count; count++) { + elements[count] = cfg->cred_store.elements[count]; + } + elements[count].key = key; + elements[count].value = value; + + cfg->cred_store.elements = elements; + cfg->cred_store.count = count; + return NULL; } static const command_rec mag_commands[] = { AP_INIT_FLAG("GSSSSLOnly", mag_ssl_only, NULL, OR_AUTHCFG, "Work only if connection is SSL Secured"), - AP_INIT_FLAG("GSSSaveCreds", mag_save_creds, NULL, OR_AUTHCFG, - "Save credentials"), + 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 } }; @@ -210,6 +370,7 @@ static void mag_register_hooks(apr_pool_t *p) { ap_hook_check_user_id(mag_auth, 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 =