static bool mag_acquire_creds(request_rec *req,
                              struct mag_config *cfg,
                              gss_OID_set desired_mechs,
                              gss_cred_usage_t cred_usage,
                              gss_cred_id_t *creds,
                              gss_OID_set *actual_mechs)
{
    uint32_t maj, min;
#ifdef HAVE_CRED_STORE
    gss_const_key_value_set_t store = cfg->cred_store;

    maj = gss_acquire_cred_from(&min, GSS_C_NO_NAME, GSS_C_INDEFINITE,
                                desired_mechs, cred_usage, store, creds,
                                actual_mechs, NULL);
#else
    maj = gss_acquire_cred(&min, GSS_C_NO_NAME, GSS_C_INDEFINITE,
                           desired_mechs, cred_usage, creds,
                           actual_mechs, NULL);
#endif

    if (GSS_ERROR(maj)) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "%s",
                      mag_error(req, "gss_acquire_cred[_from]() "
                                "failed to get server creds",
                                maj, min));
        return false;
    }

    return true;
}
Exemple #2
0
static gss_cred_id_t
acquire_cred_service(const char *service,
		     gss_OID nametype,
		     gss_OID_set oidset,
		     gss_cred_usage_t usage,
		     gss_const_key_value_set_t cred_store)
{
    OM_uint32 major_status, minor_status;
    gss_cred_id_t cred_handle;
    OM_uint32 time_rec;
    gss_buffer_desc name_buffer;
    gss_name_t name = GSS_C_NO_NAME;

    if (service) {
	name_buffer.value = rk_UNCONST(service);
	name_buffer.length = strlen(service);

	major_status = gss_import_name(&minor_status,
				       &name_buffer,
				       nametype,
				       &name);
	if (GSS_ERROR(major_status))
	    errx(1, "import_name failed");
    }

    major_status = gss_acquire_cred_from(&minor_status,
					 name,
					 0,
					 oidset,
					 usage,
					 cred_store,
					 &cred_handle,
					 NULL,
					 &time_rec);
    if (GSS_ERROR(major_status)) {
	warnx("acquire_cred failed: %s",
	     gssapi_err(major_status, minor_status, GSS_C_NO_OID));
    } else {
	print_time(time_rec);
	gss_release_cred(&minor_status, &cred_handle);
    }

    if (name != GSS_C_NO_NAME)
	gss_release_name(&minor_status, &name);

    if (GSS_ERROR(major_status))
	exit(1);

    return cred_handle;
}
static int mag_auth(request_rec *req)
{
    const char *type;
    struct mag_config *cfg;
    const char *auth_header;
    char *auth_header_type;
    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;
    gss_name_t client = GSS_C_NO_NAME;
    gss_cred_id_t acquired_cred = GSS_C_NO_CREDENTIAL;
    gss_cred_id_t delegated_cred = GSS_C_NO_CREDENTIAL;
    uint32_t flags;
    uint32_t vtime;
    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;
    }

    /* ignore auth for subrequests */
    if (!ap_is_initial_req(req)) {
        return OK;
    }

    cfg = ap_get_module_config(req->per_dir_config, &auth_gssapi_module);

    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) {
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, req,
                          "Failed to retrieve connection context!");
            goto done;
        }
    }

    /* if available, session always supersedes connection bound data */
    mag_check_session(req, cfg, &mc);

    if (mc) {
        /* register the context in the memory pool, so it can be freed
         * when the connection/request is terminated */
        apr_pool_userdata_set(mc, "mag_conn_ptr",
                              mag_conn_destroy, mc->parent);

        if (mc->established) {
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, req,
                          "Already established context 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");
    if (!auth_header) goto done;

    auth_header_type = ap_getword_white(req->pool, &auth_header);
    if (!auth_header_type) goto done;

    if (strcasecmp(auth_header_type, "Negotiate") != 0) goto done;

    auth_header_value = ap_getword_white(req->pool, &auth_header);
    if (!auth_header_value) goto done;
    input.length = apr_base64_decode_len(auth_header_value) + 1;
    input.value = apr_pcalloc(req->pool, input.length);
    if (!input.value) goto done;
    input.length = apr_base64_decode(input.value, auth_header_value);

#ifdef HAVE_GSS_ACQUIRE_CRED_FROM
    if (cfg->use_s4u2proxy) {
        maj = gss_acquire_cred_from(&min, GSS_C_NO_NAME, 0,
                                    GSS_C_NO_OID_SET, GSS_C_BOTH,
                                    cfg->cred_store, &acquired_cred,
                                    NULL, NULL);
        if (GSS_ERROR(maj)) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, "%s",
                          mag_error(req, "gss_acquire_cred_from() failed",
                                    maj, min));
            goto done;
        }
    }
