Ejemplo n.º 1
0
uint32_t
sapgss_inquire_cred_by_mech(
    uint32_t *minor_status,
    gss_cred_id_t cred_handle,
    sapgss_OID mech_type,
    gss_name_t *name,
    uint32_t *initiator_lifetime,
    uint32_t *acceptor_lifetime,
    gss_cred_usage_t *cred_usage)
{
    gss_OID mech_type_loc;
    uint32_t major_status;
    int ret;

    ret = gss_OID_sap_to_loc(mech_type, &mech_type_loc);
    if (ret != 0) {
	*minor_status = ret;
	return GSS_S_FAILURE;
    }
    major_status = gss_inquire_cred_by_mech(minor_status, cred_handle,
					    mech_type_loc, name,
					    initiator_lifetime,
					    acceptor_lifetime, cred_usage);
    /* Comply with the gss_OID_sap_to_loc contract and free mech_type_loc */
    gss_OID_loc_release(&mech_type_loc);
    return major_status;
}
Ejemplo n.º 2
0
OM_uint32 _gss_spnego_inquire_cred_by_mech (
            OM_uint32 * minor_status,
            const gss_cred_id_t cred_handle,
            const gss_OID mech_type,
            gss_name_t * name,
            OM_uint32 * initiator_lifetime,
            OM_uint32 * acceptor_lifetime,
            gss_cred_usage_t * cred_usage
           )
{
    gssspnego_cred cred;
    spnego_name sname = NULL;
    OM_uint32 ret;

    if (cred_handle == GSS_C_NO_CREDENTIAL) {
	*minor_status = 0;
	return GSS_S_NO_CRED;
    }

    if (name) {
	sname = calloc(1, sizeof(*sname));
	if (sname == NULL) {
	    *minor_status = ENOMEM;
	    return GSS_S_FAILURE;
	}
    }

    cred = (gssspnego_cred)cred_handle;

    ret = gss_inquire_cred_by_mech(minor_status,
				   cred->negotiated_cred_id,
				   mech_type,
				   sname ? &sname->mech : NULL,
				   initiator_lifetime,
				   acceptor_lifetime,
				   cred_usage);

    if (ret) {
	if (sname)
	    free(sname);
	return ret;
    }
    if (name)
	*name = (gss_name_t)sname;

    return GSS_S_COMPLETE;
}
Ejemplo n.º 3
0
uint32_t gp_export_gssx_cred(uint32_t *min, struct gp_call_ctx *gpcall,
                             gss_cred_id_t *in, gssx_cred *out)
{
    uint32_t ret_maj;
    uint32_t ret_min;
    gss_name_t name = NULL;
    uint32_t lifetime;
    gss_cred_usage_t cred_usage;
    gss_OID_set mechanisms = NULL;
    uint32_t initiator_lifetime;
    uint32_t acceptor_lifetime;
    struct gssx_cred_element *el;
    int ret;
    int i, j;
    struct gp_creds_handle *handle = NULL;
    gss_buffer_desc token = GSS_C_EMPTY_BUFFER;

    ret_maj = gss_inquire_cred(&ret_min, *in,
                               &name, &lifetime, &cred_usage, &mechanisms);
    if (ret_maj) {
        goto done;
    }

    ret_maj = gp_conv_name_to_gssx(&ret_min, name, &out->desired_name);
    if (ret_maj) {
        goto done;
    }
    gss_release_name(&ret_min, &name);
    name = NULL;

    out->elements.elements_len = mechanisms->count;
    out->elements.elements_val = calloc(out->elements.elements_len,
                                        sizeof(gssx_cred_element));
    if (!out->elements.elements_val) {
        ret_maj = GSS_S_FAILURE;
        ret_min = ENOMEM;
        goto done;
    }

    for (i = 0, j = 0; i < mechanisms->count; i++, j++) {

        el = &out->elements.elements_val[j];

        ret_maj = gss_inquire_cred_by_mech(&ret_min, *in,
                                           &mechanisms->elements[i],
                                           &name,
                                           &initiator_lifetime,
                                           &acceptor_lifetime,
                                           &cred_usage);
        if (ret_maj) {
            gp_log_failure(&mechanisms->elements[i], ret_maj, ret_min);

            /* temporarily skip any offender */
            out->elements.elements_len--;
            j--;
            continue;
#if 0
            ret = EINVAL;
            goto done;
#endif
        }

        ret_maj = gp_conv_name_to_gssx(&ret_min, name, &el->MN);
        if (ret_maj) {
            goto done;
        }
        gss_release_name(&ret_min, &name);
        name = NULL;

        ret = gp_conv_oid_to_gssx(&mechanisms->elements[i], &el->mech);
        if (ret) {
            ret_maj = GSS_S_FAILURE;
            ret_min = ret;
            goto done;
        }
        el->cred_usage = gp_conv_gssx_to_cred_usage(cred_usage);

        el->initiator_time_rec = initiator_lifetime;
        el->acceptor_time_rec = acceptor_lifetime;
    }

    handle = gp_service_get_creds_handle(gpcall->service);
    if (!handle) {
        ret_maj = GSS_S_FAILURE;
        ret_min = EINVAL;
        goto done;
    }

    ret_maj = gss_export_cred(&ret_min, *in, &token);
    if (ret_maj) {
        goto done;
    }

    ret = gp_encrypt_buffer(handle->context, &handle->key,
                            token.length, token.value,
                            &out->cred_handle_reference);
    if (ret) {
        ret_maj = GSS_S_FAILURE;
        ret_min = ret;
        goto done;
    }
    out->needs_release = false;
    /* now we have serialized creds in the hands of the client.
     * we can safey free them here so that we can remain sateless and
     * not leak memory */
    gss_release_cred(&ret_min, in);

    ret_maj = GSS_S_COMPLETE;
    ret_min = 0;

done:
    *min = ret_min;
    gss_release_name(&ret_min, &name);
    gss_release_oid_set(&ret_min, &mechanisms);
    return ret_maj;
}
Ejemplo n.º 4
0
OM_uint32 gssi_inquire_cred_by_mech(OM_uint32 *minor_status,
                                    gss_cred_id_t cred_handle,
                                    gss_OID mech_type,
                                    gss_name_t *name,
                                    OM_uint32 *initiator_lifetime,
                                    OM_uint32 *acceptor_lifetime,
                                    gss_cred_usage_t *cred_usage)
{
    struct gpp_cred_handle *cred = NULL;
    struct gpp_name_handle *gpname = NULL;
    OM_uint32 maj, min;

    GSSI_TRACE();

    if (cred_handle == GSS_C_NO_CREDENTIAL) {
        maj = gppint_get_def_creds(&min, gpp_get_behavior(), NULL,
                                   GSS_C_INITIATE, &cred);
        if (maj != GSS_S_COMPLETE) {
            goto done;
        }
    } else {
        cred = (struct gpp_cred_handle *)cred_handle;
    }

    if (name) {
        gpname = calloc(1, sizeof(struct gpp_name_handle));
        if (!gpname) {
            min = ENOMEM;
            maj = GSS_S_FAILURE;
            goto done;
        }
    }

    if (cred->local) {
        maj = gss_inquire_cred_by_mech(&min, cred->local,
                                       gpp_special_mech(mech_type),
                                       gpname ? &gpname->local : NULL,
                                       initiator_lifetime, acceptor_lifetime,
                                       cred_usage);
    } else if (cred->remote) {
        maj = gpm_inquire_cred_by_mech(&min, cred->remote,
                                       gpp_unspecial_mech(mech_type),
                                       gpname ? &gpname->remote : NULL,
                                       initiator_lifetime, acceptor_lifetime,
                                       cred_usage);
    } else {
        min = 0;
        maj = GSS_S_FAILURE;
    }

done:
    *minor_status = gpp_map_error(min);
    if (cred_handle == GSS_C_NO_CREDENTIAL) {
        gssi_release_cred(&min, (gss_cred_id_t*)&cred);
    }
    if (name && maj == GSS_S_COMPLETE) {
        *name = (gss_name_t)gpname;
    } else {
        free(gpname);
    }
    return maj;
}
Ejemplo n.º 5
0
/* Privileged (called from accept_secure_ctx) */
OM_uint32
ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
{
	int i = 0;
	int equal = 0;
	gss_name_t new_name = GSS_C_NO_NAME;
	gss_buffer_desc ename = GSS_C_EMPTY_BUFFER;

	if (options.gss_store_rekey && client->used && ctx->client_creds) {
		if (client->mech->oid.length != ctx->oid->length ||
		    (memcmp(client->mech->oid.elements,
		     ctx->oid->elements, ctx->oid->length) !=0)) {
			debug("Rekeyed credentials have different mechanism");
			return GSS_S_COMPLETE;
		}

		if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor, 
		    ctx->client_creds, ctx->oid, &new_name, 
		    NULL, NULL, NULL))) {
			ssh_gssapi_error(ctx);
			return (ctx->major);
		}

		ctx->major = gss_compare_name(&ctx->minor, client->name, 
		    new_name, &equal);

		if (GSS_ERROR(ctx->major)) {
			ssh_gssapi_error(ctx);
			return (ctx->major);
		}
 
		if (!equal) {
			debug("Rekeyed credentials have different name");
			return GSS_S_COMPLETE;
		}

		debug("Marking rekeyed credentials for export");

		gss_release_name(&ctx->minor, &client->name);
		gss_release_cred(&ctx->minor, &client->creds);
		client->name = new_name;
		client->creds = ctx->client_creds;
        	ctx->client_creds = GSS_C_NO_CREDENTIAL;
		client->updated = 1;
		return GSS_S_COMPLETE;
	}

	client->mech = NULL;

	while (supported_mechs[i]->name != NULL) {
		if (supported_mechs[i]->oid.length == ctx->oid->length &&
		    (memcmp(supported_mechs[i]->oid.elements,
		    ctx->oid->elements, ctx->oid->length) == 0))
			client->mech = supported_mechs[i];
		i++;
	}

	if (client->mech == NULL)
		return GSS_S_FAILURE;

	if (ctx->client_creds &&
	    (ctx->major = gss_inquire_cred_by_mech(&ctx->minor,
	     ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) {
		ssh_gssapi_error(ctx);
		return (ctx->major);
	}

	if ((ctx->major = gss_display_name(&ctx->minor, ctx->client,
	    &client->displayname, NULL))) {
		ssh_gssapi_error(ctx);
		return (ctx->major);
	}

	if ((ctx->major = gss_export_name(&ctx->minor, ctx->client,
	    &ename))) {
		ssh_gssapi_error(ctx);
		return (ctx->major);
	}

	if ((ctx->major = ssh_gssapi_parse_ename(ctx,&ename,
	    &client->exportedname))) {
		return (ctx->major);
	}

	gss_release_buffer(&ctx->minor, &ename);

	/* We can't copy this structure, so we just move the pointer to it */
	client->creds = ctx->client_creds;
	ctx->client_creds = GSS_C_NO_CREDENTIAL;
	return (ctx->major);
}
Ejemplo n.º 6
0
/** @brief returns the OIDs of the mechs that have usable credentials
 */
static int ssh_gssapi_match(ssh_session session, gss_OID_set *valid_oids)
{
    OM_uint32 maj_stat, min_stat, lifetime;
    gss_OID_set actual_mechs;
    gss_buffer_desc namebuf;
    gss_name_t client_id = GSS_C_NO_NAME;
    gss_OID oid;
    unsigned int i;
    char *ptr;
    int ret;

    if (session->gssapi->client.client_deleg_creds == NULL) {
        if (session->opts.gss_client_identity != NULL) {
            namebuf.value = (void *)session->opts.gss_client_identity;
            namebuf.length = strlen(session->opts.gss_client_identity);

            maj_stat = gss_import_name(&min_stat, &namebuf,
                                       GSS_C_NT_USER_NAME, &client_id);
            if (GSS_ERROR(maj_stat)) {
                ret = SSH_ERROR;
                goto end;
            }
        }

        maj_stat = gss_acquire_cred(&min_stat, client_id, GSS_C_INDEFINITE,
                                    GSS_C_NO_OID_SET, GSS_C_INITIATE,
                                    &session->gssapi->client.creds,
                                    &actual_mechs, NULL);
        if (GSS_ERROR(maj_stat)) {
            ret = SSH_ERROR;
            goto end;
        }
    } else {
        session->gssapi->client.creds =
                                    session->gssapi->client.client_deleg_creds;

        maj_stat = gss_inquire_cred(&min_stat, session->gssapi->client.creds,
                                    &client_id, NULL, NULL, &actual_mechs);
        if (GSS_ERROR(maj_stat)) {
            ret = SSH_ERROR;
            goto end;
        }
    }

    gss_create_empty_oid_set(&min_stat, valid_oids);

    /* double check each single cred */
    for (i = 0; i < actual_mechs->count; i++) {
        /* check lifetime is not 0 or skip */
        lifetime = 0;
        oid = &actual_mechs->elements[i];
        maj_stat = gss_inquire_cred_by_mech(&min_stat,
                                            session->gssapi->client.creds,
                                            oid, NULL, &lifetime, NULL, NULL);
        if (maj_stat == GSS_S_COMPLETE && lifetime > 0) {
            gss_add_oid_set_member(&min_stat, oid, valid_oids);
            ptr = ssh_get_hexa(oid->elements, oid->length);
            SSH_LOG(SSH_LOG_DEBUG, "GSSAPI valid oid %d : %s\n", i, ptr);
            SAFE_FREE(ptr);
        }
    }

    ret = SSH_OK;

end:
    gss_release_name(&min_stat, &client_id);
    return ret;
}
Ejemplo n.º 7
0
static bool mag_auth_basic(request_rec *req,
                           struct mag_config *cfg,
                           gss_buffer_desc ba_user,
                           gss_buffer_desc ba_pwd,
                           gss_name_t *client,
                           gss_OID *mech_type,
                           gss_cred_id_t *delegated_cred,
                           uint32_t *vtime)
{
#ifdef HAVE_GSS_KRB5_CCACHE_NAME
    const char *user_ccache = NULL;
    const char *orig_ccache = NULL;
    long long unsigned int rndname;
    apr_status_t rs;
#endif
    gss_name_t user = GSS_C_NO_NAME;
    gss_cred_id_t user_cred = GSS_C_NO_CREDENTIAL;
    gss_ctx_id_t user_ctx = GSS_C_NO_CONTEXT;
    gss_name_t server = GSS_C_NO_NAME;
    gss_cred_id_t server_cred = GSS_C_NO_CREDENTIAL;
    gss_ctx_id_t server_ctx = GSS_C_NO_CONTEXT;
    gss_buffer_desc input = GSS_C_EMPTY_BUFFER;
    gss_buffer_desc output = GSS_C_EMPTY_BUFFER;
    gss_OID_set allowed_mechs;
    gss_OID_set filtered_mechs;
    gss_OID_set actual_mechs = GSS_C_NO_OID_SET;
    uint32_t init_flags = 0;
    uint32_t maj, min;
    int present = 0;
    bool ret = false;

    maj = gss_import_name(&min, &ba_user, GSS_C_NT_USER_NAME, &user);
    if (GSS_ERROR(maj)) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
                      "In Basic Auth, %s",
                      mag_error(req, "gss_import_name() failed",
                                maj, min));
        goto done;
    }

    if (cfg->basic_mechs) {
        allowed_mechs = cfg->basic_mechs;
    } else if (cfg->allowed_mechs) {
        allowed_mechs = cfg->allowed_mechs;
    } else {
        struct mag_server_config *scfg;
        /* Try to fetch the default set if not explicitly configured,
         * We need to do this because gss_acquire_cred_with_password()
         * is currently limited to acquire creds for a single "default"
         * mechanism if no desired mechanisms are passed in. This causes
         * authentication to fail for secondary mechanisms as no user
         * credentials are generated for those. */
        scfg = ap_get_module_config(req->server->module_config,
                                    &auth_gssapi_module);
        /* In the worst case scenario default_mechs equals to GSS_C_NO_OID_SET.
         * This generally causes only the krb5 mechanism to be tried due
         * to implementation constraints, but may change in future. */
        allowed_mechs = scfg->default_mechs;
    }

    /* Remove Spnego if present, or we'd repeat failed authentiations
     * multiple times, one within Spnego and then again with an explicit
     * mechanism. We would normally just force Spnego and use
     * gss_set_neg_mechs, but due to the way we source the server name
     * and the fact MIT up to 1.14 at least does no handle union names,
     * we can't provide spnego with a server name that can be used by
     * multiple mechanisms, causing any but the first mechanism to fail.
     * Also remove unwanted krb mechs, or AS requests will be repeated
     * multiple times uselessly.
     */
    filtered_mechs = mag_filter_unwanted_mechs(allowed_mechs);
    if (filtered_mechs == allowed_mechs) {
        /* in case filtered_mechs was not allocated here don't free it */
        filtered_mechs = GSS_C_NO_OID_SET;
    } else if (filtered_mechs == GSS_C_NO_OID_SET) {
        ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, req, "Fatal "
                      "failure while filtering mechs, aborting");
        goto done;
    } else {
        /* use the filtered list */
        allowed_mechs = filtered_mechs;
    }

