xref: /illumos-gate/usr/src/uts/common/rpc/sec_gss/rpcsec_gss_utils.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 1996-1997,2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/systm.h>
30 #include <sys/errno.h>
31 #include <sys/cmn_err.h>
32 #include <gssapi/gssapi.h>
33 #include <rpc/rpc.h>
34 #include <rpc/rpcsec_defs.h>
35 
36 #ifdef RPCGSS_DEBUG
37 /*
38  * Kernel rpcsec_gss module debugging aid. The global variable "rpcgss_log"
39  * is a bit mask which allows various types of debugging messages to be printed
40  * out.
41  *
42  *	  rpcgss_log & 1	will cause actual failures to be printed.
43  *	  rpcgss_log & 2 	will cause informational messages to be
44  *			printed on the client side of rpcsec_gss.
45  *	  rpcgss_log & 4	will cause informational messages to be
46  *			printed on the server side of rpcsec_gss.
47  *	  rpcgss_log & 8	will cause informational messages to be
48  *			printed on both client and server side of rpcsec_gss.
49  */
50 
51 uint_t rpcgss_log = 0;
52 
53 #endif /* RPCGSS_DEBUG */
54 
55 /*
56  * Internal utility routines.
57  */
58 
59 /*
60  *  Duplicate a gss_OID value.
61  */
62 void
63 __rpc_gss_dup_oid(gss_OID oid, gss_OID *ret)
64 {
65 	gss_OID tmp;
66 
67 	if (oid == GSS_C_NULL_OID || oid->length == 0) {
68 		*ret = NULL;
69 		return;
70 	}
71 
72 	tmp = (gss_OID) kmem_alloc(sizeof (gss_OID_desc), KM_SLEEP);
73 	if (tmp) {
74 	    tmp->elements = kmem_alloc((oid->length), KM_SLEEP);
75 	    bcopy((char *)oid->elements, (char *)tmp->elements, oid->length);
76 	    tmp->length = oid->length;
77 	    *ret = tmp;
78 	} else {
79 	    *ret = NULL;
80 	}
81 }
82 
83 /*
84  *  Check if 2 gss_OID are the same.
85  */
86 bool_t
87 __rpc_gss_oids_equal(oid1, oid2)
88 	gss_OID	oid1, oid2;
89 {
90 	if ((oid1->length == 0) && (oid2->length == 0))
91 		return (TRUE);
92 
93 	if (oid1->length != oid2->length)
94 		return (FALSE);
95 
96 	return (bcmp(oid1->elements, oid2->elements, oid1->length) == 0);
97 }
98 
99 void
100 __rpc_gss_convert_name(principal, name, name_type)
101 	rpc_gss_principal_t	principal;
102 	gss_buffer_desc		*name;
103 	gss_OID			*name_type;
104 {
105 	char			*cp;
106 
107 	cp = principal->name;
108 	if (*(int *)cp == 0)
109 		*name_type = GSS_C_NULL_OID;
110 	else {
111 		(*name_type)->length = *(int *)cp;
112 		(*name_type)->elements = (void *)(cp + sizeof (int));
113 	}
114 	cp += RNDUP(*(int *)cp) + sizeof (int);
115 	if ((name->length = *(int *)cp) == 0)
116 		name->value = NULL;
117 	else
118 		name->value = cp + sizeof (int);
119 }
120 
121 /*
122  *  Make a client principal name from a flat exported gss name.
123  */
124 bool_t
125 __rpc_gss_make_principal(principal, name)
126 	rpc_gss_principal_t	*principal;
127 	gss_buffer_desc		*name;
128 {
129 	int			plen;
130 	char			*s;
131 
132 	RPCGSS_LOG(8, "name-length = %lu\n", name->length);
133 	RPCGSS_LOG(8, "name-value = 0x%p\n", (void *)name->value);
134 
135 	plen = RNDUP(name->length) + sizeof (int);
136 	(*principal) = (rpc_gss_principal_t)kmem_alloc(plen, KM_SLEEP);
137 	if ((*principal) == NULL)
138 		return (FALSE);
139 	bzero((caddr_t)(*principal), plen);
140 	(*principal)->len = RNDUP(name->length);
141 	s = (*principal)->name;
142 	bcopy(name->value, s, name->length);
143 	return (TRUE);
144 }
145 
146 
147 /*
148  * Make a copy of a principal name.
149  */
150 rpc_gss_principal_t
151 __rpc_gss_dup_principal(principal)
152 	rpc_gss_principal_t	principal;
153 {
154 	rpc_gss_principal_t	pdup;
155 	int			len;
156 
157 	if (principal == NULL)
158 		return (NULL);
159 	len = principal->len + sizeof (int);
160 	if ((pdup = (rpc_gss_principal_t)mem_alloc(len)) == NULL)
161 		return (NULL);
162 	pdup->len = len;
163 	bcopy(principal->name, pdup->name, len);
164 	return (pdup);
165 }
166 
167 /*
168  * Returns highest and lowest versions of RPCSEC_GSS flavor supported.
169  */
170 bool_t
171 rpc_gss_get_versions(vers_hi, vers_lo)
172 	uint_t	*vers_hi;
173 	uint_t	*vers_lo;
174 {
175 	*vers_hi = RPCSEC_GSS_VERSION;
176 	*vers_lo = RPCSEC_GSS_VERSION;
177 	return (TRUE);
178 }
179 
180 void
181 rpc_gss_display_status(major, minor, mech_type,
182 		uid, gss_function_name)
183 	OM_uint32	major, minor;
184 	gss_OID		mech_type;
185 	uid_t		uid;
186 	char		*gss_function_name;
187 
188 {
189 	int message_context;
190 	int major_stat;
191 	uint_t minor_stat;
192 	gss_buffer_desc status_string;
193 
194 	/*
195 	 * Before we return let us see
196 	 * whether we can log more meaningful error
197 	 * string using kgss_display_status
198 	 * If we can not just log the gssstat in hex
199 	 * and return.
200 	 */
201 	message_context = 0;
202 
203 	/*
204 	 * First get the status string out of gss_major_code
205 	 */
206 
207 	do {
208 	    major_stat = kgss_display_status(&minor_stat, major,
209 		GSS_C_GSS_CODE, mech_type,
210 		&message_context, &status_string, uid);
211 		/*
212 		 * If we failed just log the original error codes
213 		 */
214 	    if (major_stat != GSS_S_COMPLETE &&
215 		major != GSS_S_CONTINUE_NEEDED) {
216 
217 		RPCGSS_LOG1(1, "%s GSS major error 0x%x\n",
218 			gss_function_name, major);
219 		RPCGSS_LOG1(1, "%s GSS minor error 0x%x\n",
220 			gss_function_name, minor);
221 
222 		return;
223 	    } else {
224 		RPCGSS_LOG1(1, "%s GSS Error %s\n",
225 			(char *)gss_function_name,
226 			(char *)status_string.value);
227 		(void) gss_release_buffer(&minor_stat, &status_string);
228 	    }
229 	} while (message_context != 0);
230 	/*
231 	 * Now get the status string out of gss_minor_code
232 	 * This is mechanism specific error which is most
233 	 * useful
234 	 */
235 	message_context = 0;
236 	do {
237 	    major_stat = kgss_display_status(&minor_stat, minor,
238 		GSS_C_MECH_CODE, mech_type,
239 		&message_context, &status_string, uid);
240 	    if (major_stat != GSS_S_COMPLETE &&
241 		major_stat != GSS_S_CONTINUE_NEEDED) {
242 		RPCGSS_LOG1(1, "%s GSS minor error 0x%x\n",
243 		gss_function_name, minor);
244 		return;
245 	    } else {
246 		RPCGSS_LOG1(1,
247 		    "%s GSS Minor Error %s\n",
248 		    (char *)gss_function_name, (char *)status_string.value);
249 		(void) gss_release_buffer(&minor_stat,
250 		    &status_string);
251 	    }
252 	} while (message_context != 0);
253 }
254