xref: /illumos-gate/usr/src/lib/libgss/g_glue.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <mechglueP.h>
30*7c478bd9Sstevel@tonic-gate #include <stdio.h>
31*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
32*7c478bd9Sstevel@tonic-gate #include <strings.h>
33*7c478bd9Sstevel@tonic-gate #include <errno.h>
34*7c478bd9Sstevel@tonic-gate 
35*7c478bd9Sstevel@tonic-gate #define	MSO_BIT (8*(sizeof (int) - 1))  /* Most significant octet bit */
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate /*
38*7c478bd9Sstevel@tonic-gate  * This file contains the support routines for the glue layer.
39*7c478bd9Sstevel@tonic-gate  */
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate /*
42*7c478bd9Sstevel@tonic-gate  * get_der_length: Givin a pointer to a buffer that contains a DER encoded
43*7c478bd9Sstevel@tonic-gate  * length, decode the length updating the buffer to point to the character
44*7c478bd9Sstevel@tonic-gate  * after the DER encoding. The parameter bytes will point to the number of
45*7c478bd9Sstevel@tonic-gate  * bytes that made up the DER encoding of the length originally pointed to
46*7c478bd9Sstevel@tonic-gate  * by the buffer. Note we return -1 on error.
47*7c478bd9Sstevel@tonic-gate  */
48*7c478bd9Sstevel@tonic-gate int
49*7c478bd9Sstevel@tonic-gate get_der_length(unsigned char **buf, unsigned int buf_len, unsigned int *bytes)
50*7c478bd9Sstevel@tonic-gate {
51*7c478bd9Sstevel@tonic-gate 	/* p points to the beginning of the buffer */
52*7c478bd9Sstevel@tonic-gate 	unsigned char *p = *buf;
53*7c478bd9Sstevel@tonic-gate 	int length, new_length;
54*7c478bd9Sstevel@tonic-gate 	int octets;
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate 	if (buf_len < 1)
57*7c478bd9Sstevel@tonic-gate 		return (-1);
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate 	/* We should have at least one byte */
60*7c478bd9Sstevel@tonic-gate 	*bytes = 1;
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate 	/*
63*7c478bd9Sstevel@tonic-gate 	 * If the High order bit is not set then the length is just the value
64*7c478bd9Sstevel@tonic-gate 	 * of *p.
65*7c478bd9Sstevel@tonic-gate 	 */
66*7c478bd9Sstevel@tonic-gate 	if (*p < 128) {
67*7c478bd9Sstevel@tonic-gate 		*buf = p+1;	/* Advance the buffer */
68*7c478bd9Sstevel@tonic-gate 	return (*p);		/* return the length */
69*7c478bd9Sstevel@tonic-gate 	}
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate 	/*
72*7c478bd9Sstevel@tonic-gate 	 * if the High order bit is set, then the low order bits represent
73*7c478bd9Sstevel@tonic-gate 	 * the number of bytes that contain the DER encoding of the length.
74*7c478bd9Sstevel@tonic-gate 	 */
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate 	octets = *p++ & 0x7f;
77*7c478bd9Sstevel@tonic-gate 	*bytes += octets;
78*7c478bd9Sstevel@tonic-gate 
79*7c478bd9Sstevel@tonic-gate 	/* See if the supplied buffer contains enough bytes for the length. */
80*7c478bd9Sstevel@tonic-gate 	if (octets > buf_len - 1)
81*7c478bd9Sstevel@tonic-gate 		return (-1);
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate 	/*
84*7c478bd9Sstevel@tonic-gate 	 * Calculate a multibyte length. The length is encoded as an
85*7c478bd9Sstevel@tonic-gate 	 * unsigned integer base 256.
86*7c478bd9Sstevel@tonic-gate 	 */
87*7c478bd9Sstevel@tonic-gate 	for (length = 0; octets; octets--) {
88*7c478bd9Sstevel@tonic-gate 		new_length = (length << 8) + *p++;
89*7c478bd9Sstevel@tonic-gate 		if (new_length < length)  /* overflow */
90*7c478bd9Sstevel@tonic-gate 			return (-1);
91*7c478bd9Sstevel@tonic-gate 		length = new_length;
92*7c478bd9Sstevel@tonic-gate 	}
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate 	*buf = p; /* Advance the buffer */
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate 	return (length);
97*7c478bd9Sstevel@tonic-gate }
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate /*
100*7c478bd9Sstevel@tonic-gate  * der_length_size: Return the number of bytes to encode a given length.
101*7c478bd9Sstevel@tonic-gate  */
102*7c478bd9Sstevel@tonic-gate unsigned int
103*7c478bd9Sstevel@tonic-gate der_length_size(unsigned int len)
104*7c478bd9Sstevel@tonic-gate {
105*7c478bd9Sstevel@tonic-gate 	int i;
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate 	if (len < 128)
108*7c478bd9Sstevel@tonic-gate 		return (1);
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate 	for (i = 0; len; i++) {
111*7c478bd9Sstevel@tonic-gate 		len >>= 8;
112*7c478bd9Sstevel@tonic-gate 	}
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate 	return (i+1);
115*7c478bd9Sstevel@tonic-gate }
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate /*
118*7c478bd9Sstevel@tonic-gate  * put_der_length: Encode the supplied length into the buffer pointed to
119*7c478bd9Sstevel@tonic-gate  * by buf. max_length represents the maximum length of the buffer pointed
120*7c478bd9Sstevel@tonic-gate  * to by buff. We will advance buf to point to the character after the newly
121*7c478bd9Sstevel@tonic-gate  * DER encoded length. We return 0 on success or -l it the length cannot
122*7c478bd9Sstevel@tonic-gate  * be encoded in max_len characters.
123*7c478bd9Sstevel@tonic-gate  */
124*7c478bd9Sstevel@tonic-gate int
125*7c478bd9Sstevel@tonic-gate put_der_length(unsigned length, unsigned char **buf, unsigned int max_len)
126*7c478bd9Sstevel@tonic-gate {
127*7c478bd9Sstevel@tonic-gate 	unsigned char *s = *buf, *p;
128*7c478bd9Sstevel@tonic-gate 	unsigned int buf_len = 0;
129*7c478bd9Sstevel@tonic-gate 	int i, first;
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate 	/* Oops */
132*7c478bd9Sstevel@tonic-gate 	if (buf == 0 || max_len < 1)
133*7c478bd9Sstevel@tonic-gate 		return (-1);
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate 	/* Single byte is the length */
136*7c478bd9Sstevel@tonic-gate 	if (length < 128) {
137*7c478bd9Sstevel@tonic-gate 		*s++ = length;
138*7c478bd9Sstevel@tonic-gate 		*buf = s;
139*7c478bd9Sstevel@tonic-gate 		return (0);
140*7c478bd9Sstevel@tonic-gate 	}
141*7c478bd9Sstevel@tonic-gate 
142*7c478bd9Sstevel@tonic-gate 	/* First byte contains the number of octets */
143*7c478bd9Sstevel@tonic-gate 	p = s + 1;
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate 	/* Running total of the DER encoding length */
146*7c478bd9Sstevel@tonic-gate 	buf_len = 0;
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate 	/*
149*7c478bd9Sstevel@tonic-gate 	 * Encode MSB first. We do the encoding by setting a shift
150*7c478bd9Sstevel@tonic-gate 	 * factor to MSO_BIT (24 for 32 bit words) and then shifting the length
151*7c478bd9Sstevel@tonic-gate 	 * by the factor. We then encode the resulting low order byte.
152*7c478bd9Sstevel@tonic-gate 	 * We subtract 8 from the shift factor and repeat to ecnode the next
153*7c478bd9Sstevel@tonic-gate 	 * byte. We stop when the shift factor is zero or we've run out of
154*7c478bd9Sstevel@tonic-gate 	 * buffer to encode into.
155*7c478bd9Sstevel@tonic-gate 	 */
156*7c478bd9Sstevel@tonic-gate 	first = 0;
157*7c478bd9Sstevel@tonic-gate 	for (i = MSO_BIT; i >= 0 && buf_len <= max_len; i -= 8) {
158*7c478bd9Sstevel@tonic-gate 		unsigned int v;
159*7c478bd9Sstevel@tonic-gate 		v = (length >> i) & 0xff;
160*7c478bd9Sstevel@tonic-gate 		if ((v) || first) {
161*7c478bd9Sstevel@tonic-gate 			buf_len += 1;
162*7c478bd9Sstevel@tonic-gate 			*p++ = v;
163*7c478bd9Sstevel@tonic-gate 			first = 1;
164*7c478bd9Sstevel@tonic-gate 		}
165*7c478bd9Sstevel@tonic-gate 	}
166*7c478bd9Sstevel@tonic-gate 	if (i >= 0)			/* buffer overflow */
167*7c478bd9Sstevel@tonic-gate 		return (-1);
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 	/*
170*7c478bd9Sstevel@tonic-gate 	 * We go back now and set the first byte to be the length with
171*7c478bd9Sstevel@tonic-gate 	 * the high order bit set.
172*7c478bd9Sstevel@tonic-gate 	 */
173*7c478bd9Sstevel@tonic-gate 	*s = buf_len | 0x80;
174*7c478bd9Sstevel@tonic-gate 	*buf = p;
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate 	return (0);
177*7c478bd9Sstevel@tonic-gate }
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate /*
181*7c478bd9Sstevel@tonic-gate  *  glue routine for get_mech_type
182*7c478bd9Sstevel@tonic-gate  *
183*7c478bd9Sstevel@tonic-gate  */
184*7c478bd9Sstevel@tonic-gate OM_uint32
185*7c478bd9Sstevel@tonic-gate __gss_get_mech_type(OID, token)
186*7c478bd9Sstevel@tonic-gate 	gss_OID			OID;
187*7c478bd9Sstevel@tonic-gate 	const gss_buffer_t	token;
188*7c478bd9Sstevel@tonic-gate {
189*7c478bd9Sstevel@tonic-gate 	unsigned char *buffer_ptr;
190*7c478bd9Sstevel@tonic-gate 	int length;
191*7c478bd9Sstevel@tonic-gate 
192*7c478bd9Sstevel@tonic-gate 	/*
193*7c478bd9Sstevel@tonic-gate 	 * This routine reads the prefix of "token" in order to determine
194*7c478bd9Sstevel@tonic-gate 	 * its mechanism type. It assumes the encoding suggested in
195*7c478bd9Sstevel@tonic-gate 	 * Appendix B of RFC 1508. This format starts out as follows :
196*7c478bd9Sstevel@tonic-gate 	 *
197*7c478bd9Sstevel@tonic-gate 	 * tag for APPLICATION 0, Sequence[constructed, definite length]
198*7c478bd9Sstevel@tonic-gate 	 * length of remainder of token
199*7c478bd9Sstevel@tonic-gate 	 * tag of OBJECT IDENTIFIER
200*7c478bd9Sstevel@tonic-gate 	 * length of mechanism OID
201*7c478bd9Sstevel@tonic-gate 	 * encoding of mechanism OID
202*7c478bd9Sstevel@tonic-gate 	 * <the rest of the token>
203*7c478bd9Sstevel@tonic-gate 	 *
204*7c478bd9Sstevel@tonic-gate 	 * Numerically, this looks like :
205*7c478bd9Sstevel@tonic-gate 	 *
206*7c478bd9Sstevel@tonic-gate 	 * 0x60
207*7c478bd9Sstevel@tonic-gate 	 * <length> - could be multiple bytes
208*7c478bd9Sstevel@tonic-gate 	 * 0x06
209*7c478bd9Sstevel@tonic-gate 	 * <length> - assume only one byte, hence OID length < 127
210*7c478bd9Sstevel@tonic-gate 	 * <mech OID bytes>
211*7c478bd9Sstevel@tonic-gate 	 *
212*7c478bd9Sstevel@tonic-gate 	 * The routine fills in the OID value and returns an error as necessary.
213*7c478bd9Sstevel@tonic-gate 	 */
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate 	if (OID == NULL)
216*7c478bd9Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate 	if ((token == NULL) || (token->value == NULL))
219*7c478bd9Sstevel@tonic-gate 		return (GSS_S_DEFECTIVE_TOKEN);
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate 	/* Skip past the APP/Sequnce byte and the token length */
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate 	buffer_ptr = (unsigned char *) token->value;
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 	if (*(buffer_ptr++) != 0x60)
226*7c478bd9Sstevel@tonic-gate 		return (GSS_S_DEFECTIVE_TOKEN);
227*7c478bd9Sstevel@tonic-gate 	length = *buffer_ptr++;
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate 	/* check if token length is null */
230*7c478bd9Sstevel@tonic-gate 	if (length == 0)
231*7c478bd9Sstevel@tonic-gate 	    return (GSS_S_DEFECTIVE_TOKEN);
232*7c478bd9Sstevel@tonic-gate 
233*7c478bd9Sstevel@tonic-gate 	if (length & 0x80) {
234*7c478bd9Sstevel@tonic-gate 		if ((length & 0x7f) > 4)
235*7c478bd9Sstevel@tonic-gate 			return (GSS_S_DEFECTIVE_TOKEN);
236*7c478bd9Sstevel@tonic-gate 		buffer_ptr += length & 0x7f;
237*7c478bd9Sstevel@tonic-gate 	}
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate 	if (*(buffer_ptr++) != 0x06)
240*7c478bd9Sstevel@tonic-gate 		return (GSS_S_DEFECTIVE_TOKEN);
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate 	OID->length = (OM_uint32) *(buffer_ptr++);
243*7c478bd9Sstevel@tonic-gate 	OID->elements = (void *) buffer_ptr;
244*7c478bd9Sstevel@tonic-gate 	return (GSS_S_COMPLETE);
245*7c478bd9Sstevel@tonic-gate }
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate 
248*7c478bd9Sstevel@tonic-gate /*
249*7c478bd9Sstevel@tonic-gate  *  Internal routines to get and release an internal mechanism name
250*7c478bd9Sstevel@tonic-gate  */
251*7c478bd9Sstevel@tonic-gate OM_uint32 __gss_import_internal_name(minor_status, mech_type, union_name,
252*7c478bd9Sstevel@tonic-gate 					internal_name)
253*7c478bd9Sstevel@tonic-gate OM_uint32		*minor_status;
254*7c478bd9Sstevel@tonic-gate const gss_OID		mech_type;
255*7c478bd9Sstevel@tonic-gate gss_union_name_t	union_name;
256*7c478bd9Sstevel@tonic-gate gss_name_t		*internal_name;
257*7c478bd9Sstevel@tonic-gate {
258*7c478bd9Sstevel@tonic-gate 	OM_uint32			status;
259*7c478bd9Sstevel@tonic-gate 	gss_mechanism		mech;
260*7c478bd9Sstevel@tonic-gate 
261*7c478bd9Sstevel@tonic-gate 	mech = __gss_get_mechanism(mech_type);
262*7c478bd9Sstevel@tonic-gate 	if (mech) {
263*7c478bd9Sstevel@tonic-gate 		if (mech->gss_import_name)
264*7c478bd9Sstevel@tonic-gate 			status = mech->gss_import_name(
265*7c478bd9Sstevel@tonic-gate 						mech->context,
266*7c478bd9Sstevel@tonic-gate 						minor_status,
267*7c478bd9Sstevel@tonic-gate 						union_name->external_name,
268*7c478bd9Sstevel@tonic-gate 						union_name->name_type,
269*7c478bd9Sstevel@tonic-gate 						internal_name);
270*7c478bd9Sstevel@tonic-gate 		else
271*7c478bd9Sstevel@tonic-gate 			status = GSS_S_UNAVAILABLE;
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate 		return (status);
274*7c478bd9Sstevel@tonic-gate 	}
275*7c478bd9Sstevel@tonic-gate 
276*7c478bd9Sstevel@tonic-gate 	return (GSS_S_BAD_MECH);
277*7c478bd9Sstevel@tonic-gate }
278*7c478bd9Sstevel@tonic-gate 
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate OM_uint32 __gss_export_internal_name(minor_status, mech_type,
281*7c478bd9Sstevel@tonic-gate 		internal_name, name_buf)
282*7c478bd9Sstevel@tonic-gate OM_uint32		*minor_status;
283*7c478bd9Sstevel@tonic-gate const gss_OID		mech_type;
284*7c478bd9Sstevel@tonic-gate const gss_name_t	internal_name;
285*7c478bd9Sstevel@tonic-gate gss_buffer_t		name_buf;
286*7c478bd9Sstevel@tonic-gate {
287*7c478bd9Sstevel@tonic-gate 	OM_uint32 status;
288*7c478bd9Sstevel@tonic-gate 	gss_mechanism mech;
289*7c478bd9Sstevel@tonic-gate 	gss_buffer_desc dispName;
290*7c478bd9Sstevel@tonic-gate 	gss_OID nameOid;
291*7c478bd9Sstevel@tonic-gate 	unsigned char *buf = NULL;
292*7c478bd9Sstevel@tonic-gate 	const unsigned char tokId[] = "\x04\x01";
293*7c478bd9Sstevel@tonic-gate 	const int tokIdLen = 2;
294*7c478bd9Sstevel@tonic-gate 	const int mechOidLenLen = 2, mechOidTagLen = 1, nameLenLen = 4;
295*7c478bd9Sstevel@tonic-gate 	int mechOidDERLen = 0;
296*7c478bd9Sstevel@tonic-gate 	int mechOidLen = 0;
297*7c478bd9Sstevel@tonic-gate 
298*7c478bd9Sstevel@tonic-gate 	mech = __gss_get_mechanism(mech_type);
299*7c478bd9Sstevel@tonic-gate 	if (!mech)
300*7c478bd9Sstevel@tonic-gate 		return (GSS_S_BAD_MECH);
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate 	if (mech->gss_export_name)
303*7c478bd9Sstevel@tonic-gate 		return (mech->gss_export_name(mech->context,
304*7c478bd9Sstevel@tonic-gate 						minor_status,
305*7c478bd9Sstevel@tonic-gate 						internal_name,
306*7c478bd9Sstevel@tonic-gate 						name_buf));
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate 	/*
309*7c478bd9Sstevel@tonic-gate 	 * if we are here it is because the mechanism does not provide
310*7c478bd9Sstevel@tonic-gate 	 * a gss_export_name so we will use our implementation.  We
311*7c478bd9Sstevel@tonic-gate 	 * do required that the mechanism define a gss_display_name.
312*7c478bd9Sstevel@tonic-gate 	 */
313*7c478bd9Sstevel@tonic-gate 	if (!mech->gss_display_name)
314*7c478bd9Sstevel@tonic-gate 		return (GSS_S_UNAVAILABLE);
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 	/*
317*7c478bd9Sstevel@tonic-gate 	 * NOTE: RFC2743 (section 3.2) governs the format of the outer
318*7c478bd9Sstevel@tonic-gate 	 *	 wrapper of exported names; the mechanisms' specs govern
319*7c478bd9Sstevel@tonic-gate 	 *	 the format of the inner portion of the exported name
320*7c478bd9Sstevel@tonic-gate 	 *	 and, for some (e.g., RFC1964, the Kerberos V mech), a
321*7c478bd9Sstevel@tonic-gate 	 *	 generic default as implemented here will do.
322*7c478bd9Sstevel@tonic-gate 	 *
323*7c478bd9Sstevel@tonic-gate 	 * The outer wrapper of an exported MN is: 2-octet tok Id
324*7c478bd9Sstevel@tonic-gate 	 * (0x0401) + 2-octet network-byte order mech OID length + mech
325*7c478bd9Sstevel@tonic-gate 	 * oid (in DER format, including DER tag and DER length) +
326*7c478bd9Sstevel@tonic-gate 	 * 4-octet network-byte order length of inner portion + inner
327*7c478bd9Sstevel@tonic-gate 	 * portion.
328*7c478bd9Sstevel@tonic-gate 	 *
329*7c478bd9Sstevel@tonic-gate 	 * For the Kerberos V mechanism the inner portion of an exported
330*7c478bd9Sstevel@tonic-gate 	 * MN is the display name string and ignores the name type OID
331*7c478bd9Sstevel@tonic-gate 	 * altogether.  And we hope this will be so for any future
332*7c478bd9Sstevel@tonic-gate 	 * mechanisms also, so that factoring name export/import out of
333*7c478bd9Sstevel@tonic-gate 	 * the mech and into libgss pays off.
334*7c478bd9Sstevel@tonic-gate 	 */
335*7c478bd9Sstevel@tonic-gate 	if ((status = mech->gss_display_name(mech->context,
336*7c478bd9Sstevel@tonic-gate 						minor_status,
337*7c478bd9Sstevel@tonic-gate 						internal_name,
338*7c478bd9Sstevel@tonic-gate 						&dispName,
339*7c478bd9Sstevel@tonic-gate 						&nameOid))
340*7c478bd9Sstevel@tonic-gate 						!= GSS_S_COMPLETE)
341*7c478bd9Sstevel@tonic-gate 		return (status);
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate 	/* determine the size of the buffer needed */
344*7c478bd9Sstevel@tonic-gate 	mechOidDERLen = der_length_size(mech_type->length);
345*7c478bd9Sstevel@tonic-gate 	name_buf->length = tokIdLen + mechOidLenLen +
346*7c478bd9Sstevel@tonic-gate 				mechOidTagLen + mechOidDERLen +
347*7c478bd9Sstevel@tonic-gate 				mech_type->length +
348*7c478bd9Sstevel@tonic-gate 				nameLenLen + dispName.length;
349*7c478bd9Sstevel@tonic-gate 	if ((name_buf->value = (void*)malloc(name_buf->length)) ==
350*7c478bd9Sstevel@tonic-gate 		(void*)NULL) {
351*7c478bd9Sstevel@tonic-gate 			name_buf->length = 0;
352*7c478bd9Sstevel@tonic-gate 			(void) gss_release_buffer(&status, &dispName);
353*7c478bd9Sstevel@tonic-gate 			return (GSS_S_FAILURE);
354*7c478bd9Sstevel@tonic-gate 	}
355*7c478bd9Sstevel@tonic-gate 
356*7c478bd9Sstevel@tonic-gate 	/* now create the name ..... */
357*7c478bd9Sstevel@tonic-gate 	buf = (unsigned char *)name_buf->value;
358*7c478bd9Sstevel@tonic-gate 	(void) memset(name_buf->value, 0, name_buf->length);
359*7c478bd9Sstevel@tonic-gate 	(void) memcpy(buf, tokId, tokIdLen);
360*7c478bd9Sstevel@tonic-gate 	buf += tokIdLen;
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate 	/* spec allows only 2 bytes for the mech oid length */
363*7c478bd9Sstevel@tonic-gate 	mechOidLen = mechOidDERLen + mechOidTagLen + mech_type->length;
364*7c478bd9Sstevel@tonic-gate 	*buf++ = (mechOidLen & 0xFF00) >> 8;
365*7c478bd9Sstevel@tonic-gate 	*buf++ = (mechOidLen & 0x00FF);
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate 	/*
368*7c478bd9Sstevel@tonic-gate 	 * DER Encoding of mech OID contains OID Tag (0x06), length and
369*7c478bd9Sstevel@tonic-gate 	 * mech OID value
370*7c478bd9Sstevel@tonic-gate 	 */
371*7c478bd9Sstevel@tonic-gate 	*buf++ = 0x06;
372*7c478bd9Sstevel@tonic-gate 	if (put_der_length(mech_type->length, &buf,
373*7c478bd9Sstevel@tonic-gate 		(name_buf->length - tokIdLen -2)) != 0) {
374*7c478bd9Sstevel@tonic-gate 		name_buf->length = 0;
375*7c478bd9Sstevel@tonic-gate 		free(name_buf->value);
376*7c478bd9Sstevel@tonic-gate 		(void) gss_release_buffer(&status, &dispName);
377*7c478bd9Sstevel@tonic-gate 		return (GSS_S_FAILURE);
378*7c478bd9Sstevel@tonic-gate 	}
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate 	(void) memcpy(buf, mech_type->elements, mech_type->length);
381*7c478bd9Sstevel@tonic-gate 	buf += mech_type->length;
382*7c478bd9Sstevel@tonic-gate 
383*7c478bd9Sstevel@tonic-gate 	/* spec designates the next 4 bytes for the name length */
384*7c478bd9Sstevel@tonic-gate 	*buf++ = (dispName.length & 0xFF000000) >> 24;
385*7c478bd9Sstevel@tonic-gate 	*buf++ = (dispName.length & 0x00FF0000) >> 16;
386*7c478bd9Sstevel@tonic-gate 	*buf++ = (dispName.length & 0x0000FF00) >> 8;
387*7c478bd9Sstevel@tonic-gate 	*buf++ = (dispName.length & 0X000000FF);
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 	/* for the final ingredient - add the name from gss_display_name */
390*7c478bd9Sstevel@tonic-gate 	(void) memcpy(buf, dispName.value, dispName.length);
391*7c478bd9Sstevel@tonic-gate 
392*7c478bd9Sstevel@tonic-gate 	/* release the buffer obtained from gss_display_name */
393*7c478bd9Sstevel@tonic-gate 	(void) gss_release_buffer(minor_status, &dispName);
394*7c478bd9Sstevel@tonic-gate 	return (GSS_S_COMPLETE);
395*7c478bd9Sstevel@tonic-gate } /*  __gss_export_internal_name */
396*7c478bd9Sstevel@tonic-gate 
397*7c478bd9Sstevel@tonic-gate 
398*7c478bd9Sstevel@tonic-gate OM_uint32 __gss_display_internal_name(minor_status, mech_type, internal_name,
399*7c478bd9Sstevel@tonic-gate 						external_name, name_type)
400*7c478bd9Sstevel@tonic-gate OM_uint32		*minor_status;
401*7c478bd9Sstevel@tonic-gate const gss_OID		mech_type;
402*7c478bd9Sstevel@tonic-gate const gss_name_t	internal_name;
403*7c478bd9Sstevel@tonic-gate gss_buffer_t		external_name;
404*7c478bd9Sstevel@tonic-gate gss_OID			*name_type;
405*7c478bd9Sstevel@tonic-gate {
406*7c478bd9Sstevel@tonic-gate 	OM_uint32			status;
407*7c478bd9Sstevel@tonic-gate 	gss_mechanism		mech;
408*7c478bd9Sstevel@tonic-gate 
409*7c478bd9Sstevel@tonic-gate 	mech = __gss_get_mechanism(mech_type);
410*7c478bd9Sstevel@tonic-gate 	if (mech) {
411*7c478bd9Sstevel@tonic-gate 		if (mech->gss_display_name)
412*7c478bd9Sstevel@tonic-gate 			status = mech->gss_display_name(
413*7c478bd9Sstevel@tonic-gate 							mech->context,
414*7c478bd9Sstevel@tonic-gate 							minor_status,
415*7c478bd9Sstevel@tonic-gate 							internal_name,
416*7c478bd9Sstevel@tonic-gate 							external_name,
417*7c478bd9Sstevel@tonic-gate 							name_type);
418*7c478bd9Sstevel@tonic-gate 		else
419*7c478bd9Sstevel@tonic-gate 			status = GSS_S_UNAVAILABLE;
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate 		return (status);
422*7c478bd9Sstevel@tonic-gate 	}
423*7c478bd9Sstevel@tonic-gate 
424*7c478bd9Sstevel@tonic-gate 	return (GSS_S_BAD_MECH);
425*7c478bd9Sstevel@tonic-gate }
426*7c478bd9Sstevel@tonic-gate 
427*7c478bd9Sstevel@tonic-gate OM_uint32
428*7c478bd9Sstevel@tonic-gate __gss_release_internal_name(minor_status, mech_type, internal_name)
429*7c478bd9Sstevel@tonic-gate OM_uint32		*minor_status;
430*7c478bd9Sstevel@tonic-gate const gss_OID		mech_type;
431*7c478bd9Sstevel@tonic-gate gss_name_t		*internal_name;
432*7c478bd9Sstevel@tonic-gate {
433*7c478bd9Sstevel@tonic-gate 	OM_uint32			status;
434*7c478bd9Sstevel@tonic-gate 	gss_mechanism		mech;
435*7c478bd9Sstevel@tonic-gate 
436*7c478bd9Sstevel@tonic-gate 	mech = __gss_get_mechanism(mech_type);
437*7c478bd9Sstevel@tonic-gate 	if (mech) {
438*7c478bd9Sstevel@tonic-gate 		if (mech->gss_release_name)
439*7c478bd9Sstevel@tonic-gate 			status = mech->gss_release_name(
440*7c478bd9Sstevel@tonic-gate 							mech->context,
441*7c478bd9Sstevel@tonic-gate 							minor_status,
442*7c478bd9Sstevel@tonic-gate 							internal_name);
443*7c478bd9Sstevel@tonic-gate 		else
444*7c478bd9Sstevel@tonic-gate 			status = GSS_S_UNAVAILABLE;
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate 		return (status);
447*7c478bd9Sstevel@tonic-gate 	}
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate 	return (GSS_S_BAD_MECH);
450*7c478bd9Sstevel@tonic-gate }
451*7c478bd9Sstevel@tonic-gate 
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate /*
454*7c478bd9Sstevel@tonic-gate  * This function converts an internal gssapi name to a union gssapi
455*7c478bd9Sstevel@tonic-gate  * name.  Note that internal_name should be considered "consumed" by
456*7c478bd9Sstevel@tonic-gate  * this call, whether or not we return an error.
457*7c478bd9Sstevel@tonic-gate  */
458*7c478bd9Sstevel@tonic-gate OM_uint32 __gss_convert_name_to_union_name(minor_status, mech,
459*7c478bd9Sstevel@tonic-gate 						internal_name, external_name)
460*7c478bd9Sstevel@tonic-gate 	OM_uint32 *minor_status;
461*7c478bd9Sstevel@tonic-gate 	gss_mechanism		mech;
462*7c478bd9Sstevel@tonic-gate 	gss_name_t		internal_name;
463*7c478bd9Sstevel@tonic-gate 	gss_name_t		*external_name;
464*7c478bd9Sstevel@tonic-gate {
465*7c478bd9Sstevel@tonic-gate 	OM_uint32 major_status, tmp;
466*7c478bd9Sstevel@tonic-gate 	gss_union_name_t union_name;
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate 	union_name = (gss_union_name_t)malloc(sizeof (gss_union_name_desc));
469*7c478bd9Sstevel@tonic-gate 	if (!union_name) {
470*7c478bd9Sstevel@tonic-gate 			goto allocation_failure;
471*7c478bd9Sstevel@tonic-gate 	}
472*7c478bd9Sstevel@tonic-gate 	union_name->mech_type = 0;
473*7c478bd9Sstevel@tonic-gate 	union_name->mech_name = internal_name;
474*7c478bd9Sstevel@tonic-gate 	union_name->name_type = 0;
475*7c478bd9Sstevel@tonic-gate 	union_name->external_name = 0;
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate 	major_status = generic_gss_copy_oid(minor_status, &mech->mech_type,
478*7c478bd9Sstevel@tonic-gate 						&union_name->mech_type);
479*7c478bd9Sstevel@tonic-gate 	if (major_status != GSS_S_COMPLETE)
480*7c478bd9Sstevel@tonic-gate 		goto allocation_failure;
481*7c478bd9Sstevel@tonic-gate 
482*7c478bd9Sstevel@tonic-gate 	union_name->external_name =
483*7c478bd9Sstevel@tonic-gate 		(gss_buffer_t)malloc(sizeof (gss_buffer_desc));
484*7c478bd9Sstevel@tonic-gate 	if (!union_name->external_name) {
485*7c478bd9Sstevel@tonic-gate 			goto allocation_failure;
486*7c478bd9Sstevel@tonic-gate 	}
487*7c478bd9Sstevel@tonic-gate 
488*7c478bd9Sstevel@tonic-gate 	major_status = mech->gss_display_name(mech->context, minor_status,
489*7c478bd9Sstevel@tonic-gate 						internal_name,
490*7c478bd9Sstevel@tonic-gate 						union_name->external_name,
491*7c478bd9Sstevel@tonic-gate 						&union_name->name_type);
492*7c478bd9Sstevel@tonic-gate 	if (major_status != GSS_S_COMPLETE)
493*7c478bd9Sstevel@tonic-gate 		goto allocation_failure;
494*7c478bd9Sstevel@tonic-gate 
495*7c478bd9Sstevel@tonic-gate 	*external_name =  (gss_name_t)union_name;
496*7c478bd9Sstevel@tonic-gate 	return (GSS_S_COMPLETE);
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate allocation_failure:
499*7c478bd9Sstevel@tonic-gate 	if (union_name) {
500*7c478bd9Sstevel@tonic-gate 		if (union_name->external_name) {
501*7c478bd9Sstevel@tonic-gate 			if (union_name->external_name->value)
502*7c478bd9Sstevel@tonic-gate 				free(union_name->external_name->value);
503*7c478bd9Sstevel@tonic-gate 			free(union_name->external_name);
504*7c478bd9Sstevel@tonic-gate 		}
505*7c478bd9Sstevel@tonic-gate 		if (union_name->name_type)
506*7c478bd9Sstevel@tonic-gate 			(void) gss_release_oid(&tmp, &union_name->name_type);
507*7c478bd9Sstevel@tonic-gate 		if (union_name->mech_type)
508*7c478bd9Sstevel@tonic-gate 			(void) gss_release_oid(&tmp, &union_name->mech_type);
509*7c478bd9Sstevel@tonic-gate 		free(union_name);
510*7c478bd9Sstevel@tonic-gate 	}
511*7c478bd9Sstevel@tonic-gate 	/*
512*7c478bd9Sstevel@tonic-gate 	 * do as the top comment says - since we are now owners of
513*7c478bd9Sstevel@tonic-gate 	 * internal_name, we must clean it up
514*7c478bd9Sstevel@tonic-gate 	 */
515*7c478bd9Sstevel@tonic-gate 	if (internal_name)
516*7c478bd9Sstevel@tonic-gate 		(void) __gss_release_internal_name(&tmp, &mech->mech_type,
517*7c478bd9Sstevel@tonic-gate 						&internal_name);
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate 	return (major_status);
520*7c478bd9Sstevel@tonic-gate }
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate /*
523*7c478bd9Sstevel@tonic-gate  * Glue routine for returning the mechanism-specific credential from a
524*7c478bd9Sstevel@tonic-gate  * external union credential.
525*7c478bd9Sstevel@tonic-gate  */
526*7c478bd9Sstevel@tonic-gate gss_cred_id_t
527*7c478bd9Sstevel@tonic-gate __gss_get_mechanism_cred(union_cred, mech_type)
528*7c478bd9Sstevel@tonic-gate 	const gss_union_cred_t	union_cred;
529*7c478bd9Sstevel@tonic-gate 	const gss_OID		mech_type;
530*7c478bd9Sstevel@tonic-gate {
531*7c478bd9Sstevel@tonic-gate 	int			i;
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate 	if (union_cred == (gss_union_cred_t)GSS_C_NO_CREDENTIAL)
534*7c478bd9Sstevel@tonic-gate 		return (GSS_C_NO_CREDENTIAL);
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < union_cred->count; i++) {
537*7c478bd9Sstevel@tonic-gate 		if (g_OID_equal(mech_type, &union_cred->mechs_array[i]))
538*7c478bd9Sstevel@tonic-gate 			return (union_cred->cred_array[i]);
539*7c478bd9Sstevel@tonic-gate 	}
540*7c478bd9Sstevel@tonic-gate 	return (GSS_C_NO_CREDENTIAL);
541*7c478bd9Sstevel@tonic-gate }
542*7c478bd9Sstevel@tonic-gate 
543*7c478bd9Sstevel@tonic-gate 
544*7c478bd9Sstevel@tonic-gate /*
545*7c478bd9Sstevel@tonic-gate  * Routine to create and copy the gss_buffer_desc structure.
546*7c478bd9Sstevel@tonic-gate  * Both space for the structure and the data is allocated.
547*7c478bd9Sstevel@tonic-gate  */
548*7c478bd9Sstevel@tonic-gate OM_uint32
549*7c478bd9Sstevel@tonic-gate __gss_create_copy_buffer(srcBuf, destBuf, addNullChar)
550*7c478bd9Sstevel@tonic-gate 	const gss_buffer_t	srcBuf;
551*7c478bd9Sstevel@tonic-gate 	gss_buffer_t 		*destBuf;
552*7c478bd9Sstevel@tonic-gate 	int			addNullChar;
553*7c478bd9Sstevel@tonic-gate {
554*7c478bd9Sstevel@tonic-gate 	gss_buffer_t aBuf;
555*7c478bd9Sstevel@tonic-gate 	int len;
556*7c478bd9Sstevel@tonic-gate 
557*7c478bd9Sstevel@tonic-gate 	if (destBuf == NULL)
558*7c478bd9Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
559*7c478bd9Sstevel@tonic-gate 
560*7c478bd9Sstevel@tonic-gate 	*destBuf = 0;
561*7c478bd9Sstevel@tonic-gate 
562*7c478bd9Sstevel@tonic-gate 	aBuf = (gss_buffer_t)malloc(sizeof (gss_buffer_desc));
563*7c478bd9Sstevel@tonic-gate 	if (!aBuf)
564*7c478bd9Sstevel@tonic-gate 		return (GSS_S_FAILURE);
565*7c478bd9Sstevel@tonic-gate 
566*7c478bd9Sstevel@tonic-gate 	if (addNullChar)
567*7c478bd9Sstevel@tonic-gate 		len = srcBuf->length + 1;
568*7c478bd9Sstevel@tonic-gate 	else
569*7c478bd9Sstevel@tonic-gate 		len = srcBuf->length;
570*7c478bd9Sstevel@tonic-gate 
571*7c478bd9Sstevel@tonic-gate 	if (!(aBuf->value = (void*)malloc(len))) {
572*7c478bd9Sstevel@tonic-gate 		free(aBuf);
573*7c478bd9Sstevel@tonic-gate 		return (GSS_S_FAILURE);
574*7c478bd9Sstevel@tonic-gate 	}
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate 	(void) memcpy(aBuf->value, srcBuf->value, srcBuf->length);
578*7c478bd9Sstevel@tonic-gate 	aBuf->length = srcBuf->length;
579*7c478bd9Sstevel@tonic-gate 	*destBuf = aBuf;
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate 	/* optionally add a NULL character */
582*7c478bd9Sstevel@tonic-gate 	if (addNullChar)
583*7c478bd9Sstevel@tonic-gate 		((char *)aBuf->value)[aBuf->length] = '\0';
584*7c478bd9Sstevel@tonic-gate 
585*7c478bd9Sstevel@tonic-gate 	return (GSS_S_COMPLETE);
586*7c478bd9Sstevel@tonic-gate } /* ****** __gss_create_copy_buffer  ****** */
587