#ifdef HAVE_GSS_KRB5_CCACHE_NAME
    /* If we are using the krb5 mechanism make sure to set a per thread
     * memory ccache so that there can't be interferences between threads.
     * Also make sure we have  new cache so no cached results end up being
     * used. Some implementations of gss_acquire_cred_with_password() do
     * not reacquire creds if cached ones are around, failing to check
     * again for the password. */
    maj = gss_test_oid_set_member(&min, discard_const(gss_mech_krb5),
                                  allowed_mechs, &present);
    if (GSS_ERROR(maj)) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
                      "In Basic Auth, %s",
                      mag_error(req, "gss_test_oid_set_member() failed",
                                maj, min));
        goto done;
    }
    if (present) {
        rs = apr_generate_random_bytes((unsigned char *)(&rndname),
                                       sizeof(long long unsigned int));
        if (rs != APR_SUCCESS) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
                          "Failed to generate random ccache name");
            goto done;
        }
        user_ccache = apr_psprintf(req->pool, "MEMORY:user_%qu", rndname);
        maj = gss_krb5_ccache_name(&min, user_ccache, &orig_ccache);
        if (GSS_ERROR(maj)) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
                          "In Basic Auth, %s",
                          mag_error(req, "gss_krb5_ccache_name() "
                                    "failed", maj, min));
            goto done;
        }
    }
