/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* name.c
*
* Copyright 2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include "dh_gssapi.h"
#include <pwd.h>
#include <string.h>
#include <stdlib.h>
#include <thread.h>
extern int
get_der_length(unsigned char **, unsigned int, unsigned int *);
extern unsigned int
der_length_size(unsigned int);
extern int
put_der_length(unsigned int, unsigned char **, unsigned int);
/* Diffie-Hellman ONC RPC netname name type */
{ 9, "\053\006\004\001\052\002\032\001\001" };
/*
* __dh_gss_compare_name: Diffie-Hellman machanism support for
* gss_compare_name. Given two gss_name_ts that are presumed to
* be rpc netnames set the *equal parameter to true if they are
* the same, else set it to false.
*/
int *equal /* The result */)
{
return (GSS_S_CALL_INACCESSIBLE_WRITE);
*minor = DH_SUCCESS;
return (GSS_S_BAD_NAME | GSS_S_CALL_INACCESSIBLE_READ);
}
return (GSS_S_COMPLETE);
}
/*
* __dh_gss_display_name: Supports gss_display_name for Diffie-Hellman
* mechanism. This takes a gss internal name and converts it to
* a counted string suitable for display.
*/
{
return (GSS_S_CALL_INACCESSIBLE_WRITE);
if (name == 0)
return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
*minor = DH_SUCCESS;
return (GSS_S_FAILURE);
}
/*
* Note: we no longer copy the name type OID. The current draft of
* the standard specifies:
*
* "The returned gss_OID will be a pointer into static stoarge
* and should be treated as read-only by the caller (in particular,
* it does not need to be freed)."
*
* if (name_type) {
* if ((*minor = __OID_copy(name_type, __DH_GSS_C_NT_NETNAME))
* != DH_SUCCESS) {
* free(output->value);
* output->value = NULL;
* return (GSS_S_FAILURE);
* }
* }
*/
if (name_type)
return (GSS_S_COMPLETE);
}
/*
* Routine that takes a netname as a character string and assigns it
* to a an gss_name_t pointed to by output.
*/
static OM_uint32
{
return (GSS_S_BAD_NAME);
*minor = DH_SUCCESS;
return (GSS_S_FAILURE);
}
return (GSS_S_COMPLETE);
}
/*
* do_uid_nametype converts a uid to a gss_name_t pointed to by output
*/
static OM_uint32
{
return (GSS_S_FAILURE);
}
}
/*
* do_username_nametype converts a username to a gss_name_t pointed to by
* output.
*
* A username will be represented by the following:
* name[/node][@security-domain]
*
* Then optional security-domain will represent secure rpc domain if
* present. If not present the local domain will be used. name is the
* user name as found in the unix password file. If name is root and
* node is present, then node will represent the host. If the host is
* a qualified name we assume that it is a DNS name and will only return
* the first commponnet since we want host name that are relative to
* the security domain (secure rpc domain).
*/
static OM_uint32
{
/* Set outputs to sane values */
*output = 0;
*minor = DH_SUCCESS;
/* See if we have a name */
if (uname == 0) {
*minor = DH_NO_SUCH_USER;
return (GSS_S_FAILURE);
}
/* copy the name so that we can do surgery on it */
if (user == 0) {
return (GSS_S_FAILURE);
}
/* Look for optional node part */
if (node) {
/*
* user is now just the user portion and node
* points to the start of the node part.
*/
*node++ = '\0';
/* Now see if there is a domain */
}
else
/* Check for a domain */
/* Set domain to the beginning of the domain part if pressent */
if (domain)
*domain++ = '\0';
/*
* See if the node part is important. If the user is root get
* the host from the node. If node is not present we assume
* we're the local host.
*/
char *dot;
/*
* We only want the host part of a qualfied host name. We
* assume the domain part of a hostname is a DNS domain,
* not an rpc domain. The rpc domain can be specified
* in the optional security domain part.
*/
if (node) {
if (dot)
*dot = '\0';
}
/*
* If node is null, assume local host. If domain is
* null assume local domain. See host2netname(3N)
*/
return (GSS_S_FAILURE);
}
}
/*
* We use getpwnam_r to convert the name to uid. Note it is
* important to use getpwnam_r to preserve MT safty.
*/
*minor = DH_NO_SUCH_USER;
return (GSS_S_FAILURE);
}
/* If domain is null assume local domain. See user2netname(3N) */
return (GSS_S_FAILURE);
}
}
/*
* do_hostbase_nametype convert a hostbase service name of the form
* service@hostname.
*
* For Diffie-Hellman we assume that the service is running with the
* credtials of the machine, i.e., as root.
*/
static OM_uint32
{
/* Get the nostname */
/* If no host return bad name */
return (GSS_S_BAD_NAME);
/* Advance pass the "@" sign */
host += 1;
/* Convert the hostname to its netname */
return (GSS_S_FAILURE);
}
/* Internalize the netname to output */
}
/*
* do_exported_netname: Convert an exported Diffie-Hellman name
* to a Diffie-Hellman internal name.
*/
static OM_uint32
{
/* All export names must start with this */
int mechoidlen;
/* The len must be at least this big */
return (GSS_S_DEFECTIVE_TOKEN);
/* Export names must start with the token id of 0x04 0x01 */
return (GSS_S_DEFECTIVE_TOKEN);
p += tokid_len;
/* Decode the Mechanism oid */
oidlen |= *p++ & 0xff;
/* Check that we actually have the mechanism oid elements */
return (GSS_S_DEFECTIVE_TOKEN);
/* Compare that the input is for this mechanism */
if (*p++ != 0x06)
return (GSS_S_DEFECTIVE_TOKEN);
return (GSS_S_DEFECTIVE_TOKEN);
return (GSS_S_DEFECTIVE_TOKEN);
return (GSS_S_DEFECTIVE_TOKEN);
p += mechoidlen;
/* Grab the length of the mechanism specific name per RFC 2078 */
namelen |= *p++ & 0xff;
/* This should alway be false */
return (GSS_S_DEFECTIVE_TOKEN);
/* Make sure the bytes for the netname oid length are available */
if (namelen < OIDlen_len)
return (GSS_S_DEFECTIVE_TOKEN);
/* Get the netname oid length */
oidlen = *p++ & 0xff;
/* See if we have the elements of the netname oid */
return (GSS_S_DEFECTIVE_TOKEN);
/* Check that the oid is really a netname */
return (GSS_S_DEFECTIVE_TOKEN);
__DH_GSS_C_NT_NETNAME->length) != 0)
return (GSS_S_DEFECTIVE_TOKEN);
/* p now points to the netname wich is null terminated */
p += oidlen;
/*
* How the netname is encoded in an export name type for
* this mechanism. See _dh_gss_export_name below.
*/
return (GSS_S_DEFECTIVE_TOKEN);
/* Grab the netname */
if (*output) {
*minor = 0;
return (GSS_S_COMPLETE);
}
return (GSS_S_FAILURE);
}
/*
* __dh_gss_import_name: Diffie-Hellman entry point for gss_import_name.
* Given an input name of a specified name type, convert this to a
* Diffie-Hellman internal name (netname).
*
* The idea here is simply compare the name_type supplied with each
* name type that we know how to deal with. If we have a match we call
* the appropriate support routine form above. If we done't have a match
* we return GSS_S_BAD_NAMETYPE
*/
{
char *name;
return (GSS_S_CALL_INACCESSIBLE_WRITE);
return (GSS_S_BAD_NAME | GSS_S_CALL_INACCESSIBLE_READ);
if (name_type == GSS_C_NO_OID)
return (GSS_S_BAD_NAMETYPE);
/* Set sane state */
*minor = DH_SUCCESS;
*output = GSS_C_NO_NAME;
/* UID in machine format */
return (GSS_S_BAD_NAME);
/* Should we assume that the id is network byte order ??? */
/* uid = htonl(uid); No, this should be the local orfering */
/* Name that was exported with __dh_gss_export_name */
return (stat);
}
/* Null ternamte name so we can manipulate as a c-style string */
return (GSS_S_FAILURE);
}
/* Diffie-Hellman (ONC RPC netname) */
return (stat);
/* Host based service name (service@hostname) */
return (stat);
/* Thus local OS user name */
return (stat);
/* The os user id writen as a string */
char *p;
/* Convert the name to a uid */
if (*p != '\0')
return (GSS_S_BAD_NAME);
} else {
/* Any thing else */
return (GSS_S_BAD_NAMETYPE);
}
}
/*
* __dh_gss_release_name: DH entry point for gss_release_name.
* Release an internal DH name.
*/
{
return (GSS_S_CALL_INACCESSIBLE_WRITE);
*minor = DH_SUCCESS;
*name = GSS_C_NO_NAME;
return (GSS_S_COMPLETE);
}
/* Lock for initializing oid_name_tab */
/* Table of name types that this mechanism understands */
/*
* __dh_gss_inquire_names_for_mech: DH entry point for
* gss_inquire_names_for_mech.
*
* Return a set of OID name types that a mechanism can understand
*/
{
/* See if we need to initialize the table */
if (oid_name_tab[0] == 0) {
/* If nobody sneaked in, initialize the table */
if (oid_name_tab[0] == 0) {
/* oid_name_tab[6] = GSS_C_NT_ANONYMOUS_NAME; */
}
}
/* Return the set of OIDS from the table */
return (GSS_S_FAILURE);
return (GSS_S_COMPLETE);
}
/*
* Private libgss entry point to convert a principal name to uid.
*/
{
int glen;
/* Convert the principal name to a netname */
if (pname == 0)
return (GSS_S_BAD_NAME | GSS_S_CALL_INACCESSIBLE_READ);
return (GSS_S_CALL_INACCESSIBLE_WRITE);
*minor = DH_SUCCESS;
*uid = UID_NOBODY;
/* First try to convert as a user */
return (GSS_S_COMPLETE);
/* Get this hosts netname */
/*
* If the netname is this host's netname then we're root
* else we're nobody.
*/
*uid = 0;
return (GSS_S_COMPLETE);
}
/* We could not get a netname */
return (GSS_S_FAILURE);
}
/*
* __dh_gss_export_name: Diffie-Hellman support for gss_export_name.
* Given a Diffie-Hellman internal name return the GSS exported format.
*/
{
/* input_name is dh principal name */
/* Magic for exported blobs */
unsigned char *p;
return (GSS_S_CALL_INACCESSIBLE_WRITE);
if (input_name == GSS_C_NO_NAME)
return (GSS_S_CALL_INACCESSIBLE_READ);
/* Set sane outputs */
*minor = DH_SUCCESS;
exported_name->length = 0;
/* Determine the length of the name */
/* Find the total length */
/* Allocate the blob */
if (p == NULL) {
return (GSS_S_FAILURE);
}
/* Set the blob to the exported name */
exported_name->value = p;
/* Start with some magic */
p += tokid_len;
/*
* The spec only allows two bytes for the oid length.
* We are assuming here that the correct encodeing is MSB first as
* was done in libgss.
*/
& 0xff00) >> 8;
& 0x00ff);
/* Now the mechanism OID DER Encoding */
*p++ = 0x06; /* Universal Tag for OID */
return (GSS_S_FAILURE);
}
/* Now the mechanism OID elements */
/* The name length most MSB first */
*p++ = (namelen & 0x000000ff);
/*
* We'll now encode the netname oid. Again we'll just use 2 bytes.
* This is the same encoding that the libgss implementor uses, so
* we'll just follow along.
*/
/* The netname oid values */
p += __DH_GSS_C_NT_NETNAME->length;
/* Now we copy the netname including the null byte to be safe */
return (GSS_S_COMPLETE);
}
/*
* Support routine for __dh_internal_release_oid. Return True if
* the supplied OID points to the reference OID or if the elements
* of the reference OID are the same as the supplied OID. In the
* latter case, just free the OID container and set the pointer to it
* to GSS_C_NO_OID. Otherwise return false
*/
static int
{
return (TRUE);
/*
* If some on create a shallow copy free, the structure point to
* id and set the pointer to it to GSS_C_NO_OID
*/
*oid = GSS_C_NO_OID;
return (TRUE);
}
return (FALSE);
}
/*
* __dh_gss_internal_release_oid: DH support for the gss_internal_relaese_oid
* entry. Check that the refence to an oid is one of our mechanisms static
* OIDS. If it is return true indicating to libgss that we have handled the
* release of that OID. Otherwise we return false and let libgss deal with it.
*
* The only OIDS we know are the calling mechanism found in the context
* and the shared DH_GSS_C_NT_NETNAME name type
*/
{
if (minor == 0)
return (GSS_S_CALL_INACCESSIBLE_WRITE);
*minor = DH_SUCCESS;
return (GSS_S_COMPLETE);
return (GSS_S_COMPLETE);
return (GSS_S_COMPLETE);
return (GSS_S_FAILURE);
}