#endif

    maj = gss_accept_sec_context(&min, pctx, acquired_cred,
                                 &input, GSS_C_NO_CHANNEL_BINDINGS,
                                 &client, &mech_type, &output, &flags, &vtime,
                                 &delegated_cred);
    if (GSS_ERROR(maj)) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req, "%s",
                      mag_error(req, "gss_accept_sec_context() failed",
                                maj, min));
        goto done;
    }

    if (maj == GSS_S_CONTINUE_NEEDED) {
        if (!mc) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, req,
                          "Mechanism needs continuation but neither "
                          "GssapiConnectionBound nor "
                          "GssapiUseSessions are available");
            gss_delete_sec_context(&min, pctx, GSS_C_NO_BUFFER);
            gss_release_buffer(&min, &output);
            output.length = 0;
        }
        /* auth not complete send token and wait next packet */
        goto done;
    }

    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, "%s",
                      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);

#ifdef HAVE_GSS_STORE_CRED_INTO
    if (cfg->deleg_ccache_dir && delegated_cred != GSS_C_NO_CREDENTIAL) {
        char *ccachefile = NULL;

        mag_store_deleg_creds(req, cfg->deleg_ccache_dir, clientname,
                              delegated_cred, &ccachefile);

        if (ccachefile) {
            apr_table_set(req->subprocess_env, "KRB5CCNAME", ccachefile);
        }
    }
#endif

    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, "%s",
                          mag_error(req, "gss_localname() failed", maj, min));
            goto done;
        }
        req->user = apr_pstrndup(req->pool, lname.value, lname.length);
    } 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;
        if (vtime == GSS_C_INDEFINITE || vtime < MIN_SESS_EXP_TIME) {
            vtime = MIN_SESS_EXP_TIME;
        }
        mc->expiration = time(NULL) + vtime;
        mag_attempt_session(req, cfg, mc);
    }

    ret = OK;

