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
__rpc_gss_dup_oid(gss_OID oid,gss_OID * ret)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
__rpc_gss_oids_equal(oid1,oid2)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
__rpc_gss_convert_name(principal,name,name_type)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
__rpc_gss_make_principal(principal,name)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
__rpc_gss_dup_principal(principal)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
rpc_gss_get_versions(vers_hi,vers_lo)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
rpc_gss_display_status(major,minor,mech_type,uid,gss_function_name)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