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 #include <sys/systm.h>
28 #include <sys/errno.h>
29 #include <sys/cmn_err.h>
30 #include <gssapi/gssapi.h>
31 #include <rpc/rpc.h>
32 #include <rpc/rpcsec_defs.h>
33 
34 #ifdef RPCGSS_DEBUG
35 /*
36  * Kernel rpcsec_gss module debugging aid. The global variable "rpcgss_log"
37  * is a bit mask which allows various types of debugging messages to be printed
38  * out.
39  *
40  *	  rpcgss_log & 1	will cause actual failures to be printed.
41  *	  rpcgss_log & 2 	will cause informational messages to be
42  *			printed on the client side of rpcsec_gss.
43  *	  rpcgss_log & 4	will cause informational messages to be
44  *			printed on the server side of rpcsec_gss.
45  *	  rpcgss_log & 8	will cause informational messages to be
46  *			printed on both client and server side of rpcsec_gss.
47  */
48 
49 uint_t rpcgss_log = 0;
50 
51 #endif /* RPCGSS_DEBUG */
52 
53 /*
54  * Internal utility routines.
55  */
56 
57 /*
58  *  Duplicate a gss_OID value.
59  */
60 void
__rpc_gss_dup_oid(gss_OID oid,gss_OID * ret)61 __rpc_gss_dup_oid(gss_OID oid, gss_OID *ret)
62 {
63 	gss_OID tmp;
64 
65 	if (oid == GSS_C_NULL_OID || oid->length == 0) {
66 		*ret = NULL;
67 		return;
68 	}
69 
70 	tmp = (gss_OID) kmem_alloc(sizeof (gss_OID_desc), KM_SLEEP);
71 	if (tmp) {
72 	    tmp->elements = kmem_alloc((oid->length), KM_SLEEP);
73 	    bcopy((char *)oid->elements, (char *)tmp->elements, oid->length);
74 	    tmp->length = oid->length;
75 	    *ret = tmp;
76 	} else {
77 	    *ret = NULL;
78 	}
79 }
80 
81 /*
82  *  Check if 2 gss_OID are the same.
83  */
84 bool_t
__rpc_gss_oids_equal(oid1,oid2)85 __rpc_gss_oids_equal(oid1, oid2)
86 	gss_OID	oid1, oid2;
87 {
88 	if ((oid1->length == 0) && (oid2->length == 0))
89 		return (TRUE);
90 
91 	if (oid1->length != oid2->length)
92 		return (FALSE);
93 
94 	return (bcmp(oid1->elements, oid2->elements, oid1->length) == 0);
95 }
96 
97 void
__rpc_gss_convert_name(principal,name,name_type)98 __rpc_gss_convert_name(principal, name, name_type)
99 	rpc_gss_principal_t	principal;
100 	gss_buffer_desc		*name;
101 	gss_OID			*name_type;
102 {
103 	char			*cp;
104 
105 	cp = principal->name;
106 	if (*(int *)cp == 0)
107 		*name_type = GSS_C_NULL_OID;
108 	else {
109 		(*name_type)->length = *(int *)cp;
110 		(*name_type)->elements = (void *)(cp + sizeof (int));
111 	}
112 	cp += RNDUP(*(int *)cp) + sizeof (int);
113 	if ((name->length = *(int *)cp) == 0)
114 		name->value = NULL;
115 	else
116 		name->value = cp + sizeof (int);
117 }
118 
119 /*
120  *  Make a client principal name from a flat exported gss name.
121  */
122 bool_t
__rpc_gss_make_principal(principal,name)123 __rpc_gss_make_principal(principal, name)
124 	rpc_gss_principal_t	*principal;
125 	gss_buffer_desc		*name;
126 {
127 	int			plen;
128 	char			*s;
129 
130 	RPCGSS_LOG(8, "name-length = %lu\n", name->length);
131 	RPCGSS_LOG(8, "name-value = 0x%p\n", (void *)name->value);
132 
133 	plen = RNDUP(name->length) + sizeof (int);
134 	(*principal) = (rpc_gss_principal_t)kmem_alloc(plen, KM_SLEEP);
135 	if ((*principal) == NULL)
136 		return (FALSE);
137 	bzero((caddr_t)(*principal), plen);
138 	(*principal)->len = RNDUP(name->length);
139 	s = (*principal)->name;
140 	bcopy(name->value, s, name->length);
141 	return (TRUE);
142 }
143 
144 
145 /*
146  * Make a copy of a principal name.
147  */
148 rpc_gss_principal_t
__rpc_gss_dup_principal(principal)149 __rpc_gss_dup_principal(principal)
150 	rpc_gss_principal_t	principal;
151 {
152 	rpc_gss_principal_t	pdup;
153 	int			len;
154 
155 	if (principal == NULL)
156 		return (NULL);
157 	len = principal->len + sizeof (int);
158 	if ((pdup = (rpc_gss_principal_t)mem_alloc(len)) == NULL)
159 		return (NULL);
160 	pdup->len = len;
161 	bcopy(principal->name, pdup->name, len);
162 	return (pdup);
163 }
164 
165 /*
166  * Returns highest and lowest versions of RPCSEC_GSS flavor supported.
167  */
168 bool_t
rpc_gss_get_versions(vers_hi,vers_lo)169 rpc_gss_get_versions(vers_hi, vers_lo)
170 	uint_t	*vers_hi;
171 	uint_t	*vers_lo;
172 {
173 	*vers_hi = RPCSEC_GSS_VERSION;
174 	*vers_lo = RPCSEC_GSS_VERSION;
175 	return (TRUE);
176 }
177 
178 void
rpc_gss_display_status(major,minor,mech_type,uid,gss_function_name)179 rpc_gss_display_status(major, minor, mech_type,
180 		uid, gss_function_name)
181 	OM_uint32	major, minor;
182 	gss_OID		mech_type;
183 	uid_t		uid;
184 	char		*gss_function_name;
185 
186 {
187 	int message_context;
188 	int major_stat;
189 	uint_t minor_stat;
190 	gss_buffer_desc status_string;
191 
192 	/*
193 	 * Before we return let us see
194 	 * whether we can log more meaningful error
195 	 * string using kgss_display_status
196 	 * If we can not just log the gssstat in hex
197 	 * and return.
198 	 */
199 	message_context = 0;
200 
201 	/*
202 	 * First get the status string out of gss_major_code
203 	 */
204 
205 	do {
206 	    major_stat = kgss_display_status(&minor_stat, major,
207 		GSS_C_GSS_CODE, mech_type,
208 		&message_context, &status_string, uid);
209 		/*
210 		 * If we failed just log the original error codes
211 		 */
212 	    if (major_stat != GSS_S_COMPLETE &&
213 		major != GSS_S_CONTINUE_NEEDED) {
214 
215 		RPCGSS_LOG1(1, "%s GSS major error 0x%x\n",
216 			gss_function_name, major);
217 		RPCGSS_LOG1(1, "%s GSS minor error 0x%x\n",
218 			gss_function_name, minor);
219 
220 		return;
221 	    } else {
222 		RPCGSS_LOG1(1, "%s GSS Error %s\n",
223 			(char *)gss_function_name,
224 			(char *)status_string.value);
225 		(void) gss_release_buffer(&minor_stat, &status_string);
226 	    }
227 	} while (message_context != 0);
228 	/*
229 	 * Now get the status string out of gss_minor_code
230 	 * This is mechanism specific error which is most
231 	 * useful
232 	 */
233 	message_context = 0;
234 	do {
235 	    major_stat = kgss_display_status(&minor_stat, minor,
236 		GSS_C_MECH_CODE, mech_type,
237 		&message_context, &status_string, uid);
238 	    if (major_stat != GSS_S_COMPLETE &&
239 		major_stat != GSS_S_CONTINUE_NEEDED) {
240 		RPCGSS_LOG1(1, "%s GSS minor error 0x%x\n",
241 		gss_function_name, minor);
242 		return;
243 	    } else {
244 		RPCGSS_LOG1(1,
245 		    "%s GSS Minor Error %s\n",
246 		    (char *)gss_function_name, (char *)status_string.value);
247 		(void) gss_release_buffer(&minor_stat,
248 		    &status_string);
249 	    }
250 	} while (message_context != 0);
251 }
252