2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <unistd.h>
2N/A#include <sys/note.h>
2N/A#include "dh_gssapi.h"
2N/A
2N/A/*
2N/A * This module supports the GSS credential family of routines for
2N/A * Diffie-Hellman mechanism.
2N/A */
2N/A
2N/A/*
2N/A * __dh_gss_acquire_cred: Get the credential associated with principal
2N/A * with the requested expire time and usage. Return the credential with
2N/A * the optional set of supported mechs and actual time left on the credential.
2N/A *
2N/A * Note in Diffie-Hellman the supplied principal name must be that of
2N/A * the caller. There is no way to delegate credentials.
2N/A *
2N/A * Libgss alwas sets desired_mechs to GSS_C_NO_OID_SET and set the return
2N/A * set of mechs to NULL.
2N/A */
2N/A
2N/AOM_uint32
2N/A__dh_gss_acquire_cred(
2N/A OM_uint32 *minor, /* Mechanism status */
2N/A gss_name_t principal, /* Requested principal */
2N/A OM_uint32 expire_req, /* Requested Expire time */
2N/A gss_OID_set desired_mechs, /* Set of desired mechs */
2N/A gss_cred_usage_t usage, /* Usage: init, accept, both */
2N/A gss_cred_id_t *cred, /* The return credential */
2N/A gss_OID_set *mechs, /* The return set of mechs */
2N/A OM_uint32 *expire_rec /* The expire time received*/)
2N/A{
2N/A dh_principal netname;
2N/A dh_cred_id_t dh_cred;
2N/A
2N/A /* Need to write to these */
2N/A if (minor == 0 || cred == 0)
2N/A return (GSS_S_CALL_INACCESSIBLE_WRITE);
2N/A
2N/A /* Set sane outputs */
2N/A *minor = 0;
2N/A if (mechs)
2N/A *mechs = GSS_C_NO_OID_SET;
2N/A if (expire_rec)
2N/A *expire_rec = 0;
2N/A *cred = GSS_C_NO_CREDENTIAL;
2N/A
2N/A /*
2N/A * If not GSS_C_NO_OID_SET then the set must contain the
2N/A * Diffie-Hellman mechanism
2N/A */
2N/A if (desired_mechs != GSS_C_NO_OID_SET &&
2N/A !__OID_is_member(desired_mechs, &OID))
2N/A return (GSS_S_BAD_MECH);
2N/A
2N/A /* See if the callers secretkey is available */
2N/A if (!dh_keyopts.key_secretkey_is_set())
2N/A return (GSS_S_NO_CRED);
2N/A
2N/A /* Get the principal name of the caller */
2N/A if ((netname = dh_keyopts.get_principal()) == NULL)
2N/A return (GSS_S_NO_CRED);
2N/A
2N/A /*
2N/A * Diffie-Hellman requires the principal to be the principal
2N/A * of the caller
2N/A */
2N/A
2N/A if (principal &&
2N/A strncmp(netname, (char *)principal, MAXNETNAMELEN) != 0) {
2N/A Free(netname);
2N/A return (GSS_S_NO_CRED);
2N/A }
2N/A
2N/A /* Allocate the credential */
2N/A dh_cred = New(dh_cred_id_desc, 1);
2N/A if (dh_cred == NULL) {
2N/A Free(netname);
2N/A *minor = DH_NOMEM_FAILURE;
2N/A return (GSS_S_FAILURE);
2N/A }
2N/A
2N/A /* Set credential state */
2N/A dh_cred->uid = geteuid();
2N/A dh_cred->usage = usage;
2N/A dh_cred->principal = netname;
2N/A dh_cred->expire = expire_req ? time(0) + expire_req : GSS_C_INDEFINITE;
2N/A
2N/A /*
2N/A * If mechs set it to the set that contains the appropriate
2N/A * Diffie-Hellman mechanism
2N/A */
2N/A if (mechs && (*minor = __OID_to_OID_set(mechs, &OID))) {
2N/A Free(dh_cred);
2N/A Free(netname);
2N/A return (GSS_S_FAILURE);
2N/A }
2N/A
2N/A /* Register the credential */
2N/A if ((*minor = __dh_install_cred(dh_cred)) != DH_SUCCESS) {
2N/A Free(dh_cred);
2N/A Free(netname);
2N/A return (GSS_S_FAILURE);
2N/A }
2N/A
2N/A if (expire_rec)
2N/A *expire_rec = expire_req ? expire_req : GSS_C_INDEFINITE;
2N/A
2N/A /* Return the Diffie-Hellman credential through cred */
2N/A *cred = (gss_cred_id_t)dh_cred;
2N/A
2N/A return (GSS_S_COMPLETE);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * __dh_gss_add_cred is currently a no-op. All the work is done at the
2N/A * libgss layer. That layer will invoke the mechanism specific gss_acquire_cred
2N/A * routine. This entry point should never be called. The entry point for
2N/A * this routine is set to NULL in dhmech.c.
2N/A */
2N/A
2N/A/*
2N/A * OM_uint32
2N/A * __dh_gss_add_cred(void * ctx, OM_uint32 *minor, gss_cred_id_t cred_in,
2N/A * gss_name_t name, gss_OID mech, gss_cred_usage_t usage,
2N/A * OM_uint32 init_time_req, OM_uint32 accep_time_req,
2N/A * gss_cred_id_t *cred_out, gss_OID_set *mechs,
2N/A * OM_uint32 *init_time_rec, OM_uint32 *accep_time_rec)
2N/A * {
2N/A * return (GSS_S_UNAVAILABLE);
2N/A * }
2N/A */
2N/A
2N/A/*
2N/A * __dh_gss_inquire_cred: Return tracked state of the supplied credential.
2N/A */
2N/AOM_uint32
2N/A__dh_gss_inquire_cred(
2N/A OM_uint32 *minor, /* Mechanism status */
2N/A gss_cred_id_t cred, /* cred of interest */
2N/A gss_name_t *name, /* name of principal */
2N/A OM_uint32 *lifetime, /* return the time remainning */
2N/A gss_cred_usage_t *usage, /* usage: init, accept, both */
2N/A gss_OID_set *mechs /* Set containing mech_dh */)
2N/A{
2N/A /* cred is a Diffie-Hellman credential */
2N/A dh_cred_id_t crid = (dh_cred_id_t)cred;
2N/A OM_uint32 t = GSS_C_INDEFINITE;
2N/A
2N/A if (minor == 0)
2N/A return (GSS_S_CALL_INACCESSIBLE_WRITE);
2N/A
2N/A *minor = DH_SUCCESS;
2N/A
2N/A /* Default case */
2N/A if (cred == GSS_C_NO_CREDENTIAL) {
2N/A if (!(*dh_keyopts.key_secretkey_is_set)())
2N/A return (GSS_S_NO_CRED);
2N/A if (name)
2N/A *name = (gss_name_t)(*dh_keyopts.get_principal)();
2N/A if (lifetime)
2N/A *lifetime = GSS_C_INDEFINITE;
2N/A if (usage)
2N/A *usage = GSS_C_BOTH;
2N/A } else {
2N/A /* Validate creditial */
2N/A if ((*minor = __dh_validate_cred(crid)) != DH_SUCCESS)
2N/A return (GSS_S_DEFECTIVE_CREDENTIAL);
2N/A if (name)
2N/A *name = (gss_name_t)strdup(crid->principal);
2N/A if (lifetime) {
2N/A if (crid->expire == GSS_C_INDEFINITE)
2N/A *lifetime = GSS_C_INDEFINITE;
2N/A else {
2N/A time_t now = time(0);
2N/A t = crid->expire > now ? crid->expire-now : 0;
2N/A *lifetime = t;
2N/A }
2N/A }
2N/A if (usage)
2N/A *usage = crid->usage;
2N/A }
2N/A
2N/A if (name && *name == 0)
2N/A return (GSS_S_FAILURE);
2N/A
2N/A
2N/A if (mechs &&
2N/A (*minor = __OID_to_OID_set(mechs, &OID)) != DH_SUCCESS) {
2N/A free(name);
2N/A return (GSS_S_FAILURE);
2N/A }
2N/A
2N/A /* Check if the credential is still valid */
2N/A return (t ? GSS_S_COMPLETE : GSS_S_CREDENTIALS_EXPIRED);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * __dh_gss_inquire_cred_by_mech: Return the information associated with
2N/A * cred and mech. Since we're a backend, mech must be our mech.
2N/A *
2N/A * We verify that passed in mech is correct and use the above routine
2N/A * to do the work.
2N/A */
2N/AOM_uint32
2N/A__dh_gss_inquire_cred_by_mech(
2N/A OM_uint32 *minor, /* Mechanism status */
2N/A gss_cred_id_t cred, /* Cred to iquire about */
2N/A gss_OID mech, /* Along with the mechanism */
2N/A gss_name_t *name, /* where to return principal */
2N/A OM_uint32 *init_time, /* Init time left */
2N/A OM_uint32 *accept_time, /* Accept time left */
2N/A gss_cred_usage_t *usage /* cred usage */)
2N/A{
2N/A OM_uint32 lifetime;
2N/A OM_uint32 major;
2N/A gss_cred_usage_t use;
2N/A
2N/A /* This should never happen. It would indicate a libgss failure */
2N/A if (!__OID_equal(mech, &OID)) {
2N/A *minor = DH_BAD_CONTEXT;
2N/A return (GSS_S_FAILURE);
2N/A }
2N/A
2N/A /* Fetch cred info */
2N/A major = __dh_gss_inquire_cred(minor, cred, name,
2N/A &lifetime, &use, NULL);
2N/A
2N/A /* Return option values */
2N/A if (major == GSS_S_COMPLETE) {
2N/A /* set init_time if we can */
2N/A if (init_time)
2N/A *init_time = (use == GSS_C_BOTH ||
2N/A use == GSS_C_INITIATE) ? lifetime : 0;
2N/A /* Ditto for accept time */
2N/A if (accept_time)
2N/A *accept_time = (use == GSS_C_BOTH ||
2N/A use == GSS_C_ACCEPT) ? lifetime : 0;
2N/A if (usage)
2N/A *usage = use;
2N/A }
2N/A
2N/A return (major);
2N/A}
2N/A
2N/A/*
2N/A * __dh_gss_release_cred: Release the resources associated with cred.
2N/A */
2N/AOM_uint32
2N/A__dh_gss_release_cred(
2N/A OM_uint32 *minor, /* Mechanism status */
2N/A gss_cred_id_t *cred /* The cred to free */)
2N/A{
2N/A dh_cred_id_t dh_cred = (dh_cred_id_t)*cred;
2N/A
2N/A /* Check that we can read and write required parameters */
2N/A if (minor == 0 || cred == 0)
2N/A return (GSS_S_CALL_INACCESSIBLE_WRITE);
2N/A
2N/A /* Nothing to do */
2N/A if (*cred == GSS_C_NO_CREDENTIAL)
2N/A return (GSS_S_COMPLETE);
2N/A
2N/A /* Check if the credential is valid */
2N/A if ((*minor = __dh_validate_cred(dh_cred)) != DH_SUCCESS)
2N/A return (GSS_S_NO_CRED);
2N/A
2N/A /* Unregister the credential */
2N/A *minor = __dh_remove_cred(dh_cred);
2N/A
2N/A /* Free the principal and the cred itself */
2N/A Free(dh_cred->principal);
2N/A Free(dh_cred);
2N/A
2N/A /* Set cred to no credential */
2N/A *cred = GSS_C_NO_CREDENTIAL;
2N/A
2N/A return (GSS_S_COMPLETE);
2N/A}