#endif

    maj = gss_acquire_cred_with_password(&min, user, &ba_pwd,
                                         GSS_C_INDEFINITE,
                                         allowed_mechs,
                                         GSS_C_INITIATE,
                                         &user_cred, &actual_mechs, NULL);
    if (GSS_ERROR(maj)) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
                      "In Basic Auth, %s",
                      mag_error(req, "gss_acquire_cred_with_password() "
                                "failed", maj, min));
        goto done;
    }

    /* must acquire creds based on the actual mechs we want to try */
    if (!mag_acquire_creds(req, cfg, actual_mechs,
                           GSS_C_ACCEPT, &server_cred, NULL)) {
        goto done;
    }

#ifdef HAVE_CRED_STORE
    if (cfg->deleg_ccache_dir) {
        /* delegate ourselves credentials so we store them as requested */
        init_flags |= GSS_C_DELEG_FLAG;
    }
#endif

    for (int i = 0; i < actual_mechs->count; i++) {

        /* free these if looping */
        gss_release_buffer(&min, &output);
        gss_release_buffer(&min, &input);
        gss_release_name(&min, &server);

        maj = gss_inquire_cred_by_mech(&min, server_cred,
                                       &actual_mechs->elements[i],
                                       &server, NULL, NULL, NULL);
        if (GSS_ERROR(maj)) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
                          "%s", mag_error(req, "gss_inquired_cred_by_mech() "
                                          "failed", maj, min));
            continue;
        }

        do {
            /* output and input are inverted here, this is intentional */
            maj = gss_init_sec_context(&min, user_cred, &user_ctx, server,
                                       &actual_mechs->elements[i], init_flags,
                                       300, GSS_C_NO_CHANNEL_BINDINGS, &output,
                                       NULL, &input, NULL, NULL);
            if (GSS_ERROR(maj)) {
                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
                              "%s", mag_error(req, "gss_init_sec_context() "
                                              "failed", maj, min));
                break;
            }
            gss_release_buffer(&min, &output);
            maj = gss_accept_sec_context(&min, &server_ctx, server_cred,
                                         &input, GSS_C_NO_CHANNEL_BINDINGS,
                                         client, mech_type, &output, NULL,
                                         vtime, delegated_cred);
            if (GSS_ERROR(maj)) {
                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
                              "%s", mag_error(req, "gss_accept_sec_context()"
                                              " failed", maj, min));
                break;
            }
            gss_release_buffer(&min, &input);
        } while (maj == GSS_S_CONTINUE_NEEDED);

        if (maj == GSS_S_COMPLETE) {
            ret = true;
            break;
        }
    }

done:
    gss_release_buffer(&min, &output);
    gss_release_buffer(&min, &input);
    gss_release_name(&min, &server);
    gss_delete_sec_context(&min, &server_ctx, GSS_C_NO_BUFFER);
    gss_release_cred(&min, &server_cred);
    gss_release_name(&min, &user);
    gss_release_cred(&min, &user_cred);
    gss_delete_sec_context(&min, &user_ctx, GSS_C_NO_BUFFER);
    gss_release_oid_set(&min, &actual_mechs);
    gss_release_oid_set(&min, &filtered_mechs);
#ifdef HAVE_GSS_KRB5_CCACHE_NAME
    if (user_ccache != NULL) {
        maj = gss_krb5_ccache_name(&min, orig_ccache, NULL);
        if (maj != GSS_S_COMPLETE) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
                          "Failed to restore per-thread ccache, %s",
                          mag_error(req, "gss_krb5_ccache_name() "
                                    "failed", maj, min));
        }
    }
#endif
    return ret;
}