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