Ejemplo n.º 1
0
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));
}
Ejemplo n.º 2
0
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);
}