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 "dh_gssapi.h"
2N/A#include <pwd.h>
2N/A#include <string.h>
2N/A#include <stdlib.h>
2N/A#include <unistd.h>
2N/A#include <alloca.h>
2N/A#include <sys/types.h>
2N/A#include <sys/param.h>
2N/A#include <sys/note.h>
2N/A#include <thread.h>
2N/A
2N/Aextern int
2N/Aget_der_length(unsigned char **, unsigned int, unsigned int *);
2N/A
2N/Aextern unsigned int
2N/Ader_length_size(unsigned int);
2N/A
2N/Aextern int
2N/Aput_der_length(unsigned int, unsigned char **, unsigned int);
2N/A
2N/A/* Diffie-Hellman ONC RPC netname name type */
2N/Astatic gss_OID_desc __DH_GSS_C_NT_NETNAME_desc =
2N/A { 9, "\053\006\004\001\052\002\032\001\001" };
2N/A
2N/Aconst gss_OID_desc * const __DH_GSS_C_NT_NETNAME = &__DH_GSS_C_NT_NETNAME_desc;
2N/A
2N/A#define OID_MAX_NAME_ENTRIES 32
2N/A
2N/A/*
2N/A * __dh_gss_compare_name: Diffie-Hellman machanism support for
2N/A * gss_compare_name. Given two gss_name_ts that are presumed to
2N/A * be rpc netnames set the *equal parameter to true if they are
2N/A * the same, else set it to false.
2N/A */
2N/A
2N/AOM_uint32
2N/A__dh_gss_compare_name(
2N/A OM_uint32 *minor, /* Mechanism status */
2N/A gss_name_t name1, /* First name to compare */
2N/A gss_name_t name2, /* Second name to compare */
2N/A int *equal /* The result */)
2N/A{
2N/A
2N/A if (minor == 0 || equal == 0)
2N/A return (GSS_S_CALL_INACCESSIBLE_WRITE);
2N/A
2N/A *minor = DH_SUCCESS;
2N/A
2N/A if (name1 == 0 || name2 == 0) {
2N/A *minor = DH_BADARG_FAILURE;
2N/A return (GSS_S_BAD_NAME | GSS_S_CALL_INACCESSIBLE_READ);
2N/A }
2N/A
2N/A *equal = (strcmp((char *)name1, (char *)name2) == 0);
2N/A
2N/A return (GSS_S_COMPLETE);
2N/A}
2N/A
2N/A/*
2N/A * __dh_gss_display_name: Supports gss_display_name for Diffie-Hellman
2N/A * mechanism. This takes a gss internal name and converts it to
2N/A * a counted string suitable for display.
2N/A */
2N/AOM_uint32
2N/A__dh_gss_display_name(
2N/A OM_uint32* minor, /* Mechanism status */
2N/A gss_name_t name, /* Diffie-Hellman internal name */
2N/A gss_buffer_t output, /* Were the printable name goes */
2N/A gss_OID *name_type /* Name type of the internal name */)
2N/A{
2N/A if (minor == 0 || output == 0)
2N/A return (GSS_S_CALL_INACCESSIBLE_WRITE);
2N/A
2N/A if (name == 0)
2N/A return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
2N/A
2N/A *minor = DH_SUCCESS;
2N/A
2N/A output->length = 0;
2N/A output->value = (void *)strdup((char *)name);
2N/A if (output->value == NULL) {
2N/A *minor = DH_NOMEM_FAILURE;
2N/A return (GSS_S_FAILURE);
2N/A }
2N/A output->length = strlen((char *)name) + 1;
2N/A
2N/A/*
2N/A * Note: we no longer copy the name type OID. The current draft of
2N/A * the standard specifies:
2N/A *
2N/A * "The returned gss_OID will be a pointer into static stoarge
2N/A * and should be treated as read-only by the caller (in particular,
2N/A * it does not need to be freed)."
2N/A *
2N/A * if (name_type) {
2N/A * if ((*minor = __OID_copy(name_type, __DH_GSS_C_NT_NETNAME))
2N/A * != DH_SUCCESS) {
2N/A * free(output->value);
2N/A * output->value = NULL;
2N/A * return (GSS_S_FAILURE);
2N/A * }
2N/A * }
2N/A */
2N/A
2N/A if (name_type)
2N/A *name_type = (gss_OID) __DH_GSS_C_NT_NETNAME;
2N/A
2N/A return (GSS_S_COMPLETE);
2N/A}
2N/A
2N/A/*
2N/A * Routine that takes a netname as a character string and assigns it
2N/A * to a an gss_name_t pointed to by output.
2N/A */
2N/Astatic OM_uint32
2N/Ado_netname_nametype(OM_uint32 *minor, char *input, gss_name_t *output)
2N/A{
2N/A if (__dh_validate_principal(input) != DH_SUCCESS)
2N/A return (GSS_S_BAD_NAME);
2N/A
2N/A *minor = DH_SUCCESS;
2N/A *output = (gss_name_t)strdup((char *)input);
2N/A
2N/A if (*output == NULL) {
2N/A *minor = DH_NOMEM_FAILURE;
2N/A return (GSS_S_FAILURE);
2N/A }
2N/A
2N/A return (GSS_S_COMPLETE);
2N/A}
2N/A
2N/A/*
2N/A * do_uid_nametype converts a uid to a gss_name_t pointed to by output
2N/A */
2N/Astatic OM_uint32
2N/Ado_uid_nametype(OM_uint32 *minor, uid_t uid, gss_name_t *output)
2N/A{
2N/A char netname[MAXNETNAMELEN+1];
2N/A
2N/A if (!user2netname(netname, uid, NULL)) {
2N/A *minor = DH_NETNAME_FAILURE;
2N/A return (GSS_S_FAILURE);
2N/A }
2N/A return (do_netname_nametype(minor, netname, output));
2N/A}
2N/A
2N/A/*
2N/A * do_username_nametype converts a username to a gss_name_t pointed to by
2N/A * output.
2N/A *
2N/A * A username will be represented by the following:
2N/A * name[/node][@security-domain]
2N/A *
2N/A * Then optional security-domain will represent secure rpc domain if
2N/A * present. If not present the local domain will be used. name is the
2N/A * user name as found in the unix password file. If name is root and
2N/A * node is present, then node will represent the host. If the host is
2N/A * a qualified name we assume that it is a DNS name and will only return
2N/A * the first commponnet since we want host name that are relative to
2N/A * the security domain (secure rpc domain).
2N/A */
2N/A
2N/Astatic OM_uint32
2N/Ado_username_nametype(OM_uint32 *minor, char *uname, gss_name_t *output)
2N/A{
2N/A char netname[MAXNETNAMELEN+1];
2N/A char *user, *node, *domain;
2N/A struct passwd pwd;
2N/A char buff[1024];
2N/A
2N/A /* Set outputs to sane values */
2N/A
2N/A *output = 0;
2N/A *minor = DH_SUCCESS;
2N/A
2N/A /* See if we have a name */
2N/A if (uname == 0) {
2N/A *minor = DH_NO_SUCH_USER;
2N/A return (GSS_S_FAILURE);
2N/A }
2N/A
2N/A /* copy the name so that we can do surgery on it */
2N/A user = strdup(uname);
2N/A if (user == 0) {
2N/A *minor = DH_NOMEM_FAILURE;
2N/A return (GSS_S_FAILURE);
2N/A }
2N/A
2N/A
2N/A /* Look for optional node part */
2N/A node = strchr(user, '/');
2N/A if (node) {
2N/A /*
2N/A * user is now just the user portion and node
2N/A * points to the start of the node part.
2N/A */
2N/A *node++ = '\0';
2N/A
2N/A /* Now see if there is a domain */
2N/A domain = strchr(node, '@');
2N/A }
2N/A else
2N/A /* Check for a domain */
2N/A domain = strchr(user, '@');
2N/A
2N/A /* Set domain to the beginning of the domain part if pressent */
2N/A if (domain)
2N/A *domain++ = '\0';
2N/A
2N/A /*
2N/A * See if the node part is important. If the user is root get
2N/A * the host from the node. If node is not present we assume
2N/A * we're the local host.
2N/A */
2N/A if (strcmp(user, "root") == 0) {
2N/A char *dot;
2N/A
2N/A /*
2N/A * We only want the host part of a qualfied host name. We
2N/A * assume the domain part of a hostname is a DNS domain,
2N/A * not an rpc domain. The rpc domain can be specified
2N/A * in the optional security domain part.
2N/A */
2N/A if (node) {
2N/A dot = strchr(node, '.');
2N/A if (dot)
2N/A *dot = '\0';
2N/A }
2N/A /*
2N/A * If node is null, assume local host. If domain is
2N/A * null assume local domain. See host2netname(3N)
2N/A */
2N/A if (!host2netname(netname, node, domain)) {
2N/A *minor = DH_NETNAME_FAILURE;
2N/A free(user);
2N/A return (GSS_S_FAILURE);
2N/A }
2N/A free(user);
2N/A return (do_netname_nametype(minor, netname, output));
2N/A }
2N/A
2N/A /*
2N/A * We use getpwnam_r to convert the name to uid. Note it is
2N/A * important to use getpwnam_r to preserve MT safty.
2N/A */
2N/A if (getpwnam_r(user, &pwd, buff, sizeof (buff)) == NULL) {
2N/A *minor = DH_NO_SUCH_USER;
2N/A free(user);
2N/A return (GSS_S_FAILURE);
2N/A }
2N/A
2N/A /* If domain is null assume local domain. See user2netname(3N) */
2N/A if (!user2netname(netname, pwd.pw_uid, domain)) {
2N/A *minor = DH_NETNAME_FAILURE;
2N/A free(user);
2N/A return (GSS_S_FAILURE);
2N/A }
2N/A free(user);
2N/A return (do_netname_nametype(minor, netname, output));
2N/A}
2N/A
2N/A/*
2N/A * do_hostbase_nametype convert a hostbase service name of the form
2N/A * service@hostname.
2N/A *
2N/A * For Diffie-Hellman we assume that the service is running with the
2N/A * credtials of the machine, i.e., as root.
2N/A */
2N/Astatic OM_uint32
2N/Ado_hostbase_nametype(OM_uint32 *minor, char *input, gss_name_t *output)
2N/A{
2N/A /* Get the nostname */
2N/A char *host = strchr(input, '@');
2N/A char netname[MAXNETNAMELEN+1];
2N/A
2N/A
2N/A /* If no host return bad name */
2N/A if (host == NULL)
2N/A return (GSS_S_BAD_NAME);
2N/A
2N/A /* Advance pass the "@" sign */
2N/A host += 1;
2N/A
2N/A /* Convert the hostname to its netname */
2N/A if (!host2netname(netname, host, NULL)) {
2N/A *minor = DH_NETNAME_FAILURE;
2N/A return (GSS_S_FAILURE);
2N/A }
2N/A
2N/A /* Internalize the netname to output */
2N/A return (do_netname_nametype(minor, netname, output));
2N/A}
2N/A
2N/A/*
2N/A * do_exported_netname: Convert an exported Diffie-Hellman name
2N/A * to a Diffie-Hellman internal name.
2N/A */
2N/Astatic OM_uint32
2N/Ado_exported_netname(
2N/A OM_uint32 *minor, /* Mech status */
2N/A gss_buffer_t input, /* The export name to convert */
2N/A gss_name_t *output /* The converted internal name */)
2N/A{
2N/A /* All export names must start with this */
2N/A const char tokid[] = "\x04\x01";
2N/A const int tokid_len = 2;
2N/A const int OIDlen_len = 2;
2N/A const int namelen_len = 4;
2N/A unsigned char *p = (unsigned char *)input->value;
2N/A OM_uint32 len = input->length;
2N/A int mechoidlen;
2N/A OM_uint32 oidlen; /* includes object tag len & DER len bytes */
2N/A OM_uint32 namelen;
2N/A OM_uint32 currlen;
2N/A OM_uint32 bytes;
2N/A
2N/A *minor = DH_BADARG_FAILURE;
2N/A
2N/A /* The len must be at least this big */
2N/A if (len < tokid_len + OIDlen_len + namelen_len)
2N/A return (GSS_S_DEFECTIVE_TOKEN);
2N/A
2N/A /* Export names must start with the token id of 0x04 0x01 */
2N/A if (memcmp(p, tokid, tokid_len) != 0)
2N/A return (GSS_S_DEFECTIVE_TOKEN);
2N/A p += tokid_len;
2N/A
2N/A /* Decode the Mechanism oid */
2N/A oidlen = (*p++ << 8) & 0xff00;
2N/A oidlen |= *p++ & 0xff;
2N/A
2N/A /* Check that we actually have the mechanism oid elements */
2N/A if (len < tokid_len + OIDlen_len + oidlen + namelen_len)
2N/A return (GSS_S_DEFECTIVE_TOKEN);
2N/A
2N/A /* Compare that the input is for this mechanism */
2N/A if (*p++ != 0x06)
2N/A return (GSS_S_DEFECTIVE_TOKEN);
2N/A currlen = len - (tokid_len + OIDlen_len + oidlen + namelen_len);
2N/A if ((mechoidlen = get_der_length(&p, currlen, &bytes)) < 0)
2N/A return (GSS_S_DEFECTIVE_TOKEN);
2N/A if (mechoidlen != OID.length)
2N/A return (GSS_S_DEFECTIVE_TOKEN);
2N/A if (memcmp(p, OID.elements, mechoidlen) != 0)
2N/A return (GSS_S_DEFECTIVE_TOKEN);
2N/A p += mechoidlen;
2N/A
2N/A /* Grab the length of the mechanism specific name per RFC 2078 */
2N/A namelen = (*p++ << 24) & 0xff000000;
2N/A namelen |= (*p++ << 16) & 0xff0000;
2N/A namelen |= (*p++ << 8) & 0xff00;
2N/A namelen |= *p++ & 0xff;
2N/A
2N/A /* This should alway be false */
2N/A if (len < tokid_len + OIDlen_len + oidlen + namelen_len + namelen)
2N/A return (GSS_S_DEFECTIVE_TOKEN);
2N/A
2N/A /* Make sure the bytes for the netname oid length are available */
2N/A if (namelen < OIDlen_len)
2N/A return (GSS_S_DEFECTIVE_TOKEN);
2N/A
2N/A /* Get the netname oid length */
2N/A oidlen = (*p++ << 8) & 0xff00;
2N/A oidlen = *p++ & 0xff;
2N/A
2N/A /* See if we have the elements of the netname oid */
2N/A if (namelen < OIDlen_len + oidlen)
2N/A return (GSS_S_DEFECTIVE_TOKEN);
2N/A
2N/A /* Check that the oid is really a netname */
2N/A if (oidlen != __DH_GSS_C_NT_NETNAME->length)
2N/A return (GSS_S_DEFECTIVE_TOKEN);
2N/A if (memcmp(p, __DH_GSS_C_NT_NETNAME->elements,
2N/A __DH_GSS_C_NT_NETNAME->length) != 0)
2N/A return (GSS_S_DEFECTIVE_TOKEN);
2N/A
2N/A /* p now points to the netname wich is null terminated */
2N/A p += oidlen;
2N/A
2N/A /*
2N/A * How the netname is encoded in an export name type for
2N/A * this mechanism. See _dh_gss_export_name below.
2N/A */
2N/A
2N/A if (namelen != OIDlen_len + oidlen + strlen((char *)p) + 1)
2N/A return (GSS_S_DEFECTIVE_TOKEN);
2N/A
2N/A /* Grab the netname */
2N/A *output = (gss_name_t)strdup((char *)p);
2N/A if (*output) {
2N/A *minor = 0;
2N/A return (GSS_S_COMPLETE);
2N/A }
2N/A
2N/A *minor = DH_NOMEM_FAILURE;
2N/A return (GSS_S_FAILURE);
2N/A}
2N/A
2N/A/*
2N/A * __dh_gss_import_name: Diffie-Hellman entry point for gss_import_name.
2N/A * Given an input name of a specified name type, convert this to a
2N/A * Diffie-Hellman internal name (netname).
2N/A *
2N/A * The idea here is simply compare the name_type supplied with each
2N/A * name type that we know how to deal with. If we have a match we call
2N/A * the appropriate support routine form above. If we done't have a match
2N/A * we return GSS_S_BAD_NAMETYPE
2N/A */
2N/AOM_uint32
2N/A__dh_gss_import_name(
2N/A OM_uint32 *minor, /* Mechanism status */
2N/A gss_buffer_t input, /* The name to convert */
2N/A gss_OID name_type, /* of this name_type */
2N/A gss_name_t *output /* The converted name */)
2N/A{
2N/A char *name;
2N/A OM_uint32 stat;
2N/A
2N/A if (minor == NULL || output == NULL)
2N/A return (GSS_S_CALL_INACCESSIBLE_WRITE);
2N/A
2N/A if (input == NULL || input->value == NULL)
2N/A return (GSS_S_BAD_NAME | GSS_S_CALL_INACCESSIBLE_READ);
2N/A if (name_type == GSS_C_NO_OID)
2N/A return (GSS_S_BAD_NAMETYPE);
2N/A
2N/A /* Set sane state */
2N/A *minor = DH_SUCCESS;
2N/A *output = GSS_C_NO_NAME;
2N/A
2N/A /* UID in machine format */
2N/A if (__OID_equal(name_type, GSS_C_NT_MACHINE_UID_NAME)) {
2N/A uid_t uid;
2N/A if (input->length != sizeof (uid_t))
2N/A return (GSS_S_BAD_NAME);
2N/A uid = *(uid_t *)input->value;
2N/A /* Should we assume that the id is network byte order ??? */
2N/A /* uid = htonl(uid); No, this should be the local orfering */
2N/A return (do_uid_nametype(minor, uid, output));
2N/A
2N/A /* Name that was exported with __dh_gss_export_name */
2N/A } else if (__OID_equal(name_type, GSS_C_NT_EXPORT_NAME)) {
2N/A stat = do_exported_netname(minor, input, output);
2N/A return (stat);
2N/A }
2N/A
2N/A /* Null ternamte name so we can manipulate as a c-style string */
2N/A name = malloc(input->length+1);
2N/A if (name == NULL) {
2N/A *minor = DH_NOMEM_FAILURE;
2N/A return (GSS_S_FAILURE);
2N/A }
2N/A memcpy(name, input->value, input->length);
2N/A name[input->length] = '\0';
2N/A
2N/A
2N/A /* Diffie-Hellman (ONC RPC netname) */
2N/A if (__OID_equal(name_type, __DH_GSS_C_NT_NETNAME)) {
2N/A stat = do_netname_nametype(minor, name, output);
2N/A free(name);
2N/A return (stat);
2N/A /* Host based service name (service@hostname) */
2N/A } else if (__OID_equal(name_type, GSS_C_NT_HOSTBASED_SERVICE)) {
2N/A stat = do_hostbase_nametype(minor, name, output);
2N/A free(name);
2N/A return (stat);
2N/A /* Thus local OS user name */
2N/A } else if (__OID_equal(name_type, GSS_C_NT_USER_NAME)) {
2N/A stat = do_username_nametype(minor, name, output);
2N/A free(name);
2N/A return (stat);
2N/A /* The os user id writen as a string */
2N/A } else if (__OID_equal(name_type, GSS_C_NT_STRING_UID_NAME)) {
2N/A char *p;
2N/A /* Convert the name to a uid */
2N/A uid_t uid = (uid_t)strtol(name, &p, 0);
2N/A free(name);
2N/A if (*p != '\0')
2N/A return (GSS_S_BAD_NAME);
2N/A return (do_uid_nametype(minor, uid, output));
2N/A } else {
2N/A /* Any thing else */
2N/A free(name);
2N/A return (GSS_S_BAD_NAMETYPE);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * __dh_gss_release_name: DH entry point for gss_release_name.
2N/A * Release an internal DH name.
2N/A */
2N/AOM_uint32
2N/A__dh_gss_release_name(OM_uint32 *minor, gss_name_t *name)
2N/A{
2N/A
2N/A if (minor == 0 || name == 0)
2N/A return (GSS_S_CALL_INACCESSIBLE_WRITE);
2N/A
2N/A *minor = DH_SUCCESS;
2N/A
2N/A free(*name);
2N/A *name = GSS_C_NO_NAME;
2N/A
2N/A return (GSS_S_COMPLETE);
2N/A}
2N/A
2N/A/* Lock for initializing oid_name_tab */
2N/Astatic mutex_t name_tab_lock = DEFAULTMUTEX;
2N/A
2N/A/* Table of name types that this mechanism understands */
2N/Astatic const gss_OID_desc * oid_name_tab[OID_MAX_NAME_ENTRIES];
2N/A
2N/A/*
2N/A * __dh_gss_inquire_names_for_mech: DH entry point for
2N/A * gss_inquire_names_for_mech.
2N/A *
2N/A * Return a set of OID name types that a mechanism can understand
2N/A */
2N/AOM_uint32
2N/A__dh_gss_inquire_names_for_mech(OM_uint32 *minor,
2N/A gss_OID mech, gss_OID_set *names)
2N/A{
2N/A /* See if we need to initialize the table */
2N/A if (oid_name_tab[0] == 0) {
2N/A mutex_lock(&name_tab_lock);
2N/A /* If nobody sneaked in, initialize the table */
2N/A if (oid_name_tab[0] == 0) {
2N/A oid_name_tab[0] = __DH_GSS_C_NT_NETNAME;
2N/A oid_name_tab[1] = GSS_C_NT_HOSTBASED_SERVICE;
2N/A oid_name_tab[2] = GSS_C_NT_USER_NAME;
2N/A oid_name_tab[3] = GSS_C_NT_MACHINE_UID_NAME;
2N/A oid_name_tab[4] = GSS_C_NT_STRING_UID_NAME;
2N/A oid_name_tab[5] = GSS_C_NT_EXPORT_NAME;
2N/A /* oid_name_tab[6] = GSS_C_NT_ANONYMOUS_NAME; */
2N/A }
2N/A mutex_unlock(&name_tab_lock);
2N/A }
2N/A
2N/A /* Return the set of OIDS from the table */
2N/A if ((*minor = __OID_copy_set_from_array(names,
2N/A oid_name_tab, 6)) != DH_SUCCESS)
2N/A return (GSS_S_FAILURE);
2N/A
2N/A return (GSS_S_COMPLETE);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Private libgss entry point to convert a principal name to uid.
2N/A */
2N/AOM_uint32
2N/A__dh_pname_to_uid(
2N/A OM_uint32 *minor, /* Mech status */
2N/A const gss_name_t pname, /* principal */
2N/A uid_t *uid /* where to put the uid */)
2N/A{
2N/A
2N/A gid_t gid;
2N/A gid_t *glist;
2N/A int glen;
2N/A /* Convert the principal name to a netname */
2N/A char *netname = (char *)pname;
2N/A char host_netname[MAXNETNAMELEN+1];
2N/A
2N/A if (pname == 0)
2N/A return (GSS_S_BAD_NAME | GSS_S_CALL_INACCESSIBLE_READ);
2N/A if (minor == 0 || uid == 0)
2N/A return (GSS_S_CALL_INACCESSIBLE_WRITE);
2N/A
2N/A *minor = DH_SUCCESS;
2N/A *uid = UID_NOBODY;
2N/A
2N/A glen = sysconf(_SC_NGROUPS_MAX);
2N/A if (glen < NGRPS)
2N/A glen = NGRPS;
2N/A
2N/A glist = alloca(glen * sizeof (gid_t));
2N/A
2N/A /* First try to convert as a user */
2N/A if (netname2user(netname, uid, &gid, &glen, glist))
2N/A return (GSS_S_COMPLETE);
2N/A /* Get this hosts netname */
2N/A else if (host2netname(host_netname, NULL, NULL)) {
2N/A /*
2N/A * If the netname is this host's netname then we're root
2N/A * else we're nobody.
2N/A */
2N/A if (strncmp(netname, host_netname, MAXNETNAMELEN) == 0)
2N/A *uid = 0;
2N/A return (GSS_S_COMPLETE);
2N/A }
2N/A
2N/A /* We could not get a netname */
2N/A *minor = DH_NETNAME_FAILURE;
2N/A return (GSS_S_FAILURE);
2N/A}
2N/A
2N/A/*
2N/A * __dh_gss_export_name: Diffie-Hellman support for gss_export_name.
2N/A * Given a Diffie-Hellman internal name return the GSS exported format.
2N/A */
2N/AOM_uint32
2N/A__dh_gss_export_name(
2N/A OM_uint32 *minor, /* Mechanism status */
2N/A const gss_name_t input_name, /* The name to export */
2N/A gss_buffer_t exported_name /* Exported name goes here */)
2N/A{
2N/A /* input_name is dh principal name */
2N/A dh_principal pname = (dh_principal)input_name;
2N/A /* Magic for exported blobs */
2N/A const char tokid[] = "\x04\x01";
2N/A const int tokid_len = 2;
2N/A const int OIDlen_len = 2; /* Why did they do this? */
2N/A const int namelen_len = 4;
2N/A const int mechoid_tag_len = 1;
2N/A unsigned char *p;
2N/A OM_uint32 len;
2N/A OM_uint32 namelen;
2N/A OM_uint32 currlen;
2N/A OM_uint32 oid_der_len = 0;
2N/A
2N/A if (minor == 0 || exported_name == GSS_C_NO_BUFFER)
2N/A return (GSS_S_CALL_INACCESSIBLE_WRITE);
2N/A if (input_name == GSS_C_NO_NAME)
2N/A return (GSS_S_CALL_INACCESSIBLE_READ);
2N/A
2N/A /* Set sane outputs */
2N/A *minor = DH_SUCCESS;
2N/A exported_name->length = 0;
2N/A exported_name->value = NULL;
2N/A
2N/A /* Determine the length of the name */
2N/A namelen = OIDlen_len + __DH_GSS_C_NT_NETNAME->length
2N/A + strlen(pname)+1;
2N/A oid_der_len = der_length_size(OID.length);
2N/A /* Find the total length */
2N/A len = tokid_len + OIDlen_len + mechoid_tag_len + oid_der_len
2N/A + OID.length + namelen_len + namelen;
2N/A
2N/A /* Allocate the blob */
2N/A p = New(unsigned char, len);
2N/A if (p == NULL) {
2N/A *minor = DH_NOMEM_FAILURE;
2N/A return (GSS_S_FAILURE);
2N/A }
2N/A /* Set the blob to the exported name */
2N/A exported_name->length = len;
2N/A exported_name->value = p;
2N/A
2N/A /* Start with some magic */
2N/A memcpy(p, tokid, tokid_len);
2N/A p += tokid_len;
2N/A
2N/A /*
2N/A * The spec only allows two bytes for the oid length.
2N/A * We are assuming here that the correct encodeing is MSB first as
2N/A * was done in libgss.
2N/A */
2N/A
2N/A *p++ = ((mechoid_tag_len + oid_der_len + OID.length)
2N/A & 0xff00) >> 8;
2N/A *p++ = ((mechoid_tag_len + oid_der_len + OID.length)
2N/A & 0x00ff);
2N/A
2N/A /* Now the mechanism OID DER Encoding */
2N/A *p++ = 0x06; /* Universal Tag for OID */
2N/A currlen = len - tokid_len - OIDlen_len - mechoid_tag_len;
2N/A if (!put_der_length(OID.length, &p, currlen) == 0) {
2N/A return (GSS_S_FAILURE);
2N/A }
2N/A
2N/A /* Now the mechanism OID elements */
2N/A memcpy(p, OID.elements, OID.length);
2N/A p += OID.length;
2N/A
2N/A /* The name length most MSB first */
2N/A *p++ = (namelen & 0xff000000) >> 24;
2N/A *p++ = (namelen & 0x00ff0000) >> 16;
2N/A *p++ = (namelen & 0x0000ff00) >> 8;
2N/A *p++ = (namelen & 0x000000ff);
2N/A
2N/A /*
2N/A * We'll now encode the netname oid. Again we'll just use 2 bytes.
2N/A * This is the same encoding that the libgss implementor uses, so
2N/A * we'll just follow along.
2N/A */
2N/A
2N/A *p++ = (__DH_GSS_C_NT_NETNAME->length & 0xff00) >> 8;
2N/A *p++ = (__DH_GSS_C_NT_NETNAME->length &0x00ff);
2N/A
2N/A /* The netname oid values */
2N/A memcpy(p, __DH_GSS_C_NT_NETNAME->elements,
2N/A __DH_GSS_C_NT_NETNAME->length);
2N/A
2N/A p += __DH_GSS_C_NT_NETNAME->length;
2N/A
2N/A /* Now we copy the netname including the null byte to be safe */
2N/A memcpy(p, pname, strlen(pname) + 1);
2N/A
2N/A return (GSS_S_COMPLETE);
2N/A}
2N/A
2N/A/*
2N/A * Support routine for __dh_internal_release_oid. Return True if
2N/A * the supplied OID points to the reference OID or if the elements
2N/A * of the reference OID are the same as the supplied OID. In the
2N/A * latter case, just free the OID container and set the pointer to it
2N/A * to GSS_C_NO_OID. Otherwise return false
2N/A */
2N/Astatic int
2N/Arelease_oid(const gss_OID_desc * const ref, gss_OID *oid)
2N/A{
2N/A gss_OID id = *oid;
2N/A
2N/A if (id == ref)
2N/A return (TRUE);
2N/A
2N/A /*
2N/A * If some on create a shallow copy free, the structure point to
2N/A * id and set the pointer to it to GSS_C_NO_OID
2N/A */
2N/A if (id->elements == ref->elements) {
2N/A Free(id);
2N/A *oid = GSS_C_NO_OID;
2N/A return (TRUE);
2N/A }
2N/A
2N/A return (FALSE);
2N/A}
2N/A
2N/A/*
2N/A * __dh_gss_internal_release_oid: DH support for the gss_internal_relaese_oid
2N/A * entry. Check that the refence to an oid is one of our mechanisms static
2N/A * OIDS. If it is return true indicating to libgss that we have handled the
2N/A * release of that OID. Otherwise we return false and let libgss deal with it.
2N/A *
2N/A * The only OIDS we know are the calling mechanism found in the context
2N/A * and the shared DH_GSS_C_NT_NETNAME name type
2N/A */
2N/AOM_uint32
2N/A__dh_gss_internal_release_oid(OM_uint32 *minor, gss_OID *oid)
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 if (oid == NULL || *oid == NULL)
2N/A return (GSS_S_COMPLETE);
2N/A
2N/A if (release_oid(&OID, oid))
2N/A return (GSS_S_COMPLETE);
2N/A
2N/A if (release_oid(__DH_GSS_C_NT_NETNAME, oid))
2N/A return (GSS_S_COMPLETE);
2N/A
2N/A return (GSS_S_FAILURE);
2N/A}