From 4e67528fd1666614e34c6cddacf9d93a12370e33 Mon Sep 17 00:00:00 2001 From: Alejandro Perez Date: Thu, 14 Jan 2016 16:41:37 +0100 Subject: [PATCH] Implemented support for exporting GSS NAME attributes as environment variables. This code is strogly based on the code from https://github.com/modauthgssapi/mod_auth_gssapi, whith the required adaptations for accommodating it to this module. --- LICENSE | 29 +++++ Makefile.in | 4 +- README_name_attr | 20 +++ gss.c | 383 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- gss.h | 52 +++++++- mod_auth_gssapi.c | 21 ++- mod_auth_gssweb.c | 53 ++++---- 7 files changed, 512 insertions(+), 50 deletions(-) create mode 100644 README_name_attr diff --git a/LICENSE b/LICENSE index 1b8bb7e..ea9677c 100644 --- a/LICENSE +++ b/LICENSE @@ -167,3 +167,32 @@ src/mit-internals.h) which are licensed under following terms: * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ + + /* + * This package also contains parts (specifically related to the GSS + * attribute to environment variables code) that are strongly based + * on the code from https://github.com/modauthgssapi/mod_auth_gssapi, + * which is licensed under the following terms: + * + * MOD_AUTH_GSSAPI + * + * Copyright (C) 2014 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ diff --git a/Makefile.in b/Makefile.in index fdd912f..ad8c2b8 100644 --- a/Makefile.in +++ b/Makefile.in @@ -28,8 +28,8 @@ mod_auth_gssweb.la: $(GSSWEB_SRCS) install: mod_auth_gssapi.la mod_auth_gssweb.la $(INSTALL) -d $(DESTDIR)${libdir}/apache2/modules $(INSTALL) -d $(DESTDIR)${sysconfdir}/apache2/mods-available - ./apxs.sh "${CPPFLAGS}" "${LDFLAGS}" $^ "${APXS} -i -A -S LIBEXECDIR=$(DESTDIR)${libdir}/apache2/modules -S SYSCONFDIR=$(DESTDIR)${sysconfdir}/apache2 -n auth_gssapi" - ./apxs.sh "${CPPFLAGS}" "${LDFLAGS}" $^ "${APXS} -i -A -S LIBEXECDIR=$(DESTDIR)${libdir}/apache2/modules -S SYSCONFDIR=$(DESTDIR)${sysconfdir}/apache2 -n auth_gssweb" + ./apxs.sh "${CPPFLAGS}" "${LDFLAGS}" mod_auth_gssapi.la "${APXS} -i -A -S LIBEXECDIR=$(DESTDIR)${libdir}/apache2/modules -S SYSCONFDIR=$(DESTDIR)${sysconfdir}/apache2 -n auth_gssapi" + ./apxs.sh "${CPPFLAGS}" "${LDFLAGS}" mod_auth_gssweb.la "${APXS} -i -A -S LIBEXECDIR=$(DESTDIR)${libdir}/apache2/modules -S SYSCONFDIR=$(DESTDIR)${sysconfdir}/apache2 -n auth_gssweb" clean: for i in . spnegokrb5; do \ diff --git a/README_name_attr b/README_name_attr new file mode 100644 index 0000000..1dcdec0 --- /dev/null +++ b/README_name_attr @@ -0,0 +1,20 @@ +#### GssapiNameAttributes + +Enables the module to source Name Attributes from the client name +(authorization data associated with the established context) and exposes them +as environment variables. + +Value format: ENV_VAR_NAME ATTRIBUTE_NAME + +This option can be specified multiple times, once for each attribute to expose. +The Special value "json" is used to expose all attributes in a json formatted +string via the special environment variable GSS_NAME_ATTRS_JSON +The environment variable GSS_NAME_ATTR_ERROR is set with the Gssapi returned +error string in case the inquire name function fails to retrieve attributes, +and with the string "0 attributes found", if no attributes are set. + +#### Example + GssapiNameAttributes json + GssapiNameAttributes RADIUS_USER_NAME urn:ietf:params:gss:radius-attribute 1 + GssapiNameAttributes EPPN urn:ietf:params:gss:federated-saml-attribute urn:oasis:names:tc:SAML:2.0:attrname-format:uri urn:oid:1.3.6.1.4.1.5923.1.1.1.6 + diff --git a/gss.c b/gss.c index cab10c3..9ebba62 100644 --- a/gss.c +++ b/gss.c @@ -32,7 +32,7 @@ #include "mod_auth_gssapi.h" void -gss_log(const char *file, +gss_log(const char *file, int line, #if AP_SERVER_MAJORVERSION_NUMBER == 2 && AP_SERVER_MINORVERSION_NUMBER == 4 int module_index, @@ -48,16 +48,16 @@ gss_log(const char *file, va_start(ap, fmt); vsnprintf(errstr, sizeof(errstr), fmt, ap); va_end(ap); - + ap_log_rerror(file, - line, + line, #if AP_SERVER_MAJORVERSION_NUMBER == 2 && AP_SERVER_MINORVERSION_NUMBER == 4 module_index, #endif - level | APLOG_NOERRNO, - status, - r, - "%s", + level | APLOG_NOERRNO, + status, + r, + "%s", errstr); } @@ -69,7 +69,7 @@ gss_cleanup_conn_ctx(void *data) if (ctx && ctx->context != GSS_C_NO_CONTEXT) gss_delete_sec_context(&minor_status, &ctx->context, GSS_C_NO_BUFFER); - + if (ctx && ctx->server_creds != GSS_C_NO_CREDENTIAL) gss_release_cred(&minor_status, &ctx->server_creds); @@ -81,10 +81,10 @@ gss_create_conn_ctx(request_rec *r, gss_auth_config *conf) { char key[1024]; gss_conn_ctx ctx = NULL; - + snprintf(key, sizeof(key), "mod_auth_gssweb:conn_ctx"); - - if (NULL == (ctx = (gss_conn_ctx) apr_palloc(r->connection->pool, sizeof(*ctx)))) { + + if (NULL == (ctx = (gss_conn_ctx) apr_pcalloc(r->connection->pool, sizeof(*ctx)))) { gss_log(APLOG_MARK, APLOG_ERR, 0, r, "gss_create_conn_ctx: Can't allocate GSS context"); return NULL; } @@ -92,6 +92,12 @@ gss_create_conn_ctx(request_rec *r, gss_auth_config *conf) ctx->state = GSS_CTX_EMPTY; ctx->filter_stat = GSS_FILT_NEW; ctx->user = NULL; + ctx->name_attributes = NULL; + apr_pool_create(&ctx->pool, r->connection->pool); + /* register the context in the memory pool, so it can be freed + * when the connection/request is terminated */ + apr_pool_cleanup_register(ctx->pool, (void *)ctx, + gss_cleanup_conn_ctx, apr_pool_cleanup_null); /* Acquire and store server credentials */ if (0 == get_gss_creds(r, conf, &(ctx->server_creds))) { @@ -111,7 +117,7 @@ gss_retrieve_conn_ctx(request_rec *r) { char key[1024]; gss_conn_ctx ctx = NULL; - + snprintf(key, sizeof(key), "mod_auth_gssweb:conn_ctx"); apr_pool_userdata_get((void **)&ctx, key, r->connection->pool); @@ -127,6 +133,8 @@ gss_config_dir_create(apr_pool_t *p, char *d) gss_auth_config *conf; conf = (gss_auth_config *) apr_pcalloc(p, sizeof(*conf)); + conf->pool = p; + return conf; } @@ -134,7 +142,7 @@ gss_config_dir_create(apr_pool_t *p, char *d) const char * get_gss_error(request_rec *r, OM_uint32 err_maj, OM_uint32 err_min, char *prefix) { - OM_uint32 maj_stat, min_stat; + OM_uint32 maj_stat, min_stat; OM_uint32 msg_ctx = 0; gss_buffer_desc status_string; char *err_msg; @@ -234,7 +242,7 @@ get_gss_creds(request_rec *r, gss_log(APLOG_MARK, APLOG_DEBUG, 0, r, "Acquiring creds for %s", token.value); gss_release_buffer(&minor_status, &token); - + major_status = gss_acquire_cred(&minor_status, server_name, GSS_C_INDEFINITE, GSS_C_NO_OID_SET, GSS_C_ACCEPT, server_creds, NULL, NULL); @@ -276,3 +284,350 @@ cmp_gss_type(gss_buffer_t token, gss_OID oid) return memcmp(p, oid->elements, oid->length); } +/* + * Name attributes to environment variables code + * This code is strongly based on the code from https://github.com/modauthgssapi/mod_auth_gssapi + */ + +static char *mag_status(request_rec *req, int type, uint32_t err) +{ + uint32_t maj_ret, min_ret; + gss_buffer_desc text; + uint32_t msg_ctx; + char *msg_ret; + int len; + + msg_ret = NULL; + msg_ctx = 0; + do { + maj_ret = gss_display_status(&min_ret, err, type, + GSS_C_NO_OID, &msg_ctx, &text); + if (maj_ret != GSS_S_COMPLETE) { + return msg_ret; + } + + len = text.length; + if (msg_ret) { + msg_ret = apr_psprintf(req->pool, "%s, %*s", + msg_ret, len, (char *)text.value); + } else { + msg_ret = apr_psprintf(req->pool, "%*s", len, (char *)text.value); + } + gss_release_buffer(&min_ret, &text); + } while (msg_ctx != 0); + + return msg_ret; +} + +char *mag_error(request_rec *req, const char *msg, uint32_t maj, uint32_t min) +{ + char *msg_maj; + char *msg_min; + + msg_maj = mag_status(req, GSS_C_GSS_CODE, maj); + msg_min = mag_status(req, GSS_C_MECH_CODE, min); + return apr_psprintf(req->pool, "%s: [%s (%s)]", msg, msg_maj, msg_min); +} + + +static char mag_get_name_attr(request_rec *req, + gss_name_t name, name_attr *attr) +{ + uint32_t maj, min; + + maj = gss_get_name_attribute(&min, name, &attr->name, + &attr->authenticated, + &attr->complete, + &attr->value, + &attr->display_value, + &attr->more); + if (GSS_ERROR(maj)) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, + "gss_get_name_attribute() failed on %.*s%s", + (int)attr->name.length, (char *)attr->name.value, + mag_error(req, "", maj, min)); + return 0; + } + + return 1; +} + +static void mc_add_name_attribute(gss_conn_ctx_t *gss_ctx, + const char *name, const char *value) +{ + size_t size; + + if (gss_ctx->na_count % 16 == 0) { + size = sizeof(mag_attr) * (gss_ctx->na_count + 16); + gss_ctx->name_attributes = realloc(gss_ctx->name_attributes, size); + if (!gss_ctx->name_attributes) apr_pool_abort_get(gss_ctx->pool)(ENOMEM); + } + + gss_ctx->name_attributes[gss_ctx->na_count].name = apr_pstrdup(gss_ctx->pool, name); + gss_ctx->name_attributes[gss_ctx->na_count].value = apr_pstrdup(gss_ctx->pool, value); + gss_ctx->na_count++; +} + +static void mag_set_env_name_attr(request_rec *req, gss_conn_ctx_t *gss_ctx, + name_attr *attr) +{ + char *value = ""; + int len = 0; + + /* Prefer a display_value, otherwise fallback to value */ + if (attr->display_value.length != 0) { + len = attr->display_value.length; + value = (char *)attr->display_value.value; + } else if (attr->value.length != 0) { + len = apr_base64_encode_len(attr->value.length); + value = apr_pcalloc(req->pool, len); + len = apr_base64_encode(value, + (char *)attr->value.value, + attr->value.length); + } + + if (attr->number == 1) { + mc_add_name_attribute(gss_ctx, + attr->env_name, + apr_psprintf(req->pool, "%.*s", len, value)); + } + if (attr->more != 0 || attr->number > 1) { + mc_add_name_attribute(gss_ctx, + apr_psprintf(req->pool, "%s_%d", + attr->env_name, attr->number), + apr_psprintf(req->pool, "%.*s", len, value)); + } + if (attr->more == 0 && attr->number > 1) { + mc_add_name_attribute(gss_ctx, + apr_psprintf(req->pool, "%s_N", attr->env_name), + apr_psprintf(req->pool, "%d", attr->number - 1)); + } +} + +static void mag_add_json_name_attr(request_rec *req, char first, + name_attr *attr, char **json) +{ + const char *value = ""; + int len = 0; + char *b64value = NULL; + int b64len = 0; + const char *vstart = ""; + const char *vend = ""; + const char *vformat; + + if (attr->value.length != 0) { + b64len = apr_base64_encode_len(attr->value.length); + b64value = apr_pcalloc(req->pool, b64len); + b64len = apr_base64_encode(b64value, + (char *)attr->value.value, + attr->value.length); + } + if (attr->display_value.length != 0) { + len = attr->display_value.length; + value = (const char *)attr->display_value.value; + } + if (attr->number == 1) { + *json = apr_psprintf(req->pool, + "%s%s\"%.*s\":{\"authenticated\":%s," + "\"complete\":%s," + "\"values\":[", + *json, (first ? "" : ","), + (int)attr->name.length, (char *)attr->name.value, + attr->authenticated ? "true" : "false", + attr->complete ? "true" : "false"); + } else { + vstart = ","; + } + + if (b64value) { + if (len) { + vformat = "%s%s{\"raw\":\"%s\",\"display\":\"%.*s\"}%s"; + } else { + vformat = "%s%s{\"raw\":\"%s\",\"display\":%.*s}%s"; + } + } else { + if (len) { + vformat = "%s%s{\"raw\":%s,\"display\":\"%.*s\"}%s"; + } else { + vformat = "%s%s{\"raw\":%s,\"display\":%.*s}%s"; + } + } + + if (attr->more == 0) { + vend = "]}"; + } + + *json = apr_psprintf(req->pool, vformat, *json, + vstart, + b64value ? b64value : "null", + len ? len : 4, len ? value : "null", + vend); +} + +gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER; + +void mag_get_name_attributes(request_rec *req, gss_auth_config *cfg, + gss_name_t name, gss_conn_ctx_t *gss_ctx) +{ + if (!cfg->name_attributes) { + return; + } + + uint32_t maj, min; + gss_buffer_set_t attrs = GSS_C_NO_BUFFER_SET; + name_attr attr; + char *json = NULL; + char *error; + int count = 0; + int i, j; + + maj = gss_inquire_name(&min, name, NULL, NULL, &attrs); + if (GSS_ERROR(maj)) { + error = mag_error(req, "gss_inquire_name() failed", maj, min); + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "%s", error); + apr_table_set(req->subprocess_env, "GSS_NAME_ATTR_ERROR", error); + return; + } + + if (!attrs || attrs->count == 0) { + mc_add_name_attribute(gss_ctx, "GSS_NAME_ATTR_ERROR", "0 attributes found"); + } + + if (cfg->name_attributes->output_json) { + + if (attrs) count = attrs->count; + + json = apr_psprintf(req->pool, + "{\"name\":\"%s\",\"attributes\":{", + gss_ctx->user); + } else { + count = cfg->name_attributes->map_count; + } + + for (i = 0; i < count; i++) { + memset(&attr, 0, sizeof(name_attr)); + + if (cfg->name_attributes->output_json) { + attr.name = attrs->elements[i]; + for (j = 0; j < cfg->name_attributes->map_count; j++) { + if (strncmp(cfg->name_attributes->map[j].attr_name, + attrs->elements[i].value, + attrs->elements[i].length) == 0) { + attr.env_name = cfg->name_attributes->map[j].env_name; + break; + } + } + } else { + attr.name.length = strlen(cfg->name_attributes->map[i].attr_name); + attr.name.value = cfg->name_attributes->map[i].attr_name; + attr.env_name = cfg->name_attributes->map[i].env_name; + } + + attr.number = 0; + attr.more = -1; + do { + char code = 0; + attr.number++; + attr.value = empty_buffer; + attr.display_value = empty_buffer; + if (!mag_get_name_attr(req, name, &attr)) break; + + if (cfg->name_attributes->output_json) { + mag_add_json_name_attr(req, i == 0, &attr, &json); + } + if (attr.env_name) { + mag_set_env_name_attr(req, gss_ctx, &attr); + } + + gss_release_buffer(&min, &attr.value); + gss_release_buffer(&min, &attr.display_value); + } while (attr.more != 0); + } + + if (cfg->name_attributes->output_json) { + json = apr_psprintf(req->pool, "%s}}", json); + mc_add_name_attribute(gss_ctx, "GSS_NAME_ATTRS_JSON", json); + } +} + +static void mag_set_name_attributes(request_rec *req, gss_conn_ctx_t *gss_ctx) +{ + int i = 0; + for (i = 0; i < gss_ctx->na_count; i++) { + apr_table_set(req->subprocess_env, + gss_ctx->name_attributes[i].name, + gss_ctx->name_attributes[i].value); + } +} + +void mag_set_req_data(request_rec *req, + gss_auth_config *cfg, + gss_conn_ctx_t *gss_ctx) +{ + if (gss_ctx->name_attributes) { + mag_set_name_attributes(req, gss_ctx); + } +} + +#define GSS_NAME_ATTR_USERDATA "GSS Name Attributes Userdata" + +static apr_status_t mag_name_attrs_cleanup(void *data) +{ + gss_auth_config *cfg = (gss_auth_config *)data; + free(cfg->name_attributes); + cfg->name_attributes = NULL; + return 0; +} + +const char *mag_name_attrs(cmd_parms *parms, void *mconfig, + const char *w) +{ + gss_auth_config *cfg = (gss_auth_config *)mconfig; + void *tmp_na; + size_t size = 0; + char *p; + int c; + + if (!cfg->name_attributes) { + size = sizeof(mag_name_attributes) + + (sizeof(mag_na_map) * 16); + } else if (cfg->name_attributes->map_count % 16 == 0) { + size = sizeof(mag_name_attributes) + + (sizeof(mag_na_map) + * (cfg->name_attributes->map_count + 16)); + } + if (size) { + tmp_na = realloc(cfg->name_attributes, size); + if (!tmp_na) apr_pool_abort_get(cfg->pool)(ENOMEM); + + if (cfg->name_attributes) { + size_t empty = (sizeof(mag_na_map) * 16); + memset(tmp_na + size - empty, 0, empty); + } else { + memset(tmp_na, 0, size); + } + cfg->name_attributes = (mag_name_attributes *)tmp_na; + apr_pool_userdata_setn(cfg, GSS_NAME_ATTR_USERDATA, + mag_name_attrs_cleanup, cfg->pool); + } + + + p = strchr(w, ' '); + if (p == NULL) { + if (strcmp(w, "json") == 0) { + cfg->name_attributes->output_json = 1; + } else { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, parms->server, + "Invalid Name Attributes value [%s].", w); + } + return NULL; + } + + c = cfg->name_attributes->map_count; + cfg->name_attributes->map[c].env_name = apr_pstrndup(cfg->pool, w, p-w); + p++; + cfg->name_attributes->map[c].attr_name = apr_pstrdup(cfg->pool, p); + cfg->name_attributes->map_count += 1; + + return NULL; +} \ No newline at end of file diff --git a/gss.h b/gss.h index 4c01355..611f68f 100644 --- a/gss.h +++ b/gss.h @@ -29,6 +29,11 @@ * POSSIBILITY OF SUCH DAMAGE. */ +/* + * Most of the name attributes management code is based from + * https://github.com/modauthgssapi/mod_auth_gssapi, written by Simo Sorce. + */ + #ifndef __GSS_H__ #define __GSS_H__ @@ -43,15 +48,47 @@ #include #include +#include +#include + #define SERVICE_NAME "HTTP" +typedef struct { + char *env_name; + char *attr_name; +} mag_na_map; + +typedef struct { + char output_json; + int map_count; + mag_na_map map[]; +} mag_name_attributes; + +typedef struct { + const char *name; + const char *value; +} mag_attr; + +typedef struct { + gss_buffer_desc name; + int authenticated; + int complete; + gss_buffer_desc value; + gss_buffer_desc display_value; + const char *env_name; + int number; + int more; +} name_attr; + typedef struct { const char *service_name; const char *krb5_keytab; + apr_pool_t *pool; + mag_name_attributes *name_attributes; } gss_auth_config; -typedef struct gss_conn_ctx_t { +typedef struct { gss_ctx_id_t context; gss_cred_id_t server_creds; enum { @@ -69,10 +106,16 @@ typedef struct gss_conn_ctx_t { char *user; gss_buffer_desc output_token; unsigned int nonce; -} *gss_conn_ctx; + apr_pool_t *pool; + int na_count; + mag_attr *name_attributes; +} gss_conn_ctx_t, *gss_conn_ctx; + + + void -gss_log(const char *file, +gss_log(const char *file, int line, #if AP_SERVER_MAJORVERSION_NUMBER == 2 && AP_SERVER_MINORVERSION_NUMBER == 4 int module_index, @@ -103,4 +146,7 @@ get_gss_creds(request_rec *r, gss_auth_config *conf, gss_cred_id_t *server_creds int cmp_gss_type(gss_buffer_t token, gss_OID oid); +const char * +mag_name_attrs(cmd_parms *parms, void *mconfig, const char *w); + #endif diff --git a/mod_auth_gssapi.c b/mod_auth_gssapi.c index 3f255b9..02ea261 100644 --- a/mod_auth_gssapi.c +++ b/mod_auth_gssapi.c @@ -45,6 +45,8 @@ static const command_rec gss_config_cmds[] = { command("GSSKrb5Keytab", ap_set_string_slot, krb5_keytab, TAKE1, "Location of Kerberos V5 keytab file."), + AP_INIT_RAW_ARGS("GssapiNameAttributes", mag_name_attrs, NULL, OR_AUTHCFG | RSRC_CONF, + "Name Attributes to be exported as environ variables"), { NULL } }; @@ -140,7 +142,7 @@ gss_authenticate(request_rec *r, gss_auth_config *conf, gss_conn_ctx ctx, #else accept_sec_context = (cmp_gss_type(&input_token, &spnego_oid) == 0) ? gss_accept_sec_context_spnego : gss_accept_sec_context; -#endif +#endif major_status = accept_sec_context(&minor_status, &ctx->context, @@ -159,7 +161,7 @@ gss_authenticate(request_rec *r, gss_auth_config *conf, gss_conn_ctx ctx, if (output_token.length) { char *token = NULL; size_t len; - + len = apr_base64_encode_len(output_token.length) + 1; token = apr_pcalloc(r->connection->pool, len + 1); if (token == NULL) { @@ -210,7 +212,13 @@ gss_authenticate(request_rec *r, gss_auth_config *conf, gss_conn_ctx ctx, } major_status = gss_display_name(&minor_status, client_name, &output_token, NULL); - gss_release_name(&minor_status, &client_name); + ctx->user = apr_pstrdup(r->pool, output_token.value); + + /* TODO: Make it a single call! */ + mag_get_name_attributes(r, conf, client_name, ctx); + mag_set_req_data(r, conf, ctx); + + gss_release_name(&minor_status, &client_name); if (GSS_ERROR(major_status)) { gss_log(APLOG_MARK, APLOG_ERR, 0, r, "%s", get_gss_error(r, major_status, minor_status, @@ -220,7 +228,6 @@ gss_authenticate(request_rec *r, gss_auth_config *conf, gss_conn_ctx ctx, } ctx->state = GSS_CTX_ESTABLISHED; - ctx->user = apr_pstrdup(r->pool, output_token.value); gss_release_buffer(&minor_status, &output_token); ret = OK; @@ -229,7 +236,7 @@ end: if (delegated_cred) gss_release_cred(&minor_status, &delegated_cred); - if (output_token.length) + if (output_token.length) gss_release_buffer(&minor_status, &output_token); if (client_name != GSS_C_NO_NAME) @@ -244,7 +251,7 @@ end: static int gss_authenticate_user(request_rec *r) { - gss_auth_config *conf = + gss_auth_config *conf = (gss_auth_config *) ap_get_module_config(r->per_dir_config, &auth_gssapi_module); const char *auth_line = NULL; @@ -255,7 +262,7 @@ gss_authenticate_user(request_rec *r) int ret; gss_log(APLOG_MARK, APLOG_DEBUG, 0, r, "Entering GSSAPI authentication"); - + /* get the type specified in Apache configuration */ type = ap_auth_type(r); if (type == NULL || strcmp(type, "Negotiate") != 0) { diff --git a/mod_auth_gssweb.c b/mod_auth_gssweb.c index c4ef117..491e755 100644 --- a/mod_auth_gssweb.c +++ b/mod_auth_gssweb.c @@ -37,7 +37,7 @@ * NOTE: Portions of the code in this file were derived from example * code distributed under the Apache 2.0 license: * http://www.apache.org/licenses/LICENSE-2.0 - * + * * This module implements the Apache server side of the GSSWeb * authentiction type which allows Moonshot to be used for * authentication in web applications. The module consists of two @@ -48,7 +48,7 @@ * response content. * * This module uses a simple protocol between the client and server - * to exchange GSS tokens and nonce information. The protocol is + * to exchange GSS tokens and nonce information. The protocol is * described in the protocol.txt file included with module source. */ @@ -68,11 +68,11 @@ static const command_rec gssweb_config_cmds[] = { { NULL } }; - + #define DEFAULT_ENCTYPE "application/x-www-form-urlencoded" #define GSS_MAX_TOKEN_SIZE 4096 //TBD -- check this value -/* gssweb_read_req() -- reads the request data into a buffer +/* gssweb_read_req() -- reads the request data into a buffer */ static int gssweb_read_req(request_rec *r, const char **rbuf, apr_off_t *size) { @@ -82,7 +82,7 @@ static int gssweb_read_req(request_rec *r, const char **rbuf, apr_off_t *size) gss_log(APLOG_MARK, APLOG_ERR, 0, r, "gssweb_get_post_data: Failed to set up client block"); return(rc); } - + if(ap_should_client_block(r)) { char argsbuffer[HUGE_STRING_LEN]; apr_off_t rsize, len_read, rpos = 0; @@ -121,7 +121,7 @@ static int gssweb_get_post_data(request_rec *r, unsigned int *nonce, gss_buffer_ input_token->value = NULL; gss_log(APLOG_MARK, APLOG_DEBUG, 0, r, "gssweb_get_post_data: Entering function"); - + if(r->method_number != M_POST) { gss_log(APLOG_MARK, APLOG_ERR, 0, r, "gssweb_get_post_data: Request data is not a POST, declining."); return DECLINED; @@ -137,8 +137,8 @@ static int gssweb_get_post_data(request_rec *r, unsigned int *nonce, gss_buffer_ gss_log(APLOG_MARK, APLOG_ERR, 0, r, "gssweb_get_post_data: Data read error, rc = %d", rc); return rc; } - - while(*data && (val = ap_getword(r->pool, &data, '&'))) { + + while(*data && (val = ap_getword(r->pool, &data, '&'))) { key = ap_getword(r->pool, &val, '='); ap_unescape_url((char*)key); ap_unescape_url((char*)val); @@ -168,7 +168,7 @@ static int gssweb_get_post_data(request_rec *r, unsigned int *nonce, gss_buffer_ } /* gssweb_authenticate_filter() -- Output filter for gssweb authentication. - * Wraps original response in JSON -- adding JSON to the beginning of the + * Wraps original response in JSON -- adding JSON to the beginning of the * response, escapes double quotes in the original response, and adds JSON * to the end of the response. Handles responses that involve more than * one filter call by maintaining state until an EOS bucket is received. @@ -195,9 +195,9 @@ static apr_status_t gssweb_authenticate_filter (ap_filter_t *f, gss_log(APLOG_MARK, APLOG_DEBUG, 0, f->r, "Entering GSSWeb filter"); - /* Get the context from the request. If the context is NULL or - * there is no outstanding request (no nonce set), just forward - * all of the buckets as-is, because the client isn't gssweb + /* Get the context from the request. If the context is NULL or + * there is no outstanding request (no nonce set), just forward + * all of the buckets as-is, because the client isn't gssweb */ if ((NULL == (conn_ctx = gss_retrieve_conn_ctx(r))) || (0 == conn_ctx->nonce)) { @@ -205,7 +205,7 @@ static apr_status_t gssweb_authenticate_filter (ap_filter_t *f, bkt_in != APR_BRIGADE_SENTINEL(brig_in); bkt_in = APR_BUCKET_NEXT(bkt_in)) { - if (NULL == (brig_out = apr_brigade_create(r->pool, c->bucket_alloc))) { + if (NULL == (brig_out = apr_brigade_create(r->pool, c->bucket_alloc))) { apr_brigade_cleanup(brig_in); return HTTP_INTERNAL_SERVER_ERROR; } @@ -253,11 +253,11 @@ static apr_status_t gssweb_authenticate_filter (ap_filter_t *f, } /* Send opening JSON block */ - snprintf((char *)data, len+1024, - "{\"gssweb\": {\n\"token\": \"%s\",\n\"nonce\": \"%d\"},\n\"application\": {\n\"data\": \"", + snprintf((char *)data, len+1024, + "{\"gssweb\": {\n\"token\": \"%s\",\n\"nonce\": \"%d\"},\n\"application\": {\n\"data\": \"", stoken, conn_ctx->nonce); gss_log(APLOG_MARK, APLOG_DEBUG, 0, r, "gssweb_authenticate_filter: Sending (%d bytes): %s", strlen(data), data); - + bkt_out = apr_bucket_heap_create(data, strlen(data), apr_bucket_free, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(brig_out, bkt_out); @@ -286,7 +286,7 @@ static apr_status_t gssweb_authenticate_filter (ap_filter_t *f, if(APR_BUCKET_IS_EOS(bkt_in)) { /* create and add the JSON closing block */ - + if (NULL == (data = apr_bucket_alloc(1024, c->bucket_alloc))) { gss_log(APLOG_MARK, APLOG_ERR, 0, r, "gssweb_authenticate_filter: Unable to allocate space for closing JSON block"); apr_brigade_cleanup(brig_in); @@ -303,11 +303,11 @@ static apr_status_t gssweb_authenticate_filter (ap_filter_t *f, /* Indicate that the next filter call is a new response */ conn_ctx->filter_stat = GSS_FILT_NEW; - + /* set EOS in the outbound brigade */ bkt_eos = apr_bucket_eos_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL (brig_out, bkt_eos); - + /* set application type to 'application/json' */ apr_table_set(r->headers_out, "Content-Type", "application/json"); @@ -345,7 +345,7 @@ static apr_status_t gssweb_authenticate_filter (ap_filter_t *f, buf[enc_len] = '\0'; gss_log(APLOG_MARK, APLOG_DEBUG, 0, r, "gssweb_authenticate_filter: Sending (%d bytes)", enc_len); APR_BRIGADE_INSERT_TAIL(brig_out, bkt_out); - + /* Send the output brigade */ if (OK != (ret = ap_pass_brigade(f->next, brig_out))) { apr_brigade_cleanup(brig_in); @@ -365,7 +365,7 @@ static apr_status_t gssweb_authenticate_filter (ap_filter_t *f, * gssweb_insert_error_filter hook. */ static void -gssweb_add_filter(request_rec *r) +gssweb_add_filter(request_rec *r) { gss_conn_ctx conn_ctx = NULL; @@ -385,7 +385,7 @@ gssweb_add_filter(request_rec *r) * output token back to the client. */ static int -gssweb_authenticate_user(request_rec *r) +gssweb_authenticate_user(request_rec *r) { const char *auth_line = NULL; char *auth_type = NULL; @@ -518,15 +518,20 @@ gssweb_authenticate_user(request_rec *r) conn_ctx->state = GSS_CTX_ESTABLISHED; r->user = apr_pstrdup(r->pool, conn_ctx->user); r->ap_auth_type = "GSSWeb"; + + /* TODO: Make it a single call! */ + mag_get_name_attributes(r, conf, client_name, conn_ctx); + mag_set_req_data(r, conf, conn_ctx); + ret = OK; end: if (delegated_cred) gss_release_cred(&minor_status, &delegated_cred); - + if ((release_output_token) && (output_token.length)) gss_release_buffer(&minor_status, &output_token); - + if (client_name != GSS_C_NO_NAME) gss_release_name(&minor_status, &client_name); -- 2.1.4