done:
    if (ret == HTTP_UNAUTHORIZED) {
        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_release_buffer(&min, &lname);
    return ret;
}
Exemple #4
0
static int
create_krb5_cred(krb5_context ctx, char *realm, char *user, char *password,
                 char *ktname, krb5_ccache *ccache, gss_cred_id_t *gsscred,
                 char **errmsg) {
    int rc = 0, len = 0;
    unsigned int minor_stat = 0, major_stat = 0;
    const char *errmsg_tmp = NULL;
    const char *cctype = NULL;
    char *cname = NULL;
    krb5_ccache defcc = NULL;
    krb5_creds creds;
    krb5_principal princ = NULL;
    krb5_keytab keytab = NULL;
    gss_key_value_element_desc elems[2];
    gss_key_value_set_desc store;
    gss_name_t sname = NULL;
    gss_buffer_desc pr_name;

    pr_name.value = NULL;
    pr_name.length = 0;

    store.count = 0;
    store.elements = elems;

    if (user == NULL || realm == NULL) return 1;
    len = strlen(realm);

    if (len == 0 || strlen(user) == 0) return 0;

    DEBUG("create_krb5_cred (ctx:%p, realm:%s, user:%s, password:%s, ktname: %s,"
        " ccache:%p, gsscred:%p)", ctx, realm, user, "****", ktname, ccache, gsscred);

    rc = krb5_cc_default(ctx, &defcc);
    if (rc != 0) goto end;

    cctype = krb5_cc_get_type(ctx, defcc);

    rc = krb5_cc_new_unique(ctx, cctype, NULL, ccache);
    if (rc != 0) goto end;

    rc = krb5_build_principal(ctx, &princ, len, realm, user, NULL);
    if (rc != 0) goto end;

    rc = krb5_cc_initialize(ctx, *ccache, princ);
    if (rc != 0) goto end;

    if (password != NULL && strlen(password) > 0) {
        rc = krb5_get_init_creds_password(ctx, &creds, princ, password,
                                          0, NULL, 0, NULL, NULL);
        if (rc != 0) goto end;

        rc = krb5_cc_store_cred(ctx, *ccache, &creds);
        if (rc != 0) goto end;

        rc = krb5_cc_get_full_name(ctx, *ccache, &cname);
        if (rc != 0) goto end;
        
        store.elements[store.count].key = "ccache";
        store.elements[store.count].value = cname;
        store.count++;
    }

    if (ktname != NULL && strlen(ktname) > 0) {
        rc = krb5_kt_resolve(ctx, ktname, &keytab);
        if (rc != 0) goto end;

        rc = krb5_get_init_creds_keytab(ctx, &creds, princ, keytab, 0, NULL, NULL);
        if (rc != 0) goto end;
        
        rc = krb5_cc_store_cred(ctx, *ccache, &creds);
        if (rc != 0) goto end;

        rc = krb5_cc_get_full_name(ctx, *ccache, &cname);
        if (rc != 0) goto end;

        store.elements[store.count].key = "client_keytab";
        store.elements[store.count].value = ktname;
        store.count++;

        store.elements[store.count].key = "ccache";
        store.elements[store.count].value = cname;
        store.count++;

        rc = krb5_unparse_name(ctx, princ, (char**)&pr_name.value);
        if (rc != 0) goto end;
        pr_name.length = strlen(pr_name.value);

        major_stat = gss_import_name(&minor_stat, &pr_name,
                                     GSS_KRB5_NT_PRINCIPAL_NAME, &sname);
        if (major_stat != 0) goto end;
    }

    // Does not work with GSS-SPENGO.
    //major_stat = gss_krb5_import_cred(&minor_stat, *ccache, princ, NULL, gsscred);
    major_stat = gss_acquire_cred_from(&minor_stat, sname, 0, GSS_C_NO_OID_SET,
                                       GSS_C_INITIATE, &store, gsscred,
                                       NULL, NULL);

end:
    if (keytab != NULL) krb5_kt_close(ctx, keytab);
    if (princ != NULL) krb5_free_principal(ctx, princ);
    if (defcc != NULL) krb5_cc_close(ctx, defcc);
    if (cname != NULL) free(cname);
    if (pr_name.value != NULL) krb5_free_unparsed_name(ctx, pr_name.value);
    if (sname != NULL) {
        major_stat = gss_release_name(&minor_stat, &sname);
    }

    if (rc != 0) {
        /* Create error message with the error code. */
        errmsg_tmp = krb5_get_error_message(ctx, rc);
        if (errmsg != NULL && errmsg_tmp != NULL) {
            len = strlen(errmsg_tmp) + 26;
            *errmsg = (char *)malloc(len);
            if (*errmsg == NULL) {
                krb5_free_error_message(ctx, errmsg_tmp);
                return -1;
            }
            snprintf(*errmsg, len,"%s. (KRB5_ERROR 0x%08x)", errmsg_tmp, rc);
        }
        krb5_free_error_message(ctx, errmsg_tmp);
    }
    if (major_stat != 0) return major_stat;
    return rc;
}
Exemple #5
0
int
main(int argc, char *argv[])
{
    OM_uint32 minor, major;
    gss_key_value_set_desc store;
    gss_buffer_desc buf;
    gss_name_t service = GSS_C_NO_NAME;
    gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
    int i, e;

    if (argc < 2 || ((argc - 3) % 2)) {
        usage(argv[0]);
        exit(1);
    }

    store.count = (argc - 3) / 2;
    store.elements = calloc(store.count,
                            sizeof(struct gss_key_value_element_struct));
    if (!store.elements) {
        fprintf(stderr, "OOM\n");
        exit(1);
    }

    if (argc > 2) {
        if (strcmp(argv[2], "--cred_store") != 0) {
            usage(argv[0]);
            exit(1);
        }

        for (i = 3, e = 0; i < argc; i += 2, e++) {
            store.elements[e].key = argv[i];
            store.elements[e].value = argv[i + 1];
            continue;
        }
    }

    /* First acquire default creds and try to store them in the cred store. */

    major = gss_acquire_cred(&minor, GSS_C_NO_NAME, 0, GSS_C_NO_OID_SET,
                             GSS_C_INITIATE, &cred, NULL, NULL);
    if (major) {
        print_status("gss_acquire_cred(default user creds) failed",
                     major, minor);
        goto out;
    }

    major = gss_store_cred_into(&minor, cred, GSS_C_INITIATE,
                                GSS_C_NO_OID, 1, 0, &store, NULL, NULL);
    if (major) {
        print_status("gss_store_cred_in_store(default user creds) failed",
                     major, minor);
        goto out;
    }

    gss_release_cred(&minor, &cred);

    /* Then try to acquire creds from store. */

    buf.value = argv[1];
    buf.length = strlen(argv[1]);

    major = gss_import_name(&minor, &buf,
                            (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME,
                            &service);
    if (major) {
        print_status("gss_import_name(principal) failed", major, minor);
        goto out;
    }

    major = gss_acquire_cred_from(&minor, service,
                                  0, GSS_C_NO_OID_SET, GSS_C_BOTH,
                                  &store, &cred, NULL, NULL);
    if (major) {
        print_status("gss_acquire_cred_from_store(principal) failed",
                     major, minor);
        goto out;
    }

    fprintf(stdout, "Cred Store Success\n");

    major = 0;

out:
    gss_release_name(&minor, &service);
    gss_release_cred(&minor, &cred);
    free(store.elements);
    return major;
}