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