xref: /onnv-gate/usr/src/lib/gss_mechs/mech_dh/backend/mech/name.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  *	name.c
24*0Sstevel@tonic-gate  *
25*0Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
26*0Sstevel@tonic-gate  * Use is subject to license terms.
27*0Sstevel@tonic-gate  *
28*0Sstevel@tonic-gate  */
29*0Sstevel@tonic-gate 
30*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
31*0Sstevel@tonic-gate 
32*0Sstevel@tonic-gate #include "dh_gssapi.h"
33*0Sstevel@tonic-gate #include <pwd.h>
34*0Sstevel@tonic-gate #include <string.h>
35*0Sstevel@tonic-gate #include <stdlib.h>
36*0Sstevel@tonic-gate #include <sys/types.h>
37*0Sstevel@tonic-gate #include <sys/param.h>
38*0Sstevel@tonic-gate #include <sys/note.h>
39*0Sstevel@tonic-gate #include <thread.h>
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate extern int
42*0Sstevel@tonic-gate get_der_length(unsigned char **, unsigned int, unsigned int *);
43*0Sstevel@tonic-gate 
44*0Sstevel@tonic-gate extern unsigned int
45*0Sstevel@tonic-gate der_length_size(unsigned int);
46*0Sstevel@tonic-gate 
47*0Sstevel@tonic-gate extern int
48*0Sstevel@tonic-gate put_der_length(unsigned int, unsigned char **, unsigned int);
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate /* Diffie-Hellman ONC RPC netname name type */
51*0Sstevel@tonic-gate static gss_OID_desc __DH_GSS_C_NT_NETNAME_desc =
52*0Sstevel@tonic-gate 	{ 9,  "\053\006\004\001\052\002\032\001\001" };
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate const gss_OID_desc * const __DH_GSS_C_NT_NETNAME = &__DH_GSS_C_NT_NETNAME_desc;
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate #define	OID_MAX_NAME_ENTRIES  32
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate /*
59*0Sstevel@tonic-gate  * __dh_gss_compare_name: Diffie-Hellman machanism support for
60*0Sstevel@tonic-gate  * gss_compare_name. Given two gss_name_ts that are presumed to
61*0Sstevel@tonic-gate  * be rpc netnames set the *equal parameter to true if they are
62*0Sstevel@tonic-gate  * the same, else set it to false.
63*0Sstevel@tonic-gate  */
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate OM_uint32
__dh_gss_compare_name(void * ctx,OM_uint32 * minor,gss_name_t name1,gss_name_t name2,int * equal)66*0Sstevel@tonic-gate __dh_gss_compare_name(void *ctx,	/* Per mechanism context (not used) */
67*0Sstevel@tonic-gate 		    OM_uint32 *minor,	/* Mechanism status */
68*0Sstevel@tonic-gate 		    gss_name_t name1,	/* First name to compare */
69*0Sstevel@tonic-gate 		    gss_name_t name2,	/* Second name to compare */
70*0Sstevel@tonic-gate 		    int *equal		/* The result */)
71*0Sstevel@tonic-gate {
72*0Sstevel@tonic-gate _NOTE(ARGUNUSED(ctx))
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate 	if (minor == 0 || equal == 0)
75*0Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate 	*minor = DH_SUCCESS;
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate 	if (name1 == 0 || name2 == 0) {
80*0Sstevel@tonic-gate 		*minor = DH_BADARG_FAILURE;
81*0Sstevel@tonic-gate 		return (GSS_S_BAD_NAME | GSS_S_CALL_INACCESSIBLE_READ);
82*0Sstevel@tonic-gate 	}
83*0Sstevel@tonic-gate 
84*0Sstevel@tonic-gate 	*equal = (strcmp((char *)name1, (char *)name2) == 0);
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate 	return (GSS_S_COMPLETE);
87*0Sstevel@tonic-gate }
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate /*
90*0Sstevel@tonic-gate  * __dh_gss_display_name: Supports gss_display_name for Diffie-Hellman
91*0Sstevel@tonic-gate  * mechanism. This takes a gss internal name and converts it to
92*0Sstevel@tonic-gate  * a counted string suitable for display.
93*0Sstevel@tonic-gate  */
94*0Sstevel@tonic-gate OM_uint32
__dh_gss_display_name(void * ctx,OM_uint32 * minor,gss_name_t name,gss_buffer_t output,gss_OID * name_type)95*0Sstevel@tonic-gate __dh_gss_display_name(void * ctx, /* Per mechanism context (not used) */
96*0Sstevel@tonic-gate 		    OM_uint32* minor, /* Mechanism status */
97*0Sstevel@tonic-gate 		    gss_name_t name, /* Diffie-Hellman internal name */
98*0Sstevel@tonic-gate 		    gss_buffer_t output, /* Were the printable name goes */
99*0Sstevel@tonic-gate 		    gss_OID *name_type /* Name type of the internal name */)
100*0Sstevel@tonic-gate {
101*0Sstevel@tonic-gate _NOTE(ARGUNUSED(ctx))
102*0Sstevel@tonic-gate 
103*0Sstevel@tonic-gate 	if (minor == 0 || output == 0)
104*0Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
105*0Sstevel@tonic-gate 
106*0Sstevel@tonic-gate 	if (name == 0)
107*0Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate 	*minor = DH_SUCCESS;
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate 	output->length = 0;
112*0Sstevel@tonic-gate 	output->value = (void *)strdup((char *)name);
113*0Sstevel@tonic-gate 	if (output->value == NULL) {
114*0Sstevel@tonic-gate 		*minor = DH_NOMEM_FAILURE;
115*0Sstevel@tonic-gate 		return (GSS_S_FAILURE);
116*0Sstevel@tonic-gate 	}
117*0Sstevel@tonic-gate 	output->length = strlen((char *)name) + 1;
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate /*
120*0Sstevel@tonic-gate  * Note: we no longer copy the name type OID. The current draft of
121*0Sstevel@tonic-gate  * the standard specifies:
122*0Sstevel@tonic-gate  *
123*0Sstevel@tonic-gate  * "The returned gss_OID will be a pointer into static stoarge
124*0Sstevel@tonic-gate  *  and should be treated as read-only by the caller (in particular,
125*0Sstevel@tonic-gate  *  it does not need to be freed)."
126*0Sstevel@tonic-gate  *
127*0Sstevel@tonic-gate  *	if (name_type) {
128*0Sstevel@tonic-gate  *		if ((*minor = __OID_copy(name_type, __DH_GSS_C_NT_NETNAME))
129*0Sstevel@tonic-gate  *			!= DH_SUCCESS) {
130*0Sstevel@tonic-gate  *			free(output->value);
131*0Sstevel@tonic-gate  *			output->value = NULL;
132*0Sstevel@tonic-gate  *			return (GSS_S_FAILURE);
133*0Sstevel@tonic-gate  *		}
134*0Sstevel@tonic-gate  *	}
135*0Sstevel@tonic-gate  */
136*0Sstevel@tonic-gate 
137*0Sstevel@tonic-gate 	if (name_type)
138*0Sstevel@tonic-gate 		*name_type = (gss_OID) __DH_GSS_C_NT_NETNAME;
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate 	return (GSS_S_COMPLETE);
141*0Sstevel@tonic-gate }
142*0Sstevel@tonic-gate 
143*0Sstevel@tonic-gate /*
144*0Sstevel@tonic-gate  * Routine that takes a netname as a character string and assigns it
145*0Sstevel@tonic-gate  * to a an gss_name_t pointed to by output.
146*0Sstevel@tonic-gate  */
147*0Sstevel@tonic-gate static OM_uint32
do_netname_nametype(OM_uint32 * minor,char * input,gss_name_t * output)148*0Sstevel@tonic-gate do_netname_nametype(OM_uint32 *minor, char *input, gss_name_t *output)
149*0Sstevel@tonic-gate {
150*0Sstevel@tonic-gate 	if (__dh_validate_principal(input) != DH_SUCCESS)
151*0Sstevel@tonic-gate 		return (GSS_S_BAD_NAME);
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate 	*minor = DH_SUCCESS;
154*0Sstevel@tonic-gate 	*output = (gss_name_t)strdup((char *)input);
155*0Sstevel@tonic-gate 
156*0Sstevel@tonic-gate 	if (*output == NULL) {
157*0Sstevel@tonic-gate 		*minor = DH_NOMEM_FAILURE;
158*0Sstevel@tonic-gate 		return (GSS_S_FAILURE);
159*0Sstevel@tonic-gate 	}
160*0Sstevel@tonic-gate 
161*0Sstevel@tonic-gate 	return (GSS_S_COMPLETE);
162*0Sstevel@tonic-gate }
163*0Sstevel@tonic-gate 
164*0Sstevel@tonic-gate /*
165*0Sstevel@tonic-gate  * do_uid_nametype converts a uid to a gss_name_t pointed to by output
166*0Sstevel@tonic-gate  */
167*0Sstevel@tonic-gate static OM_uint32
do_uid_nametype(OM_uint32 * minor,uid_t uid,gss_name_t * output)168*0Sstevel@tonic-gate do_uid_nametype(OM_uint32 *minor, uid_t uid, gss_name_t *output)
169*0Sstevel@tonic-gate {
170*0Sstevel@tonic-gate 	char netname[MAXNETNAMELEN+1];
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate 	if (!user2netname(netname, uid, NULL)) {
173*0Sstevel@tonic-gate 		*minor = DH_NETNAME_FAILURE;
174*0Sstevel@tonic-gate 		return (GSS_S_FAILURE);
175*0Sstevel@tonic-gate 	}
176*0Sstevel@tonic-gate 	return (do_netname_nametype(minor, netname, output));
177*0Sstevel@tonic-gate }
178*0Sstevel@tonic-gate 
179*0Sstevel@tonic-gate /*
180*0Sstevel@tonic-gate  * do_username_nametype converts a username to a gss_name_t pointed to by
181*0Sstevel@tonic-gate  * output.
182*0Sstevel@tonic-gate  *
183*0Sstevel@tonic-gate  * A username will be represented by the following:
184*0Sstevel@tonic-gate  * 	name[/node][@security-domain]
185*0Sstevel@tonic-gate  *
186*0Sstevel@tonic-gate  * Then optional security-domain will represent secure rpc domain if
187*0Sstevel@tonic-gate  * present. If not present the local domain will be used. name is the
188*0Sstevel@tonic-gate  * user name as found in the unix password file. If name is root and
189*0Sstevel@tonic-gate  * node is present, then node will represent the host. If the host is
190*0Sstevel@tonic-gate  * a qualified name we assume that it is a DNS name and will only return
191*0Sstevel@tonic-gate  * the first commponnet since we want host name that are relative to
192*0Sstevel@tonic-gate  * the security domain (secure rpc domain).
193*0Sstevel@tonic-gate  */
194*0Sstevel@tonic-gate 
195*0Sstevel@tonic-gate static OM_uint32
do_username_nametype(OM_uint32 * minor,char * uname,gss_name_t * output)196*0Sstevel@tonic-gate do_username_nametype(OM_uint32 *minor, char *uname, gss_name_t *output)
197*0Sstevel@tonic-gate {
198*0Sstevel@tonic-gate 	char netname[MAXNETNAMELEN+1];
199*0Sstevel@tonic-gate 	char *user, *node, *domain;
200*0Sstevel@tonic-gate 	struct passwd pwd;
201*0Sstevel@tonic-gate 	char buff[1024];
202*0Sstevel@tonic-gate 
203*0Sstevel@tonic-gate 	/* Set outputs to sane values */
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate 	*output = 0;
206*0Sstevel@tonic-gate 	*minor = DH_SUCCESS;
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate 	/* See if we have a name */
209*0Sstevel@tonic-gate 	if (uname == 0) {
210*0Sstevel@tonic-gate 		*minor = DH_NO_SUCH_USER;
211*0Sstevel@tonic-gate 		return (GSS_S_FAILURE);
212*0Sstevel@tonic-gate 	}
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate 	/* copy the name so that we can do surgery on it */
215*0Sstevel@tonic-gate 	user = strdup(uname);
216*0Sstevel@tonic-gate 	if (user == 0) {
217*0Sstevel@tonic-gate 		*minor = DH_NOMEM_FAILURE;
218*0Sstevel@tonic-gate 		return (GSS_S_FAILURE);
219*0Sstevel@tonic-gate 	}
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate 
222*0Sstevel@tonic-gate 	/* Look for optional node part */
223*0Sstevel@tonic-gate 	node = strchr(user, '/');
224*0Sstevel@tonic-gate 	if (node) {
225*0Sstevel@tonic-gate 		/*
226*0Sstevel@tonic-gate 		 * user is now just the user portion and node
227*0Sstevel@tonic-gate 		 * points to the start of the node part.
228*0Sstevel@tonic-gate 		 */
229*0Sstevel@tonic-gate 		*node++ = '\0';
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate 		/* Now see if there is a domain */
232*0Sstevel@tonic-gate 		domain = strchr(node, '@');
233*0Sstevel@tonic-gate 	}
234*0Sstevel@tonic-gate 	else
235*0Sstevel@tonic-gate 		/* Check for a domain */
236*0Sstevel@tonic-gate 		domain = strchr(user, '@');
237*0Sstevel@tonic-gate 
238*0Sstevel@tonic-gate 	/* Set domain to the beginning of the domain part if pressent */
239*0Sstevel@tonic-gate 	if (domain)
240*0Sstevel@tonic-gate 		*domain++ = '\0';
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate 	/*
243*0Sstevel@tonic-gate 	 * See if the node part is important. If the user is root get
244*0Sstevel@tonic-gate 	 * the host from the node. If node is not present we assume
245*0Sstevel@tonic-gate 	 * we're the local host.
246*0Sstevel@tonic-gate 	 */
247*0Sstevel@tonic-gate 	if (strcmp(user, "root") == 0) {
248*0Sstevel@tonic-gate 		char *dot;
249*0Sstevel@tonic-gate 
250*0Sstevel@tonic-gate 		/*
251*0Sstevel@tonic-gate 		 * We only want the host part of a qualfied host name. We
252*0Sstevel@tonic-gate 		 * assume the domain part of a hostname is a DNS domain,
253*0Sstevel@tonic-gate 		 * not an rpc domain. The rpc domain can be specified
254*0Sstevel@tonic-gate 		 * in the optional security domain part.
255*0Sstevel@tonic-gate 		 */
256*0Sstevel@tonic-gate 		if (node) {
257*0Sstevel@tonic-gate 			dot = strchr(node, '.');
258*0Sstevel@tonic-gate 			if (dot)
259*0Sstevel@tonic-gate 				*dot = '\0';
260*0Sstevel@tonic-gate 		}
261*0Sstevel@tonic-gate 		/*
262*0Sstevel@tonic-gate 		 * If node is null, assume local host. If domain is
263*0Sstevel@tonic-gate 		 * null assume local domain. See host2netname(3N)
264*0Sstevel@tonic-gate 		 */
265*0Sstevel@tonic-gate 		if (!host2netname(netname, node,  domain)) {
266*0Sstevel@tonic-gate 			*minor = DH_NETNAME_FAILURE;
267*0Sstevel@tonic-gate 			free(user);
268*0Sstevel@tonic-gate 			return (GSS_S_FAILURE);
269*0Sstevel@tonic-gate 		}
270*0Sstevel@tonic-gate 		free(user);
271*0Sstevel@tonic-gate 		return (do_netname_nametype(minor, netname, output));
272*0Sstevel@tonic-gate 	}
273*0Sstevel@tonic-gate 
274*0Sstevel@tonic-gate 	/*
275*0Sstevel@tonic-gate 	 * We use getpwnam_r to convert the name to uid.  Note it is
276*0Sstevel@tonic-gate 	 * important to use getpwnam_r to preserve MT safty.
277*0Sstevel@tonic-gate 	 */
278*0Sstevel@tonic-gate 	if (getpwnam_r(user, &pwd, buff, sizeof (buff)) == NULL) {
279*0Sstevel@tonic-gate 		*minor = DH_NO_SUCH_USER;
280*0Sstevel@tonic-gate 		free(user);
281*0Sstevel@tonic-gate 		return (GSS_S_FAILURE);
282*0Sstevel@tonic-gate 	}
283*0Sstevel@tonic-gate 
284*0Sstevel@tonic-gate 	/* If domain is null assume local domain. See user2netname(3N) */
285*0Sstevel@tonic-gate 	if (!user2netname(netname, pwd.pw_uid, domain)) {
286*0Sstevel@tonic-gate 		*minor = DH_NETNAME_FAILURE;
287*0Sstevel@tonic-gate 		free(user);
288*0Sstevel@tonic-gate 		return (GSS_S_FAILURE);
289*0Sstevel@tonic-gate 	}
290*0Sstevel@tonic-gate 	free(user);
291*0Sstevel@tonic-gate 	return (do_netname_nametype(minor, netname, output));
292*0Sstevel@tonic-gate }
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate /*
295*0Sstevel@tonic-gate  * do_hostbase_nametype convert a hostbase service name of the form
296*0Sstevel@tonic-gate  *	service@hostname.
297*0Sstevel@tonic-gate  *
298*0Sstevel@tonic-gate  * For Diffie-Hellman we assume that the service is running with the
299*0Sstevel@tonic-gate  * credtials of the machine, i.e., as root.
300*0Sstevel@tonic-gate  */
301*0Sstevel@tonic-gate static OM_uint32
do_hostbase_nametype(OM_uint32 * minor,char * input,gss_name_t * output)302*0Sstevel@tonic-gate do_hostbase_nametype(OM_uint32 *minor, char *input, gss_name_t *output)
303*0Sstevel@tonic-gate {
304*0Sstevel@tonic-gate 	/* Get the nostname */
305*0Sstevel@tonic-gate 	char *host = strchr(input, '@');
306*0Sstevel@tonic-gate 	char netname[MAXNETNAMELEN+1];
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate 	/* If no host return bad name */
310*0Sstevel@tonic-gate 	if (host == NULL)
311*0Sstevel@tonic-gate 		return (GSS_S_BAD_NAME);
312*0Sstevel@tonic-gate 
313*0Sstevel@tonic-gate 	/* Advance pass the "@" sign */
314*0Sstevel@tonic-gate 	host += 1;
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate 	/* Convert the hostname to its netname */
317*0Sstevel@tonic-gate 	if (!host2netname(netname, host, NULL)) {
318*0Sstevel@tonic-gate 		*minor = DH_NETNAME_FAILURE;
319*0Sstevel@tonic-gate 		return (GSS_S_FAILURE);
320*0Sstevel@tonic-gate 	}
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate 	/* Internalize the netname to output */
323*0Sstevel@tonic-gate 	return (do_netname_nametype(minor, netname, output));
324*0Sstevel@tonic-gate }
325*0Sstevel@tonic-gate 
326*0Sstevel@tonic-gate /*
327*0Sstevel@tonic-gate  * do_exported_netname: Convert an exported Diffie-Hellman name
328*0Sstevel@tonic-gate  * to a Diffie-Hellman internal name.
329*0Sstevel@tonic-gate  */
330*0Sstevel@tonic-gate static OM_uint32
do_exported_netname(dh_context_t ctx,OM_uint32 * minor,gss_buffer_t input,gss_name_t * output)331*0Sstevel@tonic-gate do_exported_netname(dh_context_t ctx, /* Diffie-Hellman mech context */
332*0Sstevel@tonic-gate 		    OM_uint32 *minor, /* Mech status */
333*0Sstevel@tonic-gate 		    gss_buffer_t input, /* The export name to convert */
334*0Sstevel@tonic-gate 		    gss_name_t *output /* The converted internal name */)
335*0Sstevel@tonic-gate {
336*0Sstevel@tonic-gate 	/* All export names must start with this */
337*0Sstevel@tonic-gate 	const char tokid[] = "\x04\x01";
338*0Sstevel@tonic-gate 	const int tokid_len = 2;
339*0Sstevel@tonic-gate 	const int OIDlen_len = 2;
340*0Sstevel@tonic-gate 	const int namelen_len = 4;
341*0Sstevel@tonic-gate 	unsigned char *p = (unsigned char *)input->value;
342*0Sstevel@tonic-gate 	OM_uint32 len = input->length;
343*0Sstevel@tonic-gate 	int	 mechoidlen;
344*0Sstevel@tonic-gate 	OM_uint32 oidlen; /* includes object tag len & DER len bytes */
345*0Sstevel@tonic-gate 	OM_uint32 namelen;
346*0Sstevel@tonic-gate 	OM_uint32 currlen;
347*0Sstevel@tonic-gate 	OM_uint32 bytes;
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate 	*minor = DH_BADARG_FAILURE;
350*0Sstevel@tonic-gate 
351*0Sstevel@tonic-gate 	/* The len must be at least this big */
352*0Sstevel@tonic-gate 	if (len < tokid_len + OIDlen_len + namelen_len)
353*0Sstevel@tonic-gate 		return (GSS_S_DEFECTIVE_TOKEN);
354*0Sstevel@tonic-gate 
355*0Sstevel@tonic-gate 	/* Export names must start with the token id of 0x04 0x01 */
356*0Sstevel@tonic-gate 	if (memcmp(p, tokid, tokid_len) != 0)
357*0Sstevel@tonic-gate 		return (GSS_S_DEFECTIVE_TOKEN);
358*0Sstevel@tonic-gate 	p += tokid_len;
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate 	/* Decode the Mechanism oid */
361*0Sstevel@tonic-gate 	oidlen = (*p++ << 8) & 0xff00;
362*0Sstevel@tonic-gate 	oidlen |= *p++ & 0xff;
363*0Sstevel@tonic-gate 
364*0Sstevel@tonic-gate 	/* Check that we actually have the mechanism oid elements */
365*0Sstevel@tonic-gate 	if (len < tokid_len + OIDlen_len + oidlen + namelen_len)
366*0Sstevel@tonic-gate 		return (GSS_S_DEFECTIVE_TOKEN);
367*0Sstevel@tonic-gate 
368*0Sstevel@tonic-gate 	/* Compare that the input is for this mechanism */
369*0Sstevel@tonic-gate 	if (*p++ != 0x06)
370*0Sstevel@tonic-gate 		return (GSS_S_DEFECTIVE_TOKEN);
371*0Sstevel@tonic-gate 	currlen = len - (tokid_len + OIDlen_len + oidlen + namelen_len);
372*0Sstevel@tonic-gate 	if ((mechoidlen = get_der_length(&p, currlen, &bytes)) < 0)
373*0Sstevel@tonic-gate 		return (GSS_S_DEFECTIVE_TOKEN);
374*0Sstevel@tonic-gate 	if (mechoidlen != ctx->mech->length)
375*0Sstevel@tonic-gate 		return (GSS_S_DEFECTIVE_TOKEN);
376*0Sstevel@tonic-gate 	if (memcmp(p, ctx->mech->elements, mechoidlen) != 0)
377*0Sstevel@tonic-gate 		return (GSS_S_DEFECTIVE_TOKEN);
378*0Sstevel@tonic-gate 	p += mechoidlen;
379*0Sstevel@tonic-gate 
380*0Sstevel@tonic-gate 	/* Grab the length of the mechanism specific name per RFC 2078 */
381*0Sstevel@tonic-gate 	namelen = (*p++ << 24) & 0xff000000;
382*0Sstevel@tonic-gate 	namelen |= (*p++ << 16) & 0xff0000;
383*0Sstevel@tonic-gate 	namelen |= (*p++ << 8) & 0xff00;
384*0Sstevel@tonic-gate 	namelen |= *p++ & 0xff;
385*0Sstevel@tonic-gate 
386*0Sstevel@tonic-gate 	/* This should alway be false */
387*0Sstevel@tonic-gate 	if (len < tokid_len + OIDlen_len + oidlen + namelen_len + namelen)
388*0Sstevel@tonic-gate 		return (GSS_S_DEFECTIVE_TOKEN);
389*0Sstevel@tonic-gate 
390*0Sstevel@tonic-gate 	/* Make sure the bytes for the netname oid length are available */
391*0Sstevel@tonic-gate 	if (namelen < OIDlen_len)
392*0Sstevel@tonic-gate 		return (GSS_S_DEFECTIVE_TOKEN);
393*0Sstevel@tonic-gate 
394*0Sstevel@tonic-gate 	/* Get the netname oid length */
395*0Sstevel@tonic-gate 	oidlen = (*p++ << 8) & 0xff00;
396*0Sstevel@tonic-gate 	oidlen = *p++ & 0xff;
397*0Sstevel@tonic-gate 
398*0Sstevel@tonic-gate 	/* See if we have the elements of the netname oid */
399*0Sstevel@tonic-gate 	if (namelen < OIDlen_len + oidlen)
400*0Sstevel@tonic-gate 		return (GSS_S_DEFECTIVE_TOKEN);
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate 	/* Check that the oid is really a netname */
403*0Sstevel@tonic-gate 	if (oidlen != __DH_GSS_C_NT_NETNAME->length)
404*0Sstevel@tonic-gate 		return (GSS_S_DEFECTIVE_TOKEN);
405*0Sstevel@tonic-gate 	if (memcmp(p, __DH_GSS_C_NT_NETNAME->elements,
406*0Sstevel@tonic-gate 	    __DH_GSS_C_NT_NETNAME->length) != 0)
407*0Sstevel@tonic-gate 		return (GSS_S_DEFECTIVE_TOKEN);
408*0Sstevel@tonic-gate 
409*0Sstevel@tonic-gate 	/* p now points to the netname wich is null terminated */
410*0Sstevel@tonic-gate 	p += oidlen;
411*0Sstevel@tonic-gate 
412*0Sstevel@tonic-gate 	/*
413*0Sstevel@tonic-gate 	 * How the netname is encoded in an export name type for
414*0Sstevel@tonic-gate 	 * this mechanism. See _dh_gss_export_name below.
415*0Sstevel@tonic-gate 	 */
416*0Sstevel@tonic-gate 
417*0Sstevel@tonic-gate 	if (namelen != OIDlen_len + oidlen + strlen((char *)p) + 1)
418*0Sstevel@tonic-gate 		return (GSS_S_DEFECTIVE_TOKEN);
419*0Sstevel@tonic-gate 
420*0Sstevel@tonic-gate 	/* Grab the netname */
421*0Sstevel@tonic-gate 	*output = (gss_name_t)strdup((char *)p);
422*0Sstevel@tonic-gate 	if (*output) {
423*0Sstevel@tonic-gate 		*minor = 0;
424*0Sstevel@tonic-gate 		return (GSS_S_COMPLETE);
425*0Sstevel@tonic-gate 	}
426*0Sstevel@tonic-gate 
427*0Sstevel@tonic-gate 	*minor = DH_NOMEM_FAILURE;
428*0Sstevel@tonic-gate 	return (GSS_S_FAILURE);
429*0Sstevel@tonic-gate }
430*0Sstevel@tonic-gate 
431*0Sstevel@tonic-gate /*
432*0Sstevel@tonic-gate  * __dh_gss_import_name: Diffie-Hellman entry point for gss_import_name.
433*0Sstevel@tonic-gate  * Given an input name of a specified name type, convert this to a
434*0Sstevel@tonic-gate  * Diffie-Hellman internal name (netname).
435*0Sstevel@tonic-gate  *
436*0Sstevel@tonic-gate  * The idea here is simply compare the name_type supplied with each
437*0Sstevel@tonic-gate  * name type that we know how to deal with. If we have a match we call
438*0Sstevel@tonic-gate  * the appropriate support routine form above. If we done't have a match
439*0Sstevel@tonic-gate  * we return GSS_S_BAD_NAMETYPE
440*0Sstevel@tonic-gate  */
441*0Sstevel@tonic-gate OM_uint32
__dh_gss_import_name(void * ctx,OM_uint32 * minor,gss_buffer_t input,gss_OID name_type,gss_name_t * output)442*0Sstevel@tonic-gate __dh_gss_import_name(void *ctx, /* Per mechanism context */
443*0Sstevel@tonic-gate 		    OM_uint32 *minor, /* Mechanism status */
444*0Sstevel@tonic-gate 		    gss_buffer_t input, /* The name to convert */
445*0Sstevel@tonic-gate 		    gss_OID name_type, /* of this name_type */
446*0Sstevel@tonic-gate 		    gss_name_t *output /* The converted name */)
447*0Sstevel@tonic-gate {
448*0Sstevel@tonic-gate 	char *name;
449*0Sstevel@tonic-gate 	OM_uint32 stat;
450*0Sstevel@tonic-gate 
451*0Sstevel@tonic-gate 	if (minor == NULL || output == NULL)
452*0Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
453*0Sstevel@tonic-gate 
454*0Sstevel@tonic-gate 	if (input == NULL || input->value == NULL)
455*0Sstevel@tonic-gate 		return (GSS_S_BAD_NAME | GSS_S_CALL_INACCESSIBLE_READ);
456*0Sstevel@tonic-gate 	if (name_type == GSS_C_NO_OID)
457*0Sstevel@tonic-gate 		return (GSS_S_BAD_NAMETYPE);
458*0Sstevel@tonic-gate 
459*0Sstevel@tonic-gate 	/* Set sane state */
460*0Sstevel@tonic-gate 	*minor = DH_SUCCESS;
461*0Sstevel@tonic-gate 	*output = GSS_C_NO_NAME;
462*0Sstevel@tonic-gate 
463*0Sstevel@tonic-gate 		/* UID in machine format */
464*0Sstevel@tonic-gate 	if (__OID_equal(name_type, GSS_C_NT_MACHINE_UID_NAME)) {
465*0Sstevel@tonic-gate 		uid_t uid;
466*0Sstevel@tonic-gate 		if (input->length != sizeof (uid_t))
467*0Sstevel@tonic-gate 			return (GSS_S_BAD_NAME);
468*0Sstevel@tonic-gate 		uid = *(uid_t *)input->value;
469*0Sstevel@tonic-gate 		/* Should we assume that the id is network byte order ??? */
470*0Sstevel@tonic-gate 		/* uid = htonl(uid); No, this should be the local orfering */
471*0Sstevel@tonic-gate 		return (do_uid_nametype(minor, uid, output));
472*0Sstevel@tonic-gate 
473*0Sstevel@tonic-gate 		/* Name that was exported with __dh_gss_export_name */
474*0Sstevel@tonic-gate 	} else if (__OID_equal(name_type, GSS_C_NT_EXPORT_NAME)) {
475*0Sstevel@tonic-gate 		stat = do_exported_netname((dh_context_t)ctx, minor,
476*0Sstevel@tonic-gate 		    input, output);
477*0Sstevel@tonic-gate 		return (stat);
478*0Sstevel@tonic-gate 	}
479*0Sstevel@tonic-gate 
480*0Sstevel@tonic-gate 	/* Null ternamte name so we can manipulate as a c-style string */
481*0Sstevel@tonic-gate 	name = malloc(input->length+1);
482*0Sstevel@tonic-gate 	if (name == NULL) {
483*0Sstevel@tonic-gate 		*minor = DH_NOMEM_FAILURE;
484*0Sstevel@tonic-gate 		return (GSS_S_FAILURE);
485*0Sstevel@tonic-gate 	}
486*0Sstevel@tonic-gate 	memcpy(name, input->value, input->length);
487*0Sstevel@tonic-gate 	name[input->length] = '\0';
488*0Sstevel@tonic-gate 
489*0Sstevel@tonic-gate 
490*0Sstevel@tonic-gate 		/* Diffie-Hellman (ONC RPC netname) */
491*0Sstevel@tonic-gate 	if (__OID_equal(name_type, __DH_GSS_C_NT_NETNAME)) {
492*0Sstevel@tonic-gate 		stat = do_netname_nametype(minor, name, output);
493*0Sstevel@tonic-gate 		free(name);
494*0Sstevel@tonic-gate 		return (stat);
495*0Sstevel@tonic-gate 		/* Host based service name (service@hostname) */
496*0Sstevel@tonic-gate 	} else if (__OID_equal(name_type, GSS_C_NT_HOSTBASED_SERVICE)) {
497*0Sstevel@tonic-gate 		stat = do_hostbase_nametype(minor, name, output);
498*0Sstevel@tonic-gate 		free(name);
499*0Sstevel@tonic-gate 		return (stat);
500*0Sstevel@tonic-gate 		/* Thus local OS user name */
501*0Sstevel@tonic-gate 	} else if (__OID_equal(name_type, GSS_C_NT_USER_NAME)) {
502*0Sstevel@tonic-gate 		stat = do_username_nametype(minor, name, output);
503*0Sstevel@tonic-gate 		free(name);
504*0Sstevel@tonic-gate 		return (stat);
505*0Sstevel@tonic-gate 		/* The os user id writen as a string */
506*0Sstevel@tonic-gate 	} else if (__OID_equal(name_type, GSS_C_NT_STRING_UID_NAME)) {
507*0Sstevel@tonic-gate 		char *p;
508*0Sstevel@tonic-gate 		/* Convert the name to a uid */
509*0Sstevel@tonic-gate 		uid_t uid = (uid_t)strtol(name, &p, 0);
510*0Sstevel@tonic-gate 		free(name);
511*0Sstevel@tonic-gate 		if (*p != '\0')
512*0Sstevel@tonic-gate 			return (GSS_S_BAD_NAME);
513*0Sstevel@tonic-gate 		return (do_uid_nametype(minor, uid, output));
514*0Sstevel@tonic-gate 	} else {
515*0Sstevel@tonic-gate 		/* Any thing else */
516*0Sstevel@tonic-gate 		free(name);
517*0Sstevel@tonic-gate 		return (GSS_S_BAD_NAMETYPE);
518*0Sstevel@tonic-gate 	}
519*0Sstevel@tonic-gate }
520*0Sstevel@tonic-gate 
521*0Sstevel@tonic-gate /*
522*0Sstevel@tonic-gate  * __dh_gss_release_name: DH entry point for gss_release_name.
523*0Sstevel@tonic-gate  * Release an internal DH name.
524*0Sstevel@tonic-gate  */
525*0Sstevel@tonic-gate OM_uint32
__dh_gss_release_name(void * ctx,OM_uint32 * minor,gss_name_t * name)526*0Sstevel@tonic-gate __dh_gss_release_name(void *ctx, OM_uint32 *minor, gss_name_t *name)
527*0Sstevel@tonic-gate {
528*0Sstevel@tonic-gate _NOTE(ARGUNUSED(ctx))
529*0Sstevel@tonic-gate 
530*0Sstevel@tonic-gate 	if (minor == 0 || name == 0)
531*0Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
532*0Sstevel@tonic-gate 
533*0Sstevel@tonic-gate 	*minor = DH_SUCCESS;
534*0Sstevel@tonic-gate 
535*0Sstevel@tonic-gate 	free(*name);
536*0Sstevel@tonic-gate 	*name = GSS_C_NO_NAME;
537*0Sstevel@tonic-gate 
538*0Sstevel@tonic-gate 	return (GSS_S_COMPLETE);
539*0Sstevel@tonic-gate }
540*0Sstevel@tonic-gate 
541*0Sstevel@tonic-gate /* Lock for initializing oid_name_tab */
542*0Sstevel@tonic-gate static mutex_t name_tab_lock = DEFAULTMUTEX;
543*0Sstevel@tonic-gate 
544*0Sstevel@tonic-gate /* Table of name types that this mechanism understands */
545*0Sstevel@tonic-gate static const gss_OID_desc * oid_name_tab[OID_MAX_NAME_ENTRIES];
546*0Sstevel@tonic-gate 
547*0Sstevel@tonic-gate /*
548*0Sstevel@tonic-gate  * __dh_gss_inquire_names_for_mech: DH entry point for
549*0Sstevel@tonic-gate  * gss_inquire_names_for_mech.
550*0Sstevel@tonic-gate  *
551*0Sstevel@tonic-gate  * Return a set of OID name types that a mechanism can understand
552*0Sstevel@tonic-gate  */
553*0Sstevel@tonic-gate OM_uint32
__dh_gss_inquire_names_for_mech(void * ctx,OM_uint32 * minor,gss_OID mech,gss_OID_set * names)554*0Sstevel@tonic-gate __dh_gss_inquire_names_for_mech(void *ctx, OM_uint32 *minor,
555*0Sstevel@tonic-gate     gss_OID mech, gss_OID_set *names)
556*0Sstevel@tonic-gate {
557*0Sstevel@tonic-gate _NOTE(ARGUNUSED(ctx,mech))
558*0Sstevel@tonic-gate 
559*0Sstevel@tonic-gate 	/* See if we need to initialize the table */
560*0Sstevel@tonic-gate 	if (oid_name_tab[0] == 0) {
561*0Sstevel@tonic-gate 		mutex_lock(&name_tab_lock);
562*0Sstevel@tonic-gate 		/* If nobody sneaked in, initialize the table */
563*0Sstevel@tonic-gate 		if (oid_name_tab[0] == 0) {
564*0Sstevel@tonic-gate 			oid_name_tab[0] = __DH_GSS_C_NT_NETNAME;
565*0Sstevel@tonic-gate 			oid_name_tab[1] = GSS_C_NT_HOSTBASED_SERVICE;
566*0Sstevel@tonic-gate 			oid_name_tab[2] = GSS_C_NT_USER_NAME;
567*0Sstevel@tonic-gate 			oid_name_tab[3] = GSS_C_NT_MACHINE_UID_NAME;
568*0Sstevel@tonic-gate 			oid_name_tab[4] = GSS_C_NT_STRING_UID_NAME;
569*0Sstevel@tonic-gate 			oid_name_tab[5] = GSS_C_NT_EXPORT_NAME;
570*0Sstevel@tonic-gate 			/* oid_name_tab[6] = GSS_C_NT_ANONYMOUS_NAME; */
571*0Sstevel@tonic-gate 		}
572*0Sstevel@tonic-gate 		mutex_unlock(&name_tab_lock);
573*0Sstevel@tonic-gate 	}
574*0Sstevel@tonic-gate 
575*0Sstevel@tonic-gate 	/* Return the set of OIDS from the table */
576*0Sstevel@tonic-gate 	if ((*minor = __OID_copy_set_from_array(names,
577*0Sstevel@tonic-gate 	    oid_name_tab, 6)) != DH_SUCCESS)
578*0Sstevel@tonic-gate 		return (GSS_S_FAILURE);
579*0Sstevel@tonic-gate 
580*0Sstevel@tonic-gate 	return (GSS_S_COMPLETE);
581*0Sstevel@tonic-gate }
582*0Sstevel@tonic-gate 
583*0Sstevel@tonic-gate 
584*0Sstevel@tonic-gate /*
585*0Sstevel@tonic-gate  * Private libgss entry point to convert a principal name to uid.
586*0Sstevel@tonic-gate  */
587*0Sstevel@tonic-gate OM_uint32
__dh_pname_to_uid(void * ctx,OM_uint32 * minor,const gss_name_t pname,uid_t * uid)588*0Sstevel@tonic-gate __dh_pname_to_uid(void *ctx, /* DH mech context (not used) */
589*0Sstevel@tonic-gate 		OM_uint32 *minor, /* Mech status */
590*0Sstevel@tonic-gate 		const gss_name_t pname, /* principal */
591*0Sstevel@tonic-gate 		uid_t *uid  /* where to put the uid */)
592*0Sstevel@tonic-gate {
593*0Sstevel@tonic-gate _NOTE(ARGUNUSED(ctx))
594*0Sstevel@tonic-gate 
595*0Sstevel@tonic-gate 	gid_t gid;
596*0Sstevel@tonic-gate 	gid_t glist[NGRPS];
597*0Sstevel@tonic-gate 	int glen;
598*0Sstevel@tonic-gate 	/* Convert the principal name to a netname */
599*0Sstevel@tonic-gate 	char *netname = (char *)pname;
600*0Sstevel@tonic-gate 	char host_netname[MAXNETNAMELEN+1];
601*0Sstevel@tonic-gate 
602*0Sstevel@tonic-gate 	if (pname == 0)
603*0Sstevel@tonic-gate 		return (GSS_S_BAD_NAME | GSS_S_CALL_INACCESSIBLE_READ);
604*0Sstevel@tonic-gate 	if (minor == 0 || uid == 0)
605*0Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
606*0Sstevel@tonic-gate 
607*0Sstevel@tonic-gate 	*minor = DH_SUCCESS;
608*0Sstevel@tonic-gate 	*uid = UID_NOBODY;
609*0Sstevel@tonic-gate 
610*0Sstevel@tonic-gate 	/* First try to convert as a user */
611*0Sstevel@tonic-gate 	if (netname2user(netname, uid, &gid, &glen, glist))
612*0Sstevel@tonic-gate 		return (GSS_S_COMPLETE);
613*0Sstevel@tonic-gate 	/* Get this hosts netname */
614*0Sstevel@tonic-gate 	else if (host2netname(host_netname, NULL, NULL)) {
615*0Sstevel@tonic-gate 		/*
616*0Sstevel@tonic-gate 		 * If the netname is this host's netname then we're root
617*0Sstevel@tonic-gate 		 * else we're nobody.
618*0Sstevel@tonic-gate 		 */
619*0Sstevel@tonic-gate 		if (strncmp(netname, host_netname, MAXNETNAMELEN) == 0)
620*0Sstevel@tonic-gate 			*uid = 0;
621*0Sstevel@tonic-gate 		return (GSS_S_COMPLETE);
622*0Sstevel@tonic-gate 	}
623*0Sstevel@tonic-gate 
624*0Sstevel@tonic-gate 	/* We could not get a netname */
625*0Sstevel@tonic-gate 	*minor = DH_NETNAME_FAILURE;
626*0Sstevel@tonic-gate 	return (GSS_S_FAILURE);
627*0Sstevel@tonic-gate }
628*0Sstevel@tonic-gate 
629*0Sstevel@tonic-gate /*
630*0Sstevel@tonic-gate  * __dh_gss_export_name: Diffie-Hellman support for gss_export_name.
631*0Sstevel@tonic-gate  * Given a Diffie-Hellman internal name return the GSS exported format.
632*0Sstevel@tonic-gate  */
633*0Sstevel@tonic-gate OM_uint32
__dh_gss_export_name(void * ctx,OM_uint32 * minor,const gss_name_t input_name,gss_buffer_t exported_name)634*0Sstevel@tonic-gate __dh_gss_export_name(void *ctx, /* Per mechanism context */
635*0Sstevel@tonic-gate 		    OM_uint32 *minor, /* Mechanism status */
636*0Sstevel@tonic-gate 		    const gss_name_t input_name, /* The name to export */
637*0Sstevel@tonic-gate 		    gss_buffer_t exported_name /* Exported name goes here */)
638*0Sstevel@tonic-gate {
639*0Sstevel@tonic-gate 	/* input_name is dh principal name */
640*0Sstevel@tonic-gate 	dh_principal pname = (dh_principal)input_name;
641*0Sstevel@tonic-gate 	dh_context_t dc = (dh_context_t)ctx;
642*0Sstevel@tonic-gate 	/* Magic for exported blobs */
643*0Sstevel@tonic-gate 	const char tokid[] = "\x04\x01";
644*0Sstevel@tonic-gate 	const int tokid_len = 2;
645*0Sstevel@tonic-gate 	const int OIDlen_len = 2; /* Why did they do this? */
646*0Sstevel@tonic-gate 	const int namelen_len = 4;
647*0Sstevel@tonic-gate 	const int mechoid_tag_len = 1;
648*0Sstevel@tonic-gate 	unsigned char *p;
649*0Sstevel@tonic-gate 	OM_uint32 len;
650*0Sstevel@tonic-gate 	OM_uint32 namelen;
651*0Sstevel@tonic-gate 	OM_uint32 currlen;
652*0Sstevel@tonic-gate 	OM_uint32 oid_der_len = 0;
653*0Sstevel@tonic-gate 
654*0Sstevel@tonic-gate 	if (minor == 0 || exported_name == GSS_C_NO_BUFFER)
655*0Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
656*0Sstevel@tonic-gate 	if (input_name == GSS_C_NO_NAME)
657*0Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_READ);
658*0Sstevel@tonic-gate 
659*0Sstevel@tonic-gate 	/* Set sane outputs */
660*0Sstevel@tonic-gate 	*minor = DH_SUCCESS;
661*0Sstevel@tonic-gate 	exported_name->length = 0;
662*0Sstevel@tonic-gate 	exported_name->value = NULL;
663*0Sstevel@tonic-gate 
664*0Sstevel@tonic-gate 	/* Determine the length of the name */
665*0Sstevel@tonic-gate 	namelen = OIDlen_len + __DH_GSS_C_NT_NETNAME->length
666*0Sstevel@tonic-gate 	    + strlen(pname)+1;
667*0Sstevel@tonic-gate 	oid_der_len = der_length_size(dc->mech->length);
668*0Sstevel@tonic-gate 	/* Find the total length */
669*0Sstevel@tonic-gate 	len = tokid_len + OIDlen_len + mechoid_tag_len + oid_der_len
670*0Sstevel@tonic-gate 		+ dc->mech->length + namelen_len + namelen;
671*0Sstevel@tonic-gate 
672*0Sstevel@tonic-gate 	/* Allocate the blob */
673*0Sstevel@tonic-gate 	p = New(unsigned char, len);
674*0Sstevel@tonic-gate 	if (p == NULL) {
675*0Sstevel@tonic-gate 		*minor = DH_NOMEM_FAILURE;
676*0Sstevel@tonic-gate 		return (GSS_S_FAILURE);
677*0Sstevel@tonic-gate 	}
678*0Sstevel@tonic-gate 	/* Set the blob to the exported name */
679*0Sstevel@tonic-gate 	exported_name->length = len;
680*0Sstevel@tonic-gate 	exported_name->value = p;
681*0Sstevel@tonic-gate 
682*0Sstevel@tonic-gate 	/* Start with some magic */
683*0Sstevel@tonic-gate 	memcpy(p, tokid, tokid_len);
684*0Sstevel@tonic-gate 	p += tokid_len;
685*0Sstevel@tonic-gate 
686*0Sstevel@tonic-gate 	/*
687*0Sstevel@tonic-gate 	 * The spec only allows two bytes for the oid length.
688*0Sstevel@tonic-gate 	 * We are assuming here that the correct encodeing is MSB first as
689*0Sstevel@tonic-gate 	 * was done in libgss.
690*0Sstevel@tonic-gate 	 */
691*0Sstevel@tonic-gate 
692*0Sstevel@tonic-gate 	*p++ = ((mechoid_tag_len + oid_der_len + dc->mech->length)
693*0Sstevel@tonic-gate 			& 0xff00) >> 8;
694*0Sstevel@tonic-gate 	*p++ = ((mechoid_tag_len + oid_der_len + dc->mech->length)
695*0Sstevel@tonic-gate 			& 0x00ff);
696*0Sstevel@tonic-gate 
697*0Sstevel@tonic-gate 	/* Now the mechanism OID DER Encoding */
698*0Sstevel@tonic-gate 	*p++ = 0x06; /* Universal Tag for OID */
699*0Sstevel@tonic-gate 	currlen = len - tokid_len - OIDlen_len - mechoid_tag_len;
700*0Sstevel@tonic-gate 	if (!put_der_length(dc->mech->length, &p, currlen) == 0) {
701*0Sstevel@tonic-gate 		return (GSS_S_FAILURE);
702*0Sstevel@tonic-gate 	}
703*0Sstevel@tonic-gate 
704*0Sstevel@tonic-gate 	/* Now the mechanism OID elements */
705*0Sstevel@tonic-gate 	memcpy(p, dc->mech->elements, dc->mech->length);
706*0Sstevel@tonic-gate 	p += dc->mech->length;
707*0Sstevel@tonic-gate 
708*0Sstevel@tonic-gate 	/* The name length most MSB first */
709*0Sstevel@tonic-gate 	*p++ = (namelen & 0xff000000) >> 24;
710*0Sstevel@tonic-gate 	*p++ = (namelen & 0x00ff0000) >> 16;
711*0Sstevel@tonic-gate 	*p++ = (namelen & 0x0000ff00) >> 8;
712*0Sstevel@tonic-gate 	*p++ = (namelen & 0x000000ff);
713*0Sstevel@tonic-gate 
714*0Sstevel@tonic-gate 	/*
715*0Sstevel@tonic-gate 	 * We'll now encode the netname oid. Again we'll just use 2 bytes.
716*0Sstevel@tonic-gate 	 * This is the same encoding that the libgss implementor uses, so
717*0Sstevel@tonic-gate 	 * we'll just follow along.
718*0Sstevel@tonic-gate 	 */
719*0Sstevel@tonic-gate 
720*0Sstevel@tonic-gate 	*p++ = (__DH_GSS_C_NT_NETNAME->length & 0xff00) >> 8;
721*0Sstevel@tonic-gate 	*p++ = (__DH_GSS_C_NT_NETNAME->length &0x00ff);
722*0Sstevel@tonic-gate 
723*0Sstevel@tonic-gate 	/* The netname oid values */
724*0Sstevel@tonic-gate 	memcpy(p, __DH_GSS_C_NT_NETNAME->elements,
725*0Sstevel@tonic-gate 	    __DH_GSS_C_NT_NETNAME->length);
726*0Sstevel@tonic-gate 
727*0Sstevel@tonic-gate 	p += __DH_GSS_C_NT_NETNAME->length;
728*0Sstevel@tonic-gate 
729*0Sstevel@tonic-gate 	/* Now we copy the netname including the null byte to be safe */
730*0Sstevel@tonic-gate 	memcpy(p, pname, strlen(pname) + 1);
731*0Sstevel@tonic-gate 
732*0Sstevel@tonic-gate 	return (GSS_S_COMPLETE);
733*0Sstevel@tonic-gate }
734*0Sstevel@tonic-gate 
735*0Sstevel@tonic-gate /*
736*0Sstevel@tonic-gate  * Support routine for __dh_internal_release_oid. Return True if
737*0Sstevel@tonic-gate  * the supplied OID points to the reference OID or if the elements
738*0Sstevel@tonic-gate  * of the reference OID are the same as the supplied OID. In the
739*0Sstevel@tonic-gate  * latter case, just free the OID container and set the pointer to it
740*0Sstevel@tonic-gate  * to GSS_C_NO_OID. Otherwise return false
741*0Sstevel@tonic-gate  */
742*0Sstevel@tonic-gate static int
release_oid(const gss_OID_desc * const ref,gss_OID * oid)743*0Sstevel@tonic-gate release_oid(const gss_OID_desc * const ref, gss_OID *oid)
744*0Sstevel@tonic-gate {
745*0Sstevel@tonic-gate 	gss_OID id = *oid;
746*0Sstevel@tonic-gate 
747*0Sstevel@tonic-gate 	if (id == ref)
748*0Sstevel@tonic-gate 		return (TRUE);
749*0Sstevel@tonic-gate 
750*0Sstevel@tonic-gate 	/*
751*0Sstevel@tonic-gate 	 * If some on create a shallow copy free, the structure point to
752*0Sstevel@tonic-gate 	 * id and set the pointer to it to GSS_C_NO_OID
753*0Sstevel@tonic-gate 	 */
754*0Sstevel@tonic-gate 	if (id->elements == ref->elements) {
755*0Sstevel@tonic-gate 		Free(id);
756*0Sstevel@tonic-gate 		*oid = GSS_C_NO_OID;
757*0Sstevel@tonic-gate 		return (TRUE);
758*0Sstevel@tonic-gate 	}
759*0Sstevel@tonic-gate 
760*0Sstevel@tonic-gate 	return (FALSE);
761*0Sstevel@tonic-gate }
762*0Sstevel@tonic-gate 
763*0Sstevel@tonic-gate /*
764*0Sstevel@tonic-gate  * __dh_gss_internal_release_oid: DH support for the gss_internal_relaese_oid
765*0Sstevel@tonic-gate  * entry. Check that the refence to an oid is one of our mechanisms static
766*0Sstevel@tonic-gate  * OIDS. If it is return true indicating to libgss that we have handled the
767*0Sstevel@tonic-gate  * release of that OID. Otherwise we return false and let libgss deal with it.
768*0Sstevel@tonic-gate  *
769*0Sstevel@tonic-gate  * The only OIDS we know are the calling mechanism found in the context
770*0Sstevel@tonic-gate  * and the shared DH_GSS_C_NT_NETNAME name type
771*0Sstevel@tonic-gate  */
772*0Sstevel@tonic-gate OM_uint32
__dh_gss_internal_release_oid(void * ctx,OM_uint32 * minor,gss_OID * oid)773*0Sstevel@tonic-gate __dh_gss_internal_release_oid(void *ctx, OM_uint32 *minor, gss_OID *oid)
774*0Sstevel@tonic-gate {
775*0Sstevel@tonic-gate 	dh_context_t dhcxt = (dh_context_t)ctx;
776*0Sstevel@tonic-gate 
777*0Sstevel@tonic-gate 	if (minor == 0)
778*0Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
779*0Sstevel@tonic-gate 
780*0Sstevel@tonic-gate 	*minor = DH_SUCCESS;
781*0Sstevel@tonic-gate 
782*0Sstevel@tonic-gate 	if (oid == NULL || *oid == NULL)
783*0Sstevel@tonic-gate 		return (GSS_S_COMPLETE);
784*0Sstevel@tonic-gate 
785*0Sstevel@tonic-gate 	if (release_oid(dhcxt->mech, oid))
786*0Sstevel@tonic-gate 		return (GSS_S_COMPLETE);
787*0Sstevel@tonic-gate 
788*0Sstevel@tonic-gate 	if (release_oid(__DH_GSS_C_NT_NETNAME, oid))
789*0Sstevel@tonic-gate 		return (GSS_S_COMPLETE);
790*0Sstevel@tonic-gate 
791*0Sstevel@tonic-gate 	return (GSS_S_FAILURE);
792*0Sstevel@tonic-gate }
793