xref: /illumos-gate/usr/src/lib/libgss/gssd_pname_to_uid.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <pwd.h>
30*7c478bd9Sstevel@tonic-gate #include <grp.h>
31*7c478bd9Sstevel@tonic-gate #include <stdio.h>
32*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
33*7c478bd9Sstevel@tonic-gate #include <unistd.h>
34*7c478bd9Sstevel@tonic-gate #include <thread.h>
35*7c478bd9Sstevel@tonic-gate #include <synch.h>
36*7c478bd9Sstevel@tonic-gate #include <syslog.h>
37*7c478bd9Sstevel@tonic-gate #include <deflt.h>
38*7c478bd9Sstevel@tonic-gate #include <mechglueP.h>
39*7c478bd9Sstevel@tonic-gate #include "../../cmd/gss/gsscred/gsscred.h"
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate static mutex_t uid_map_lock = DEFAULTMUTEX;
42*7c478bd9Sstevel@tonic-gate static int uid_map_opt = 0;
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate extern int _getgroupsbymember(const char *, gid_t[], int, int);
45*7c478bd9Sstevel@tonic-gate 
46*7c478bd9Sstevel@tonic-gate /* local function used to call a mechanisms pname_to_uid */
47*7c478bd9Sstevel@tonic-gate static OM_uint32 gss_pname_to_uid(OM_uint32*, const gss_name_t,
48*7c478bd9Sstevel@tonic-gate 			const gss_OID, uid_t *);
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate static OM_uint32 private_gsscred_expname_to_unix_cred(const gss_buffer_t,
51*7c478bd9Sstevel@tonic-gate 			uid_t *, gid_t *, gid_t **, int *);
52*7c478bd9Sstevel@tonic-gate 
53*7c478bd9Sstevel@tonic-gate /*
54*7c478bd9Sstevel@tonic-gate  * The gsscred functions will first attempt to call the
55*7c478bd9Sstevel@tonic-gate  * mechanism'm pname_to_uid function.  In case this function
56*7c478bd9Sstevel@tonic-gate  * returns an error or if it is not provided by a mechanism
57*7c478bd9Sstevel@tonic-gate  * then the functions will attempt to look up the principal
58*7c478bd9Sstevel@tonic-gate  * in the gsscred table.
59*7c478bd9Sstevel@tonic-gate  * It is envisioned that the pname_to_uid function will be
60*7c478bd9Sstevel@tonic-gate  * provided by only a few mechanism, which may have the principal
61*7c478bd9Sstevel@tonic-gate  * name to unix credential mapping inherently present.
62*7c478bd9Sstevel@tonic-gate  */
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate /*
65*7c478bd9Sstevel@tonic-gate  * Fetch gsscred options from conf file.
66*7c478bd9Sstevel@tonic-gate  */
67*7c478bd9Sstevel@tonic-gate static void
68*7c478bd9Sstevel@tonic-gate get_conf_options(int *uid_map)
69*7c478bd9Sstevel@tonic-gate {
70*7c478bd9Sstevel@tonic-gate 	register int  flags;
71*7c478bd9Sstevel@tonic-gate 	char *ptr;
72*7c478bd9Sstevel@tonic-gate 	static char *conffile = "/etc/gss/gsscred.conf";
73*7c478bd9Sstevel@tonic-gate 	static  mutex_t deflt_lock = DEFAULTMUTEX;
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate 	*uid_map = 0;
77*7c478bd9Sstevel@tonic-gate 	/*
78*7c478bd9Sstevel@tonic-gate 	 * hold the lock for the deflt file access as its
79*7c478bd9Sstevel@tonic-gate 	 * interface does not appear to be mt-safe
80*7c478bd9Sstevel@tonic-gate 	 */
81*7c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&deflt_lock);
82*7c478bd9Sstevel@tonic-gate 	if (defopen(conffile) == 0) {
83*7c478bd9Sstevel@tonic-gate 		flags = defcntl(DC_GETFLAGS, 0);
84*7c478bd9Sstevel@tonic-gate 		/* ignore case */
85*7c478bd9Sstevel@tonic-gate 		TURNOFF(flags, DC_CASE);
86*7c478bd9Sstevel@tonic-gate 		(void) defcntl(DC_SETFLAGS, flags);
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate 		if ((ptr = defread("SYSLOG_UID_MAPPING=")) != NULL &&
89*7c478bd9Sstevel@tonic-gate 		    strcasecmp("yes", ptr) == 0) {
90*7c478bd9Sstevel@tonic-gate 			(void) defopen((char *)NULL);
91*7c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&deflt_lock);
92*7c478bd9Sstevel@tonic-gate 			*uid_map = 1;
93*7c478bd9Sstevel@tonic-gate 			return;
94*7c478bd9Sstevel@tonic-gate 		}
95*7c478bd9Sstevel@tonic-gate 		(void) defopen((char *)NULL);
96*7c478bd9Sstevel@tonic-gate 	}
97*7c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&deflt_lock);
98*7c478bd9Sstevel@tonic-gate }
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate void
101*7c478bd9Sstevel@tonic-gate gsscred_set_options()
102*7c478bd9Sstevel@tonic-gate {
103*7c478bd9Sstevel@tonic-gate 	int u;
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate 	get_conf_options(&u);
106*7c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&uid_map_lock);
107*7c478bd9Sstevel@tonic-gate 	uid_map_opt = u;
108*7c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&uid_map_lock);
109*7c478bd9Sstevel@tonic-gate }
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate static int
112*7c478bd9Sstevel@tonic-gate get_uid_map_opt()
113*7c478bd9Sstevel@tonic-gate {
114*7c478bd9Sstevel@tonic-gate 	int u;
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&uid_map_lock);
117*7c478bd9Sstevel@tonic-gate 	u = uid_map_opt;
118*7c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&uid_map_lock);
119*7c478bd9Sstevel@tonic-gate 	return (u);
120*7c478bd9Sstevel@tonic-gate }
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate /*
123*7c478bd9Sstevel@tonic-gate  * This routine accepts a name in export name format and retrieves
124*7c478bd9Sstevel@tonic-gate  * unix credentials associated with it.
125*7c478bd9Sstevel@tonic-gate  */
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate OM_uint32
128*7c478bd9Sstevel@tonic-gate gsscred_expname_to_unix_cred_ext(
129*7c478bd9Sstevel@tonic-gate 	const gss_buffer_t expName,
130*7c478bd9Sstevel@tonic-gate 	uid_t *uidOut,
131*7c478bd9Sstevel@tonic-gate 	gid_t *gidOut,
132*7c478bd9Sstevel@tonic-gate 	gid_t *gids[],
133*7c478bd9Sstevel@tonic-gate 	int *gidsLen,
134*7c478bd9Sstevel@tonic-gate 	int try_mech)
135*7c478bd9Sstevel@tonic-gate {
136*7c478bd9Sstevel@tonic-gate 	gss_name_t intName;
137*7c478bd9Sstevel@tonic-gate 	OM_uint32 minor, major;
138*7c478bd9Sstevel@tonic-gate 	const char *mechStr = NULL;
139*7c478bd9Sstevel@tonic-gate 	char *nameStr = NULL;
140*7c478bd9Sstevel@tonic-gate 	char *whoami = "gsscred_expname_to_unix_cred";
141*7c478bd9Sstevel@tonic-gate 	gss_buffer_desc namebuf;
142*7c478bd9Sstevel@tonic-gate 	int debug = get_uid_map_opt();
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate 	if (uidOut == NULL)
145*7c478bd9Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 	if (expName == NULL)
148*7c478bd9Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_READ);
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate 	/* first check the mechanism for the mapping */
151*7c478bd9Sstevel@tonic-gate 	if (gss_import_name(&minor, expName, (gss_OID)GSS_C_NT_EXPORT_NAME,
152*7c478bd9Sstevel@tonic-gate 			&intName) == GSS_S_COMPLETE) {
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate 		if (debug) {
155*7c478bd9Sstevel@tonic-gate 			gss_union_name_t uintName = (gss_union_name_t)intName;
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate 			if (uintName->mech_type)
158*7c478bd9Sstevel@tonic-gate 				mechStr = __gss_oid_to_mech(
159*7c478bd9Sstevel@tonic-gate 					uintName->mech_type);
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate 			major = gss_display_name(&minor, intName,
162*7c478bd9Sstevel@tonic-gate 						&namebuf, NULL);
163*7c478bd9Sstevel@tonic-gate 			if (major == GSS_S_COMPLETE) {
164*7c478bd9Sstevel@tonic-gate 				nameStr = strdup(namebuf.value);
165*7c478bd9Sstevel@tonic-gate 				(void) gss_release_buffer(&minor, &namebuf);
166*7c478bd9Sstevel@tonic-gate 			}
167*7c478bd9Sstevel@tonic-gate 		}
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 		if (try_mech) {
170*7c478bd9Sstevel@tonic-gate 			major = gss_pname_to_uid(&minor, intName,
171*7c478bd9Sstevel@tonic-gate 						NULL, uidOut);
172*7c478bd9Sstevel@tonic-gate 			if (major == GSS_S_COMPLETE) {
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate 				if (debug) {
175*7c478bd9Sstevel@tonic-gate 					syslog(LOG_AUTH|LOG_DEBUG,
176*7c478bd9Sstevel@tonic-gate 					    "%s: mech provided local name"
177*7c478bd9Sstevel@tonic-gate 					    " mapping (%s, %s, %d)", whoami,
178*7c478bd9Sstevel@tonic-gate 					    mechStr ? mechStr : "<null>",
179*7c478bd9Sstevel@tonic-gate 					    nameStr ? nameStr : "<null>",
180*7c478bd9Sstevel@tonic-gate 					    *uidOut);
181*7c478bd9Sstevel@tonic-gate 					free(nameStr);
182*7c478bd9Sstevel@tonic-gate 				}
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate 				(void) gss_release_name(&minor, &intName);
185*7c478bd9Sstevel@tonic-gate 				if (gids && gidsLen && gidOut)
186*7c478bd9Sstevel@tonic-gate 					return (gss_get_group_info(*uidOut,
187*7c478bd9Sstevel@tonic-gate 								gidOut,
188*7c478bd9Sstevel@tonic-gate 								gids,
189*7c478bd9Sstevel@tonic-gate 								gidsLen));
190*7c478bd9Sstevel@tonic-gate 				return (GSS_S_COMPLETE);
191*7c478bd9Sstevel@tonic-gate 			}
192*7c478bd9Sstevel@tonic-gate 		}
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate 		(void) gss_release_name(&minor, &intName);
195*7c478bd9Sstevel@tonic-gate 	}
196*7c478bd9Sstevel@tonic-gate 
197*7c478bd9Sstevel@tonic-gate 	/*
198*7c478bd9Sstevel@tonic-gate 	 * we fall back onto the gsscred table to provide the mapping
199*7c478bd9Sstevel@tonic-gate 	 * start by making sure that the expName is an export name buffer
200*7c478bd9Sstevel@tonic-gate 	 */
201*7c478bd9Sstevel@tonic-gate 	major = private_gsscred_expname_to_unix_cred(expName, uidOut, gidOut,
202*7c478bd9Sstevel@tonic-gate 						gids, gidsLen);
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 	if (debug && major == GSS_S_COMPLETE) {
205*7c478bd9Sstevel@tonic-gate 		syslog(LOG_AUTH|LOG_DEBUG,
206*7c478bd9Sstevel@tonic-gate 		    "%s: gsscred tbl provided"
207*7c478bd9Sstevel@tonic-gate 		    " local name mapping (%s, %s, %d)",
208*7c478bd9Sstevel@tonic-gate 		    whoami,
209*7c478bd9Sstevel@tonic-gate 		    mechStr ? mechStr : "<unknown>",
210*7c478bd9Sstevel@tonic-gate 		    nameStr ? nameStr : "<unknown>",
211*7c478bd9Sstevel@tonic-gate 		    *uidOut);
212*7c478bd9Sstevel@tonic-gate 		free(nameStr);
213*7c478bd9Sstevel@tonic-gate 	} else if (debug) {
214*7c478bd9Sstevel@tonic-gate 		syslog(LOG_AUTH|LOG_DEBUG,
215*7c478bd9Sstevel@tonic-gate 		    "%s: gsscred tbl could NOT"
216*7c478bd9Sstevel@tonic-gate 		    " provide local name mapping (%s, %s)",
217*7c478bd9Sstevel@tonic-gate 		    whoami,
218*7c478bd9Sstevel@tonic-gate 		    mechStr ? mechStr : "<unknown>",
219*7c478bd9Sstevel@tonic-gate 		    nameStr ? nameStr : "<unknown>");
220*7c478bd9Sstevel@tonic-gate 		free(nameStr);
221*7c478bd9Sstevel@tonic-gate 	}
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate 	return (major);
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate } /* gsscred_expname_to_unix_cred */
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate OM_uint32
228*7c478bd9Sstevel@tonic-gate gsscred_expname_to_unix_cred(
229*7c478bd9Sstevel@tonic-gate 	const gss_buffer_t expName,
230*7c478bd9Sstevel@tonic-gate 	uid_t *uidOut,
231*7c478bd9Sstevel@tonic-gate 	gid_t *gidOut,
232*7c478bd9Sstevel@tonic-gate 	gid_t *gids[],
233*7c478bd9Sstevel@tonic-gate 	int *gidsLen)
234*7c478bd9Sstevel@tonic-gate {
235*7c478bd9Sstevel@tonic-gate 	return (gsscred_expname_to_unix_cred_ext(expName, uidOut, gidOut, gids,
236*7c478bd9Sstevel@tonic-gate 						gidsLen, 1));
237*7c478bd9Sstevel@tonic-gate }
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate static const char *expNameTokId = "\x04\x01";
241*7c478bd9Sstevel@tonic-gate static const int expNameTokIdLen = 2;
242*7c478bd9Sstevel@tonic-gate /*
243*7c478bd9Sstevel@tonic-gate  * private routine added to be called from gsscred_name_to_unix_cred
244*7c478bd9Sstevel@tonic-gate  * and gsscred_expName_to_unix_cred.
245*7c478bd9Sstevel@tonic-gate  */
246*7c478bd9Sstevel@tonic-gate static OM_uint32
247*7c478bd9Sstevel@tonic-gate private_gsscred_expname_to_unix_cred(expName, uidOut, gidOut, gids, gidsLen)
248*7c478bd9Sstevel@tonic-gate const gss_buffer_t expName;
249*7c478bd9Sstevel@tonic-gate uid_t *uidOut;
250*7c478bd9Sstevel@tonic-gate gid_t *gidOut;
251*7c478bd9Sstevel@tonic-gate gid_t *gids[];
252*7c478bd9Sstevel@tonic-gate int *gidsLen;
253*7c478bd9Sstevel@tonic-gate {
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate 	if (expName->length < expNameTokIdLen ||
256*7c478bd9Sstevel@tonic-gate 		(memcmp(expName->value, expNameTokId, expNameTokIdLen) != 0))
257*7c478bd9Sstevel@tonic-gate 		return (GSS_S_DEFECTIVE_TOKEN);
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate 	if (!gss_getGssCredEntry(expName, uidOut))
260*7c478bd9Sstevel@tonic-gate 		return (GSS_S_FAILURE);
261*7c478bd9Sstevel@tonic-gate 
262*7c478bd9Sstevel@tonic-gate 	/* did caller request group info also ? */
263*7c478bd9Sstevel@tonic-gate 	if (gids && gidsLen && gidOut)
264*7c478bd9Sstevel@tonic-gate 		return (gss_get_group_info(*uidOut, gidOut, gids, gidsLen));
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate 	return (GSS_S_COMPLETE);
267*7c478bd9Sstevel@tonic-gate }
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate /*
270*7c478bd9Sstevel@tonic-gate  * Return a string of the authenticated name.
271*7c478bd9Sstevel@tonic-gate  * It's a bit of hack/workaround/longroad but the current intName
272*7c478bd9Sstevel@tonic-gate  * passed to gss_display_name insists on returning an empty string.
273*7c478bd9Sstevel@tonic-gate  *
274*7c478bd9Sstevel@tonic-gate  * Caller must free string memory.
275*7c478bd9Sstevel@tonic-gate  */
276*7c478bd9Sstevel@tonic-gate static
277*7c478bd9Sstevel@tonic-gate char *make_name_str(
278*7c478bd9Sstevel@tonic-gate 	const gss_name_t intName,
279*7c478bd9Sstevel@tonic-gate 	const gss_OID mechType)
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate {
282*7c478bd9Sstevel@tonic-gate 	gss_buffer_desc expName = GSS_C_EMPTY_BUFFER;
283*7c478bd9Sstevel@tonic-gate 	OM_uint32 major, minor;
284*7c478bd9Sstevel@tonic-gate 	gss_name_t canonName;
285*7c478bd9Sstevel@tonic-gate 	gss_name_t iName;
286*7c478bd9Sstevel@tonic-gate 	gss_buffer_desc namebuf;
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate 	if (major = gss_canonicalize_name(&minor, intName,
289*7c478bd9Sstevel@tonic-gate 				mechType, &canonName))
290*7c478bd9Sstevel@tonic-gate 		return (NULL);
291*7c478bd9Sstevel@tonic-gate 
292*7c478bd9Sstevel@tonic-gate 	major = gss_export_name(&minor, canonName, &expName);
293*7c478bd9Sstevel@tonic-gate 	(void) gss_release_name(&minor, &canonName);
294*7c478bd9Sstevel@tonic-gate 	if (major)
295*7c478bd9Sstevel@tonic-gate 		return (NULL);
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate 	if (gss_import_name(&minor, &expName,
298*7c478bd9Sstevel@tonic-gate 			    (gss_OID)GSS_C_NT_EXPORT_NAME,
299*7c478bd9Sstevel@tonic-gate 			    &iName) == GSS_S_COMPLETE) {
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate 		major = gss_display_name(&minor, iName, &namebuf, NULL);
302*7c478bd9Sstevel@tonic-gate 		if (major == GSS_S_COMPLETE) {
303*7c478bd9Sstevel@tonic-gate 			char *s;
304*7c478bd9Sstevel@tonic-gate 
305*7c478bd9Sstevel@tonic-gate 			if (namebuf.value)
306*7c478bd9Sstevel@tonic-gate 				s = strdup(namebuf.value);
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate 			(void) gss_release_buffer(&minor, &namebuf);
309*7c478bd9Sstevel@tonic-gate 			(void) gss_release_buffer(&minor, &expName);
310*7c478bd9Sstevel@tonic-gate 			(void) gss_release_buffer(&minor, (gss_buffer_t)iName);
311*7c478bd9Sstevel@tonic-gate 			return (s);
312*7c478bd9Sstevel@tonic-gate 		}
313*7c478bd9Sstevel@tonic-gate 		(void) gss_release_buffer(&minor, (gss_buffer_t)iName);
314*7c478bd9Sstevel@tonic-gate 	}
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 	(void) gss_release_buffer(&minor, &expName);
317*7c478bd9Sstevel@tonic-gate 	return (NULL);
318*7c478bd9Sstevel@tonic-gate }
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate /*
321*7c478bd9Sstevel@tonic-gate  * This routine accepts a name in gss internal name format together with
322*7c478bd9Sstevel@tonic-gate  * a mechanim OID and retrieves a unix credentials for that entity.
323*7c478bd9Sstevel@tonic-gate  */
324*7c478bd9Sstevel@tonic-gate OM_uint32
325*7c478bd9Sstevel@tonic-gate gsscred_name_to_unix_cred_ext(
326*7c478bd9Sstevel@tonic-gate 	const gss_name_t intName,
327*7c478bd9Sstevel@tonic-gate 	const gss_OID mechType,
328*7c478bd9Sstevel@tonic-gate 	uid_t *uidOut,
329*7c478bd9Sstevel@tonic-gate 	gid_t *gidOut,
330*7c478bd9Sstevel@tonic-gate 	gid_t *gids[],
331*7c478bd9Sstevel@tonic-gate 	int *gidsLen,
332*7c478bd9Sstevel@tonic-gate 	int try_mech)
333*7c478bd9Sstevel@tonic-gate {
334*7c478bd9Sstevel@tonic-gate 	gss_name_t canonName;
335*7c478bd9Sstevel@tonic-gate 	gss_buffer_desc expName = GSS_C_EMPTY_BUFFER;
336*7c478bd9Sstevel@tonic-gate 	OM_uint32 major, minor;
337*7c478bd9Sstevel@tonic-gate 	int debug = get_uid_map_opt();
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 	const char *mechStr;
340*7c478bd9Sstevel@tonic-gate 	char *whoami = "gsscred_name_to_unix_cred";
341*7c478bd9Sstevel@tonic-gate 	gss_buffer_desc namebuf;
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate 	if (intName == NULL || mechType == NULL)
344*7c478bd9Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_READ);
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate 	if (uidOut == NULL)
347*7c478bd9Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
348*7c478bd9Sstevel@tonic-gate 
349*7c478bd9Sstevel@tonic-gate 	mechStr = __gss_oid_to_mech(mechType);
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate 	/* first try the mechanism provided mapping */
352*7c478bd9Sstevel@tonic-gate 	if (try_mech && gss_pname_to_uid(&minor, intName, mechType, uidOut)
353*7c478bd9Sstevel@tonic-gate 		== GSS_S_COMPLETE) {
354*7c478bd9Sstevel@tonic-gate 
355*7c478bd9Sstevel@tonic-gate 		if (debug) {
356*7c478bd9Sstevel@tonic-gate 			char *s = make_name_str(intName, mechType);
357*7c478bd9Sstevel@tonic-gate 			syslog(LOG_AUTH|LOG_DEBUG,
358*7c478bd9Sstevel@tonic-gate 			    "%s: mech provided local name"
359*7c478bd9Sstevel@tonic-gate 			    " mapping (%s, %s, %d)", whoami,
360*7c478bd9Sstevel@tonic-gate 			    mechStr ? mechStr : "<null>",
361*7c478bd9Sstevel@tonic-gate 			    s ? s : "<null>",
362*7c478bd9Sstevel@tonic-gate 			    *uidOut);
363*7c478bd9Sstevel@tonic-gate 			free(s);
364*7c478bd9Sstevel@tonic-gate 		}
365*7c478bd9Sstevel@tonic-gate 
366*7c478bd9Sstevel@tonic-gate 		if (gids && gidsLen && gidOut)
367*7c478bd9Sstevel@tonic-gate 			return (gss_get_group_info(*uidOut, gidOut, gids,
368*7c478bd9Sstevel@tonic-gate 					gidsLen));
369*7c478bd9Sstevel@tonic-gate 		return (GSS_S_COMPLETE);
370*7c478bd9Sstevel@tonic-gate 	}
371*7c478bd9Sstevel@tonic-gate 	/*
372*7c478bd9Sstevel@tonic-gate 	 * falling back onto the gsscred table to provide the mapping
373*7c478bd9Sstevel@tonic-gate 	 * start by canonicalizing the passed in name and then export it
374*7c478bd9Sstevel@tonic-gate 	 */
375*7c478bd9Sstevel@tonic-gate 	if (major = gss_canonicalize_name(&minor, intName,
376*7c478bd9Sstevel@tonic-gate 				mechType, &canonName))
377*7c478bd9Sstevel@tonic-gate 		return (major);
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate 	major = gss_export_name(&minor, canonName, &expName);
380*7c478bd9Sstevel@tonic-gate 	(void) gss_release_name(&minor, &canonName);
381*7c478bd9Sstevel@tonic-gate 	if (major)
382*7c478bd9Sstevel@tonic-gate 		return (major);
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate 	major = private_gsscred_expname_to_unix_cred(&expName, uidOut, gidOut,
385*7c478bd9Sstevel@tonic-gate 					gids, gidsLen);
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate 
388*7c478bd9Sstevel@tonic-gate 	if (debug) {
389*7c478bd9Sstevel@tonic-gate 		gss_name_t iName;
390*7c478bd9Sstevel@tonic-gate 		OM_uint32 maj;
391*7c478bd9Sstevel@tonic-gate 		char *nameStr = NULL;
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate 		if (gss_import_name(&minor, &expName,
394*7c478bd9Sstevel@tonic-gate 				    (gss_OID)GSS_C_NT_EXPORT_NAME,
395*7c478bd9Sstevel@tonic-gate 				    &iName) == GSS_S_COMPLETE) {
396*7c478bd9Sstevel@tonic-gate 
397*7c478bd9Sstevel@tonic-gate 			maj = gss_display_name(&minor, iName, &namebuf,
398*7c478bd9Sstevel@tonic-gate 					    NULL);
399*7c478bd9Sstevel@tonic-gate 			(void) gss_release_buffer(&minor, (gss_buffer_t)iName);
400*7c478bd9Sstevel@tonic-gate 			if (maj == GSS_S_COMPLETE) {
401*7c478bd9Sstevel@tonic-gate 				nameStr = strdup(namebuf.value);
402*7c478bd9Sstevel@tonic-gate 				(void) gss_release_buffer(&minor, &namebuf);
403*7c478bd9Sstevel@tonic-gate 			}
404*7c478bd9Sstevel@tonic-gate 		}
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate 		if (major == GSS_S_COMPLETE)
407*7c478bd9Sstevel@tonic-gate 			syslog(LOG_AUTH|LOG_DEBUG,
408*7c478bd9Sstevel@tonic-gate 			    "%s: gsscred tbl provided"
409*7c478bd9Sstevel@tonic-gate 			    " local name mapping (%s, %s, %d)",
410*7c478bd9Sstevel@tonic-gate 			    whoami,
411*7c478bd9Sstevel@tonic-gate 			    mechStr ? mechStr : "<unknown>",
412*7c478bd9Sstevel@tonic-gate 			    nameStr ? nameStr : "<unknown>",
413*7c478bd9Sstevel@tonic-gate 			    *uidOut);
414*7c478bd9Sstevel@tonic-gate 		else
415*7c478bd9Sstevel@tonic-gate 			syslog(LOG_AUTH|LOG_DEBUG,
416*7c478bd9Sstevel@tonic-gate 			    "%s: gsscred tbl could NOT"
417*7c478bd9Sstevel@tonic-gate 			    " provide local name mapping (%s, %s)",
418*7c478bd9Sstevel@tonic-gate 			    whoami,
419*7c478bd9Sstevel@tonic-gate 			    mechStr ? mechStr : "<unknown>",
420*7c478bd9Sstevel@tonic-gate 			    nameStr ? nameStr : "<unknown>");
421*7c478bd9Sstevel@tonic-gate 
422*7c478bd9Sstevel@tonic-gate 		free(nameStr);
423*7c478bd9Sstevel@tonic-gate 	}
424*7c478bd9Sstevel@tonic-gate 
425*7c478bd9Sstevel@tonic-gate 	(void) gss_release_buffer(&minor, &expName);
426*7c478bd9Sstevel@tonic-gate 	return (major);
427*7c478bd9Sstevel@tonic-gate } /* gsscred_name_to_unix_cred */
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate OM_uint32
431*7c478bd9Sstevel@tonic-gate gsscred_name_to_unix_cred(
432*7c478bd9Sstevel@tonic-gate 	const gss_name_t intName,
433*7c478bd9Sstevel@tonic-gate 	const gss_OID mechType,
434*7c478bd9Sstevel@tonic-gate 	uid_t *uidOut,
435*7c478bd9Sstevel@tonic-gate 	gid_t *gidOut,
436*7c478bd9Sstevel@tonic-gate 	gid_t *gids[],
437*7c478bd9Sstevel@tonic-gate 	int *gidsLen)
438*7c478bd9Sstevel@tonic-gate {
439*7c478bd9Sstevel@tonic-gate 	return (gsscred_name_to_unix_cred_ext(intName, mechType,
440*7c478bd9Sstevel@tonic-gate 					    uidOut, gidOut,
441*7c478bd9Sstevel@tonic-gate 					    gids, gidsLen, 1));
442*7c478bd9Sstevel@tonic-gate }
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate /*
447*7c478bd9Sstevel@tonic-gate  * This routine accepts a unix uid, and retrieves the group id
448*7c478bd9Sstevel@tonic-gate  * and supplamentery group ids for that uid.
449*7c478bd9Sstevel@tonic-gate  * Callers should be aware that the supplamentary group ids
450*7c478bd9Sstevel@tonic-gate  * array may be empty even when this function returns success.
451*7c478bd9Sstevel@tonic-gate  */
452*7c478bd9Sstevel@tonic-gate OM_uint32
453*7c478bd9Sstevel@tonic-gate gss_get_group_info(uid, gidOut, gids, gidsLen)
454*7c478bd9Sstevel@tonic-gate const uid_t uid;
455*7c478bd9Sstevel@tonic-gate gid_t *gidOut;
456*7c478bd9Sstevel@tonic-gate gid_t *gids[];
457*7c478bd9Sstevel@tonic-gate int *gidsLen;
458*7c478bd9Sstevel@tonic-gate {
459*7c478bd9Sstevel@tonic-gate 	struct passwd *pw;
460*7c478bd9Sstevel@tonic-gate 	int maxgroups;
461*7c478bd9Sstevel@tonic-gate 
462*7c478bd9Sstevel@tonic-gate 	/* check for output parameters */
463*7c478bd9Sstevel@tonic-gate 	if (gidOut == NULL || gids == NULL || gidsLen == NULL)
464*7c478bd9Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
465*7c478bd9Sstevel@tonic-gate 
466*7c478bd9Sstevel@tonic-gate 	*gids = NULL;
467*7c478bd9Sstevel@tonic-gate 	*gidsLen = 0;
468*7c478bd9Sstevel@tonic-gate 
469*7c478bd9Sstevel@tonic-gate 	/* determine maximum number of groups possible */
470*7c478bd9Sstevel@tonic-gate 	maxgroups = sysconf(_SC_NGROUPS_MAX);
471*7c478bd9Sstevel@tonic-gate 	if (maxgroups < 1)
472*7c478bd9Sstevel@tonic-gate 	    maxgroups = 16;
473*7c478bd9Sstevel@tonic-gate 
474*7c478bd9Sstevel@tonic-gate 	if ((pw = getpwuid(uid)) == NULL)
475*7c478bd9Sstevel@tonic-gate 	    return (GSS_S_FAILURE);
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate 	/*
478*7c478bd9Sstevel@tonic-gate 	 * we allocate for the maximum number of groups
479*7c478bd9Sstevel@tonic-gate 	 * we do not reclaim the space when the actual number
480*7c478bd9Sstevel@tonic-gate 	 * is lower, just set the size approprately.
481*7c478bd9Sstevel@tonic-gate 	 */
482*7c478bd9Sstevel@tonic-gate 	*gids = (gid_t *)calloc(maxgroups, sizeof (gid_t));
483*7c478bd9Sstevel@tonic-gate 	if (*gids == NULL)
484*7c478bd9Sstevel@tonic-gate 	    return (GSS_S_FAILURE);
485*7c478bd9Sstevel@tonic-gate 
486*7c478bd9Sstevel@tonic-gate 	*gidOut = pw->pw_gid;
487*7c478bd9Sstevel@tonic-gate 	(*gids)[0] = pw->pw_gid;
488*7c478bd9Sstevel@tonic-gate 	*gidsLen = _getgroupsbymember(pw->pw_name, *gids, maxgroups, 1);
489*7c478bd9Sstevel@tonic-gate 	/*
490*7c478bd9Sstevel@tonic-gate 	 * we will try to remove the duplicate entry from the groups
491*7c478bd9Sstevel@tonic-gate 	 * array.  This can cause the group array to be empty.
492*7c478bd9Sstevel@tonic-gate 	 */
493*7c478bd9Sstevel@tonic-gate 	if (*gidsLen < 1)
494*7c478bd9Sstevel@tonic-gate 	{
495*7c478bd9Sstevel@tonic-gate 		free(*gids);
496*7c478bd9Sstevel@tonic-gate 		*gids = NULL;
497*7c478bd9Sstevel@tonic-gate 		return (GSS_S_FAILURE);
498*7c478bd9Sstevel@tonic-gate 	} else if (*gidsLen == 1) {
499*7c478bd9Sstevel@tonic-gate 		free(*gids);
500*7c478bd9Sstevel@tonic-gate 		*gids = NULL;
501*7c478bd9Sstevel@tonic-gate 		*gidsLen = 0;
502*7c478bd9Sstevel@tonic-gate 	} else {
503*7c478bd9Sstevel@tonic-gate 		/* length is atleast 2 */
504*7c478bd9Sstevel@tonic-gate 		*gidsLen = *gidsLen -1;
505*7c478bd9Sstevel@tonic-gate 		(*gids)[0] = (*gids)[*gidsLen];
506*7c478bd9Sstevel@tonic-gate 	}
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate 	return (GSS_S_COMPLETE);
509*7c478bd9Sstevel@tonic-gate } /* gss_get_group_info */
510*7c478bd9Sstevel@tonic-gate 
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate static OM_uint32
513*7c478bd9Sstevel@tonic-gate gss_pname_to_uid(minor, name, mech_type, uidOut)
514*7c478bd9Sstevel@tonic-gate OM_uint32 *minor;
515*7c478bd9Sstevel@tonic-gate const gss_name_t name;
516*7c478bd9Sstevel@tonic-gate const gss_OID mech_type;
517*7c478bd9Sstevel@tonic-gate uid_t *uidOut;
518*7c478bd9Sstevel@tonic-gate {
519*7c478bd9Sstevel@tonic-gate 	gss_mechanism mech;
520*7c478bd9Sstevel@tonic-gate 	gss_union_name_t intName;
521*7c478bd9Sstevel@tonic-gate 	gss_name_t mechName = NULL;
522*7c478bd9Sstevel@tonic-gate 	OM_uint32 major, tmpMinor;
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate 	if (!minor)
525*7c478bd9Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
526*7c478bd9Sstevel@tonic-gate 
527*7c478bd9Sstevel@tonic-gate 	*minor = 0;
528*7c478bd9Sstevel@tonic-gate 
529*7c478bd9Sstevel@tonic-gate 	if (uidOut == NULL)
530*7c478bd9Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
531*7c478bd9Sstevel@tonic-gate 
532*7c478bd9Sstevel@tonic-gate 	if (name == NULL)
533*7c478bd9Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_READ);
534*7c478bd9Sstevel@tonic-gate 
535*7c478bd9Sstevel@tonic-gate 	intName = (gss_union_name_t)name;
536*7c478bd9Sstevel@tonic-gate 
537*7c478bd9Sstevel@tonic-gate 	if (mech_type != NULL)
538*7c478bd9Sstevel@tonic-gate 		mech = __gss_get_mechanism(mech_type);
539*7c478bd9Sstevel@tonic-gate 	else {
540*7c478bd9Sstevel@tonic-gate 		/*
541*7c478bd9Sstevel@tonic-gate 		 * if this is a MN, then try using the mech
542*7c478bd9Sstevel@tonic-gate 		 * from the name; otherwise ask for default
543*7c478bd9Sstevel@tonic-gate 		 */
544*7c478bd9Sstevel@tonic-gate 		mech = __gss_get_mechanism(intName->mech_type);
545*7c478bd9Sstevel@tonic-gate 	}
546*7c478bd9Sstevel@tonic-gate 
547*7c478bd9Sstevel@tonic-gate 	if (mech == NULL || mech->pname_to_uid == NULL)
548*7c478bd9Sstevel@tonic-gate 		return (GSS_S_UNAVAILABLE);
549*7c478bd9Sstevel@tonic-gate 
550*7c478bd9Sstevel@tonic-gate 	/* may need to import the name if this is not MN */
551*7c478bd9Sstevel@tonic-gate 	if (intName->mech_type == NULL) {
552*7c478bd9Sstevel@tonic-gate 		major = __gss_import_internal_name(minor,
553*7c478bd9Sstevel@tonic-gate 				mech_type, intName,
554*7c478bd9Sstevel@tonic-gate 				&mechName);
555*7c478bd9Sstevel@tonic-gate 		if (major != GSS_S_COMPLETE)
556*7c478bd9Sstevel@tonic-gate 			return (major);
557*7c478bd9Sstevel@tonic-gate 	} else
558*7c478bd9Sstevel@tonic-gate 		mechName = intName->mech_name;
559*7c478bd9Sstevel@tonic-gate 
560*7c478bd9Sstevel@tonic-gate 
561*7c478bd9Sstevel@tonic-gate 	/* now call the mechanism's pname function to do the work */
562*7c478bd9Sstevel@tonic-gate 	major = mech->pname_to_uid(mech->context, minor, mechName, uidOut);
563*7c478bd9Sstevel@tonic-gate 
564*7c478bd9Sstevel@tonic-gate 	if (intName->mech_name != mechName)
565*7c478bd9Sstevel@tonic-gate 		(void) __gss_release_internal_name(&tmpMinor, &mech->mech_type,
566*7c478bd9Sstevel@tonic-gate 				&mechName);
567*7c478bd9Sstevel@tonic-gate 
568*7c478bd9Sstevel@tonic-gate 	return (major);
569*7c478bd9Sstevel@tonic-gate } /* gss_pname_to_uid */
570