inline static void check_base64 (char *out, const size_t out_sz, const char *in, const size_t in_len, const base64_charset enc) { force_assert(out_sz == li_to_base64_no_padding(out, out_sz, (const unsigned char *)in, in_len, enc)); buffer_reset(check); force_assert(NULL != buffer_append_base64_decode(check, out, out_sz, enc)); force_assert(buffer_is_equal_string(check, in, in_len)); }
static handler_t mod_authn_gssapi_check_spnego(server *srv, connection *con, plugin_data *p, const http_auth_require_t *require, const char *realm_str) { OM_uint32 st_major, st_minor, acc_flags; gss_buffer_desc token_s = GSS_C_EMPTY_BUFFER; gss_buffer_desc token_in = GSS_C_EMPTY_BUFFER; gss_buffer_desc token_out = GSS_C_EMPTY_BUFFER; gss_cred_id_t server_cred = GSS_C_NO_CREDENTIAL; gss_cred_id_t client_cred = GSS_C_NO_CREDENTIAL; gss_ctx_id_t context = GSS_C_NO_CONTEXT; gss_name_t server_name = GSS_C_NO_NAME; gss_name_t client_name = GSS_C_NO_NAME; buffer *sprinc; int ret = 0; buffer *t_in = buffer_init(); if (!buffer_append_base64_decode(t_in, realm_str, strlen(realm_str), BASE64_STANDARD)) { log_error_write(srv, __FILE__, __LINE__, "ss", "decoding GSSAPI authentication header failed", realm_str); buffer_free(t_in); return mod_authn_gssapi_send_400_bad_request(srv, con); } mod_authn_gssapi_patch_connection(srv, con, p); { /* ??? Should code = krb5_kt_resolve(kcontext, p->conf.auth_gssapi_keytab->ptr, &keytab); * be used, instead of putenv() of KRB5_KTNAME=...? See mod_authn_gssapi_basic() */ /* ??? Should KRB5_KTNAME go into con->environment instead ??? */ /* ??? Should KRB5_KTNAME be added to mod_authn_gssapi_basic(), too? */ buffer ktname; memset(&ktname, 0, sizeof(ktname)); buffer_copy_string(&ktname, "KRB5_KTNAME="); buffer_append_string_buffer(&ktname, p->conf.auth_gssapi_keytab); putenv(ktname.ptr); /* ktname.ptr becomes part of the environment, do not free */ } sprinc = buffer_init_buffer(p->conf.auth_gssapi_principal); if (strchr(sprinc->ptr, '/') == NULL) { /*(copy HTTP Host, omitting port if port is present)*/ /* ??? Should con->server_name be used if http_host not present? * ??? What if con->server_name is not set? * ??? Will this work below if IPv6 provided in Host? probably not */ if (!buffer_is_empty(con->request.http_host)) { buffer_append_string(sprinc, "/"); buffer_append_string_len(sprinc, con->request.http_host->ptr, strcspn(con->request.http_host->ptr, ":")); } } if (strchr(sprinc->ptr, '@') == NULL) { buffer_append_string(sprinc, "@"); buffer_append_string_buffer(sprinc, require->realm); } /*#define GSS_C_NT_USER_NAME gss_nt_user_name*/ /*#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name*/ #define GSS_KRB5_NT_PRINCIPAL_NAME gss_nt_krb5_name token_s.value = sprinc->ptr; token_s.length = buffer_string_length(sprinc); st_major = gss_import_name(&st_minor, &token_s, (gss_OID) GSS_KRB5_NT_PRINCIPAL_NAME, &server_name); if (GSS_ERROR(st_major)) { mod_authn_gssapi_log_gss_error(srv, __FILE__, __LINE__, "gss_import_name", NULL, st_major, st_minor); goto end; } memset(&token_s, 0, sizeof(token_s)); st_major = gss_display_name(&st_minor, server_name, &token_s, NULL); if (GSS_ERROR(st_major)) { mod_authn_gssapi_log_gss_error(srv, __FILE__, __LINE__, "gss_display_name", NULL, st_major, st_minor); goto end; } /* acquire server's own credentials */ st_major = gss_acquire_cred(&st_minor, server_name, GSS_C_INDEFINITE, GSS_C_NO_OID_SET, GSS_C_ACCEPT, &server_cred, NULL, NULL); if (GSS_ERROR(st_major)) { mod_authn_gssapi_log_gss_error(srv, __FILE__, __LINE__, "gss_acquire_cred", sprinc->ptr, st_major, st_minor); goto end; } /* accept the user's context */ token_in.length = buffer_string_length(t_in); token_in.value = t_in->ptr; st_major = gss_accept_sec_context(&st_minor, &context, server_cred, &token_in, GSS_C_NO_CHANNEL_BINDINGS, &client_name, NULL, &token_out, &acc_flags, NULL, &client_cred); if (GSS_ERROR(st_major)) { mod_authn_gssapi_log_gss_error(srv, __FILE__, __LINE__, "gss_accept_sec_context", NULL, st_major, st_minor); goto end; } /* fetch the username */ st_major = gss_display_name(&st_minor, client_name, &token_out, NULL); if (GSS_ERROR(st_major)) { mod_authn_gssapi_log_gss_error(srv, __FILE__, __LINE__, "gss_display_name", NULL, st_major, st_minor); goto end; } if (!(acc_flags & GSS_C_CONF_FLAG)) { log_error_write(srv, __FILE__, __LINE__, "ss", "No confidentiality for user:"******"ss", "Unable to delegate credentials for user:"******"GSSAPI")); end: buffer_free(t_in); buffer_free(sprinc); if (context != GSS_C_NO_CONTEXT) gss_delete_sec_context(&st_minor, &context, GSS_C_NO_BUFFER); if (client_cred != GSS_C_NO_CREDENTIAL) gss_release_cred(&st_minor, &client_cred); if (server_cred != GSS_C_NO_CREDENTIAL) gss_release_cred(&st_minor, &server_cred); if (client_name != GSS_C_NO_NAME) gss_release_name(&st_minor, &client_name); if (server_name != GSS_C_NO_NAME) gss_release_name(&st_minor, &server_name); if (token_s.length) gss_release_buffer(&st_minor, &token_s); /* if (token_in.length) * gss_release_buffer(&st_minor, &token_in); */ if (token_out.length) gss_release_buffer(&st_minor, &token_out); return ret ? HANDLER_GO_ON : mod_authn_gssapi_send_401_unauthorized_negotiate(srv, con); }