17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*b9175c69SKenjiro Tsuji  * Common Development and Distribution License (the "License").
6*b9175c69SKenjiro Tsuji  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*b9175c69SKenjiro Tsuji  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <pwd.h>
277c478bd9Sstevel@tonic-gate #include <grp.h>
287c478bd9Sstevel@tonic-gate #include <stdio.h>
297c478bd9Sstevel@tonic-gate #include <stdlib.h>
307c478bd9Sstevel@tonic-gate #include <unistd.h>
317c478bd9Sstevel@tonic-gate #include <thread.h>
327c478bd9Sstevel@tonic-gate #include <synch.h>
337c478bd9Sstevel@tonic-gate #include <syslog.h>
347c478bd9Sstevel@tonic-gate #include <deflt.h>
357c478bd9Sstevel@tonic-gate #include <mechglueP.h>
367c478bd9Sstevel@tonic-gate #include "../../cmd/gss/gsscred/gsscred.h"
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate static mutex_t uid_map_lock = DEFAULTMUTEX;
397c478bd9Sstevel@tonic-gate static int uid_map_opt = 0;
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate extern int _getgroupsbymember(const char *, gid_t[], int, int);
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate /* local function used to call a mechanisms pname_to_uid */
447c478bd9Sstevel@tonic-gate static OM_uint32 gss_pname_to_uid(OM_uint32*, const gss_name_t,
457c478bd9Sstevel@tonic-gate 			const gss_OID, uid_t *);
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate static OM_uint32 private_gsscred_expname_to_unix_cred(const gss_buffer_t,
487c478bd9Sstevel@tonic-gate 			uid_t *, gid_t *, gid_t **, int *);
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate /*
517c478bd9Sstevel@tonic-gate  * The gsscred functions will first attempt to call the
527c478bd9Sstevel@tonic-gate  * mechanism'm pname_to_uid function.  In case this function
537c478bd9Sstevel@tonic-gate  * returns an error or if it is not provided by a mechanism
547c478bd9Sstevel@tonic-gate  * then the functions will attempt to look up the principal
557c478bd9Sstevel@tonic-gate  * in the gsscred table.
567c478bd9Sstevel@tonic-gate  * It is envisioned that the pname_to_uid function will be
577c478bd9Sstevel@tonic-gate  * provided by only a few mechanism, which may have the principal
587c478bd9Sstevel@tonic-gate  * name to unix credential mapping inherently present.
597c478bd9Sstevel@tonic-gate  */
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate /*
627c478bd9Sstevel@tonic-gate  * Fetch gsscred options from conf file.
637c478bd9Sstevel@tonic-gate  */
647c478bd9Sstevel@tonic-gate static void
get_conf_options(int * uid_map)657c478bd9Sstevel@tonic-gate get_conf_options(int *uid_map)
667c478bd9Sstevel@tonic-gate {
67*b9175c69SKenjiro Tsuji 	int  flags;
687c478bd9Sstevel@tonic-gate 	char *ptr;
69*b9175c69SKenjiro Tsuji 	void	*defp;
707c478bd9Sstevel@tonic-gate 	static char *conffile = "/etc/gss/gsscred.conf";
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate 	*uid_map = 0;
73*b9175c69SKenjiro Tsuji 	if ((defp = defopen_r(conffile)) != NULL) {
74*b9175c69SKenjiro Tsuji 		flags = defcntl_r(DC_GETFLAGS, 0, defp);
757c478bd9Sstevel@tonic-gate 		/* ignore case */
767c478bd9Sstevel@tonic-gate 		TURNOFF(flags, DC_CASE);
77*b9175c69SKenjiro Tsuji 		(void) defcntl_r(DC_SETFLAGS, flags, defp);
787c478bd9Sstevel@tonic-gate 
79*b9175c69SKenjiro Tsuji 		if ((ptr = defread_r("SYSLOG_UID_MAPPING=", defp)) != NULL &&
807c478bd9Sstevel@tonic-gate 		    strcasecmp("yes", ptr) == 0) {
817c478bd9Sstevel@tonic-gate 			*uid_map = 1;
827c478bd9Sstevel@tonic-gate 		}
83*b9175c69SKenjiro Tsuji 		defclose_r(defp);
847c478bd9Sstevel@tonic-gate 	}
857c478bd9Sstevel@tonic-gate }
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate void
gsscred_set_options()887c478bd9Sstevel@tonic-gate gsscred_set_options()
897c478bd9Sstevel@tonic-gate {
907c478bd9Sstevel@tonic-gate 	int u;
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate 	get_conf_options(&u);
937c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&uid_map_lock);
947c478bd9Sstevel@tonic-gate 	uid_map_opt = u;
957c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&uid_map_lock);
967c478bd9Sstevel@tonic-gate }
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate static int
get_uid_map_opt()997c478bd9Sstevel@tonic-gate get_uid_map_opt()
1007c478bd9Sstevel@tonic-gate {
1017c478bd9Sstevel@tonic-gate 	int u;
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&uid_map_lock);
1047c478bd9Sstevel@tonic-gate 	u = uid_map_opt;
1057c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&uid_map_lock);
1067c478bd9Sstevel@tonic-gate 	return (u);
1077c478bd9Sstevel@tonic-gate }
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate /*
1107c478bd9Sstevel@tonic-gate  * This routine accepts a name in export name format and retrieves
1117c478bd9Sstevel@tonic-gate  * unix credentials associated with it.
1127c478bd9Sstevel@tonic-gate  */
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate OM_uint32
gsscred_expname_to_unix_cred_ext(const gss_buffer_t expName,uid_t * uidOut,gid_t * gidOut,gid_t * gids[],int * gidsLen,int try_mech)1157c478bd9Sstevel@tonic-gate gsscred_expname_to_unix_cred_ext(
1167c478bd9Sstevel@tonic-gate 	const gss_buffer_t expName,
1177c478bd9Sstevel@tonic-gate 	uid_t *uidOut,
1187c478bd9Sstevel@tonic-gate 	gid_t *gidOut,
1197c478bd9Sstevel@tonic-gate 	gid_t *gids[],
1207c478bd9Sstevel@tonic-gate 	int *gidsLen,
1217c478bd9Sstevel@tonic-gate 	int try_mech)
1227c478bd9Sstevel@tonic-gate {
1237c478bd9Sstevel@tonic-gate 	gss_name_t intName;
1247c478bd9Sstevel@tonic-gate 	OM_uint32 minor, major;
1257c478bd9Sstevel@tonic-gate 	const char *mechStr = NULL;
1267c478bd9Sstevel@tonic-gate 	char *nameStr = NULL;
1277c478bd9Sstevel@tonic-gate 	char *whoami = "gsscred_expname_to_unix_cred";
1287c478bd9Sstevel@tonic-gate 	gss_buffer_desc namebuf;
1297c478bd9Sstevel@tonic-gate 	int debug = get_uid_map_opt();
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 	if (uidOut == NULL)
1327c478bd9Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 	if (expName == NULL)
1357c478bd9Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_READ);
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate 	/* first check the mechanism for the mapping */
1387c478bd9Sstevel@tonic-gate 	if (gss_import_name(&minor, expName, (gss_OID)GSS_C_NT_EXPORT_NAME,
139*b9175c69SKenjiro Tsuji 	    &intName) == GSS_S_COMPLETE) {
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 		if (debug) {
1427c478bd9Sstevel@tonic-gate 			gss_union_name_t uintName = (gss_union_name_t)intName;
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 			if (uintName->mech_type)
1457c478bd9Sstevel@tonic-gate 				mechStr = __gss_oid_to_mech(
146*b9175c69SKenjiro Tsuji 				    uintName->mech_type);
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 			major = gss_display_name(&minor, intName,
149*b9175c69SKenjiro Tsuji 			    &namebuf, NULL);
1507c478bd9Sstevel@tonic-gate 			if (major == GSS_S_COMPLETE) {
1517c478bd9Sstevel@tonic-gate 				nameStr = strdup(namebuf.value);
1527c478bd9Sstevel@tonic-gate 				(void) gss_release_buffer(&minor, &namebuf);
1537c478bd9Sstevel@tonic-gate 			}
1547c478bd9Sstevel@tonic-gate 		}
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 		if (try_mech) {
1577c478bd9Sstevel@tonic-gate 			major = gss_pname_to_uid(&minor, intName,
158*b9175c69SKenjiro Tsuji 			    NULL, uidOut);
1597c478bd9Sstevel@tonic-gate 			if (major == GSS_S_COMPLETE) {
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 				if (debug) {
1627c478bd9Sstevel@tonic-gate 					syslog(LOG_AUTH|LOG_DEBUG,
1637c478bd9Sstevel@tonic-gate 					    "%s: mech provided local name"
1647c478bd9Sstevel@tonic-gate 					    " mapping (%s, %s, %d)", whoami,
1657c478bd9Sstevel@tonic-gate 					    mechStr ? mechStr : "<null>",
1667c478bd9Sstevel@tonic-gate 					    nameStr ? nameStr : "<null>",
1677c478bd9Sstevel@tonic-gate 					    *uidOut);
1687c478bd9Sstevel@tonic-gate 					free(nameStr);
1697c478bd9Sstevel@tonic-gate 				}
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 				(void) gss_release_name(&minor, &intName);
1727c478bd9Sstevel@tonic-gate 				if (gids && gidsLen && gidOut)
1737c478bd9Sstevel@tonic-gate 					return (gss_get_group_info(*uidOut,
174*b9175c69SKenjiro Tsuji 					    gidOut, gids, gidsLen));
1757c478bd9Sstevel@tonic-gate 				return (GSS_S_COMPLETE);
1767c478bd9Sstevel@tonic-gate 			}
1777c478bd9Sstevel@tonic-gate 		}
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 		(void) gss_release_name(&minor, &intName);
1807c478bd9Sstevel@tonic-gate 	}
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 	/*
1837c478bd9Sstevel@tonic-gate 	 * we fall back onto the gsscred table to provide the mapping
1847c478bd9Sstevel@tonic-gate 	 * start by making sure that the expName is an export name buffer
1857c478bd9Sstevel@tonic-gate 	 */
1867c478bd9Sstevel@tonic-gate 	major = private_gsscred_expname_to_unix_cred(expName, uidOut, gidOut,
187*b9175c69SKenjiro Tsuji 	    gids, gidsLen);
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	if (debug && major == GSS_S_COMPLETE) {
1907c478bd9Sstevel@tonic-gate 		syslog(LOG_AUTH|LOG_DEBUG,
1917c478bd9Sstevel@tonic-gate 		    "%s: gsscred tbl provided"
1927c478bd9Sstevel@tonic-gate 		    " local name mapping (%s, %s, %d)",
1937c478bd9Sstevel@tonic-gate 		    whoami,
1947c478bd9Sstevel@tonic-gate 		    mechStr ? mechStr : "<unknown>",
1957c478bd9Sstevel@tonic-gate 		    nameStr ? nameStr : "<unknown>",
1967c478bd9Sstevel@tonic-gate 		    *uidOut);
1977c478bd9Sstevel@tonic-gate 		free(nameStr);
1987c478bd9Sstevel@tonic-gate 	} else if (debug) {
1997c478bd9Sstevel@tonic-gate 		syslog(LOG_AUTH|LOG_DEBUG,
2007c478bd9Sstevel@tonic-gate 		    "%s: gsscred tbl could NOT"
2017c478bd9Sstevel@tonic-gate 		    " provide local name mapping (%s, %s)",
2027c478bd9Sstevel@tonic-gate 		    whoami,
2037c478bd9Sstevel@tonic-gate 		    mechStr ? mechStr : "<unknown>",
2047c478bd9Sstevel@tonic-gate 		    nameStr ? nameStr : "<unknown>");
2057c478bd9Sstevel@tonic-gate 		free(nameStr);
2067c478bd9Sstevel@tonic-gate 	}
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	return (major);
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate } /* gsscred_expname_to_unix_cred */
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate OM_uint32
gsscred_expname_to_unix_cred(const gss_buffer_t expName,uid_t * uidOut,gid_t * gidOut,gid_t * gids[],int * gidsLen)2137c478bd9Sstevel@tonic-gate gsscred_expname_to_unix_cred(
2147c478bd9Sstevel@tonic-gate 	const gss_buffer_t expName,
2157c478bd9Sstevel@tonic-gate 	uid_t *uidOut,
2167c478bd9Sstevel@tonic-gate 	gid_t *gidOut,
2177c478bd9Sstevel@tonic-gate 	gid_t *gids[],
2187c478bd9Sstevel@tonic-gate 	int *gidsLen)
2197c478bd9Sstevel@tonic-gate {
2207c478bd9Sstevel@tonic-gate 	return (gsscred_expname_to_unix_cred_ext(expName, uidOut, gidOut, gids,
221*b9175c69SKenjiro Tsuji 	    gidsLen, 1));
2227c478bd9Sstevel@tonic-gate }
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate static const char *expNameTokId = "\x04\x01";
2267c478bd9Sstevel@tonic-gate static const int expNameTokIdLen = 2;
2277c478bd9Sstevel@tonic-gate /*
2287c478bd9Sstevel@tonic-gate  * private routine added to be called from gsscred_name_to_unix_cred
2297c478bd9Sstevel@tonic-gate  * and gsscred_expName_to_unix_cred.
2307c478bd9Sstevel@tonic-gate  */
2317c478bd9Sstevel@tonic-gate static OM_uint32
private_gsscred_expname_to_unix_cred(expName,uidOut,gidOut,gids,gidsLen)2327c478bd9Sstevel@tonic-gate private_gsscred_expname_to_unix_cred(expName, uidOut, gidOut, gids, gidsLen)
2337c478bd9Sstevel@tonic-gate const gss_buffer_t expName;
2347c478bd9Sstevel@tonic-gate uid_t *uidOut;
2357c478bd9Sstevel@tonic-gate gid_t *gidOut;
2367c478bd9Sstevel@tonic-gate gid_t *gids[];
2377c478bd9Sstevel@tonic-gate int *gidsLen;
2387c478bd9Sstevel@tonic-gate {
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	if (expName->length < expNameTokIdLen ||
2417c478bd9Sstevel@tonic-gate 		(memcmp(expName->value, expNameTokId, expNameTokIdLen) != 0))
2427c478bd9Sstevel@tonic-gate 		return (GSS_S_DEFECTIVE_TOKEN);
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 	if (!gss_getGssCredEntry(expName, uidOut))
2457c478bd9Sstevel@tonic-gate 		return (GSS_S_FAILURE);
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 	/* did caller request group info also ? */
2487c478bd9Sstevel@tonic-gate 	if (gids && gidsLen && gidOut)
2497c478bd9Sstevel@tonic-gate 		return (gss_get_group_info(*uidOut, gidOut, gids, gidsLen));
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 	return (GSS_S_COMPLETE);
2527c478bd9Sstevel@tonic-gate }
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate /*
2557c478bd9Sstevel@tonic-gate  * Return a string of the authenticated name.
2567c478bd9Sstevel@tonic-gate  * It's a bit of hack/workaround/longroad but the current intName
2577c478bd9Sstevel@tonic-gate  * passed to gss_display_name insists on returning an empty string.
2587c478bd9Sstevel@tonic-gate  *
2597c478bd9Sstevel@tonic-gate  * Caller must free string memory.
2607c478bd9Sstevel@tonic-gate  */
2617c478bd9Sstevel@tonic-gate static
make_name_str(const gss_name_t intName,const gss_OID mechType)2627c478bd9Sstevel@tonic-gate char *make_name_str(
2637c478bd9Sstevel@tonic-gate 	const gss_name_t intName,
2647c478bd9Sstevel@tonic-gate 	const gss_OID mechType)
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate {
2677c478bd9Sstevel@tonic-gate 	gss_buffer_desc expName = GSS_C_EMPTY_BUFFER;
2687c478bd9Sstevel@tonic-gate 	OM_uint32 major, minor;
2697c478bd9Sstevel@tonic-gate 	gss_name_t canonName;
2707c478bd9Sstevel@tonic-gate 	gss_name_t iName;
2717c478bd9Sstevel@tonic-gate 	gss_buffer_desc namebuf;
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 	if (major = gss_canonicalize_name(&minor, intName,
2747c478bd9Sstevel@tonic-gate 				mechType, &canonName))
2757c478bd9Sstevel@tonic-gate 		return (NULL);
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 	major = gss_export_name(&minor, canonName, &expName);
2787c478bd9Sstevel@tonic-gate 	(void) gss_release_name(&minor, &canonName);
2797c478bd9Sstevel@tonic-gate 	if (major)
2807c478bd9Sstevel@tonic-gate 		return (NULL);
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 	if (gss_import_name(&minor, &expName,
2837c478bd9Sstevel@tonic-gate 			    (gss_OID)GSS_C_NT_EXPORT_NAME,
2847c478bd9Sstevel@tonic-gate 			    &iName) == GSS_S_COMPLETE) {
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 		major = gss_display_name(&minor, iName, &namebuf, NULL);
2877c478bd9Sstevel@tonic-gate 		if (major == GSS_S_COMPLETE) {
2887c478bd9Sstevel@tonic-gate 			char *s;
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 			if (namebuf.value)
2917c478bd9Sstevel@tonic-gate 				s = strdup(namebuf.value);
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 			(void) gss_release_buffer(&minor, &namebuf);
2947c478bd9Sstevel@tonic-gate 			(void) gss_release_buffer(&minor, &expName);
2957c478bd9Sstevel@tonic-gate 			(void) gss_release_buffer(&minor, (gss_buffer_t)iName);
2967c478bd9Sstevel@tonic-gate 			return (s);
2977c478bd9Sstevel@tonic-gate 		}
2987c478bd9Sstevel@tonic-gate 		(void) gss_release_buffer(&minor, (gss_buffer_t)iName);
2997c478bd9Sstevel@tonic-gate 	}
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	(void) gss_release_buffer(&minor, &expName);
3027c478bd9Sstevel@tonic-gate 	return (NULL);
3037c478bd9Sstevel@tonic-gate }
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate /*
3067c478bd9Sstevel@tonic-gate  * This routine accepts a name in gss internal name format together with
3077c478bd9Sstevel@tonic-gate  * a mechanim OID and retrieves a unix credentials for that entity.
3087c478bd9Sstevel@tonic-gate  */
3097c478bd9Sstevel@tonic-gate OM_uint32
gsscred_name_to_unix_cred_ext(const gss_name_t intName,const gss_OID mechType,uid_t * uidOut,gid_t * gidOut,gid_t * gids[],int * gidsLen,int try_mech)3107c478bd9Sstevel@tonic-gate gsscred_name_to_unix_cred_ext(
3117c478bd9Sstevel@tonic-gate 	const gss_name_t intName,
3127c478bd9Sstevel@tonic-gate 	const gss_OID mechType,
3137c478bd9Sstevel@tonic-gate 	uid_t *uidOut,
3147c478bd9Sstevel@tonic-gate 	gid_t *gidOut,
3157c478bd9Sstevel@tonic-gate 	gid_t *gids[],
3167c478bd9Sstevel@tonic-gate 	int *gidsLen,
3177c478bd9Sstevel@tonic-gate 	int try_mech)
3187c478bd9Sstevel@tonic-gate {
3197c478bd9Sstevel@tonic-gate 	gss_name_t canonName;
3207c478bd9Sstevel@tonic-gate 	gss_buffer_desc expName = GSS_C_EMPTY_BUFFER;
3217c478bd9Sstevel@tonic-gate 	OM_uint32 major, minor;
3227c478bd9Sstevel@tonic-gate 	int debug = get_uid_map_opt();
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	const char *mechStr;
3257c478bd9Sstevel@tonic-gate 	char *whoami = "gsscred_name_to_unix_cred";
3267c478bd9Sstevel@tonic-gate 	gss_buffer_desc namebuf;
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	if (intName == NULL || mechType == NULL)
3297c478bd9Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_READ);
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	if (uidOut == NULL)
3327c478bd9Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	mechStr = __gss_oid_to_mech(mechType);
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	/* first try the mechanism provided mapping */
3377c478bd9Sstevel@tonic-gate 	if (try_mech && gss_pname_to_uid(&minor, intName, mechType, uidOut)
338*b9175c69SKenjiro Tsuji 	    == GSS_S_COMPLETE) {
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 		if (debug) {
3417c478bd9Sstevel@tonic-gate 			char *s = make_name_str(intName, mechType);
3427c478bd9Sstevel@tonic-gate 			syslog(LOG_AUTH|LOG_DEBUG,
3437c478bd9Sstevel@tonic-gate 			    "%s: mech provided local name"
3447c478bd9Sstevel@tonic-gate 			    " mapping (%s, %s, %d)", whoami,
3457c478bd9Sstevel@tonic-gate 			    mechStr ? mechStr : "<null>",
3467c478bd9Sstevel@tonic-gate 			    s ? s : "<null>",
3477c478bd9Sstevel@tonic-gate 			    *uidOut);
3487c478bd9Sstevel@tonic-gate 			free(s);
3497c478bd9Sstevel@tonic-gate 		}
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 		if (gids && gidsLen && gidOut)
3527c478bd9Sstevel@tonic-gate 			return (gss_get_group_info(*uidOut, gidOut, gids,
353*b9175c69SKenjiro Tsuji 			    gidsLen));
3547c478bd9Sstevel@tonic-gate 		return (GSS_S_COMPLETE);
3557c478bd9Sstevel@tonic-gate 	}
3567c478bd9Sstevel@tonic-gate 	/*
3577c478bd9Sstevel@tonic-gate 	 * falling back onto the gsscred table to provide the mapping
3587c478bd9Sstevel@tonic-gate 	 * start by canonicalizing the passed in name and then export it
3597c478bd9Sstevel@tonic-gate 	 */
3607c478bd9Sstevel@tonic-gate 	if (major = gss_canonicalize_name(&minor, intName,
361*b9175c69SKenjiro Tsuji 	    mechType, &canonName))
3627c478bd9Sstevel@tonic-gate 		return (major);
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	major = gss_export_name(&minor, canonName, &expName);
3657c478bd9Sstevel@tonic-gate 	(void) gss_release_name(&minor, &canonName);
3667c478bd9Sstevel@tonic-gate 	if (major)
3677c478bd9Sstevel@tonic-gate 		return (major);
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	major = private_gsscred_expname_to_unix_cred(&expName, uidOut, gidOut,
370*b9175c69SKenjiro Tsuji 	    gids, gidsLen);
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	if (debug) {
3747c478bd9Sstevel@tonic-gate 		gss_name_t iName;
3757c478bd9Sstevel@tonic-gate 		OM_uint32 maj;
3767c478bd9Sstevel@tonic-gate 		char *nameStr = NULL;
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 		if (gss_import_name(&minor, &expName,
379*b9175c69SKenjiro Tsuji 		    (gss_OID)GSS_C_NT_EXPORT_NAME, &iName) == GSS_S_COMPLETE) {
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 			maj = gss_display_name(&minor, iName, &namebuf,
382*b9175c69SKenjiro Tsuji 			    NULL);
3837c478bd9Sstevel@tonic-gate 			(void) gss_release_buffer(&minor, (gss_buffer_t)iName);
3847c478bd9Sstevel@tonic-gate 			if (maj == GSS_S_COMPLETE) {
3857c478bd9Sstevel@tonic-gate 				nameStr = strdup(namebuf.value);
3867c478bd9Sstevel@tonic-gate 				(void) gss_release_buffer(&minor, &namebuf);
3877c478bd9Sstevel@tonic-gate 			}
3887c478bd9Sstevel@tonic-gate 		}
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 		if (major == GSS_S_COMPLETE)
3917c478bd9Sstevel@tonic-gate 			syslog(LOG_AUTH|LOG_DEBUG,
3927c478bd9Sstevel@tonic-gate 			    "%s: gsscred tbl provided"
3937c478bd9Sstevel@tonic-gate 			    " local name mapping (%s, %s, %d)",
3947c478bd9Sstevel@tonic-gate 			    whoami,
3957c478bd9Sstevel@tonic-gate 			    mechStr ? mechStr : "<unknown>",
3967c478bd9Sstevel@tonic-gate 			    nameStr ? nameStr : "<unknown>",
3977c478bd9Sstevel@tonic-gate 			    *uidOut);
3987c478bd9Sstevel@tonic-gate 		else
3997c478bd9Sstevel@tonic-gate 			syslog(LOG_AUTH|LOG_DEBUG,
4007c478bd9Sstevel@tonic-gate 			    "%s: gsscred tbl could NOT"
4017c478bd9Sstevel@tonic-gate 			    " provide local name mapping (%s, %s)",
4027c478bd9Sstevel@tonic-gate 			    whoami,
4037c478bd9Sstevel@tonic-gate 			    mechStr ? mechStr : "<unknown>",
4047c478bd9Sstevel@tonic-gate 			    nameStr ? nameStr : "<unknown>");
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 		free(nameStr);
4077c478bd9Sstevel@tonic-gate 	}
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	(void) gss_release_buffer(&minor, &expName);
4107c478bd9Sstevel@tonic-gate 	return (major);
4117c478bd9Sstevel@tonic-gate } /* gsscred_name_to_unix_cred */
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate OM_uint32
gsscred_name_to_unix_cred(const gss_name_t intName,const gss_OID mechType,uid_t * uidOut,gid_t * gidOut,gid_t * gids[],int * gidsLen)4157c478bd9Sstevel@tonic-gate gsscred_name_to_unix_cred(
4167c478bd9Sstevel@tonic-gate 	const gss_name_t intName,
4177c478bd9Sstevel@tonic-gate 	const gss_OID mechType,
4187c478bd9Sstevel@tonic-gate 	uid_t *uidOut,
4197c478bd9Sstevel@tonic-gate 	gid_t *gidOut,
4207c478bd9Sstevel@tonic-gate 	gid_t *gids[],
4217c478bd9Sstevel@tonic-gate 	int *gidsLen)
4227c478bd9Sstevel@tonic-gate {
4237c478bd9Sstevel@tonic-gate 	return (gsscred_name_to_unix_cred_ext(intName, mechType,
424*b9175c69SKenjiro Tsuji 	    uidOut, gidOut, gids, gidsLen, 1));
4257c478bd9Sstevel@tonic-gate }
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate /*
4307c478bd9Sstevel@tonic-gate  * This routine accepts a unix uid, and retrieves the group id
4317c478bd9Sstevel@tonic-gate  * and supplamentery group ids for that uid.
4327c478bd9Sstevel@tonic-gate  * Callers should be aware that the supplamentary group ids
4337c478bd9Sstevel@tonic-gate  * array may be empty even when this function returns success.
4347c478bd9Sstevel@tonic-gate  */
4357c478bd9Sstevel@tonic-gate OM_uint32
gss_get_group_info(uid,gidOut,gids,gidsLen)4367c478bd9Sstevel@tonic-gate gss_get_group_info(uid, gidOut, gids, gidsLen)
4377c478bd9Sstevel@tonic-gate const uid_t uid;
4387c478bd9Sstevel@tonic-gate gid_t *gidOut;
4397c478bd9Sstevel@tonic-gate gid_t *gids[];
4407c478bd9Sstevel@tonic-gate int *gidsLen;
4417c478bd9Sstevel@tonic-gate {
4427c478bd9Sstevel@tonic-gate 	struct passwd *pw;
4437c478bd9Sstevel@tonic-gate 	int maxgroups;
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	/* check for output parameters */
4467c478bd9Sstevel@tonic-gate 	if (gidOut == NULL || gids == NULL || gidsLen == NULL)
4477c478bd9Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	*gids = NULL;
4507c478bd9Sstevel@tonic-gate 	*gidsLen = 0;
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 	/* determine maximum number of groups possible */
4537c478bd9Sstevel@tonic-gate 	maxgroups = sysconf(_SC_NGROUPS_MAX);
4547c478bd9Sstevel@tonic-gate 	if (maxgroups < 1)
4557c478bd9Sstevel@tonic-gate 	    maxgroups = 16;
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	if ((pw = getpwuid(uid)) == NULL)
4587c478bd9Sstevel@tonic-gate 	    return (GSS_S_FAILURE);
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	/*
4617c478bd9Sstevel@tonic-gate 	 * we allocate for the maximum number of groups
4627c478bd9Sstevel@tonic-gate 	 * we do not reclaim the space when the actual number
4637c478bd9Sstevel@tonic-gate 	 * is lower, just set the size approprately.
4647c478bd9Sstevel@tonic-gate 	 */
4657c478bd9Sstevel@tonic-gate 	*gids = (gid_t *)calloc(maxgroups, sizeof (gid_t));
4667c478bd9Sstevel@tonic-gate 	if (*gids == NULL)
4677c478bd9Sstevel@tonic-gate 	    return (GSS_S_FAILURE);
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	*gidOut = pw->pw_gid;
4707c478bd9Sstevel@tonic-gate 	(*gids)[0] = pw->pw_gid;
4717c478bd9Sstevel@tonic-gate 	*gidsLen = _getgroupsbymember(pw->pw_name, *gids, maxgroups, 1);
4727c478bd9Sstevel@tonic-gate 	/*
4737c478bd9Sstevel@tonic-gate 	 * we will try to remove the duplicate entry from the groups
4747c478bd9Sstevel@tonic-gate 	 * array.  This can cause the group array to be empty.
4757c478bd9Sstevel@tonic-gate 	 */
4767c478bd9Sstevel@tonic-gate 	if (*gidsLen < 1)
4777c478bd9Sstevel@tonic-gate 	{
4787c478bd9Sstevel@tonic-gate 		free(*gids);
4797c478bd9Sstevel@tonic-gate 		*gids = NULL;
4807c478bd9Sstevel@tonic-gate 		return (GSS_S_FAILURE);
4817c478bd9Sstevel@tonic-gate 	} else if (*gidsLen == 1) {
4827c478bd9Sstevel@tonic-gate 		free(*gids);
4837c478bd9Sstevel@tonic-gate 		*gids = NULL;
4847c478bd9Sstevel@tonic-gate 		*gidsLen = 0;
4857c478bd9Sstevel@tonic-gate 	} else {
4867c478bd9Sstevel@tonic-gate 		/* length is atleast 2 */
4877c478bd9Sstevel@tonic-gate 		*gidsLen = *gidsLen -1;
4887c478bd9Sstevel@tonic-gate 		(*gids)[0] = (*gids)[*gidsLen];
4897c478bd9Sstevel@tonic-gate 	}
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	return (GSS_S_COMPLETE);
4927c478bd9Sstevel@tonic-gate } /* gss_get_group_info */
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate static OM_uint32
gss_pname_to_uid(minor,name,mech_type,uidOut)4967c478bd9Sstevel@tonic-gate gss_pname_to_uid(minor, name, mech_type, uidOut)
4977c478bd9Sstevel@tonic-gate OM_uint32 *minor;
4987c478bd9Sstevel@tonic-gate const gss_name_t name;
4997c478bd9Sstevel@tonic-gate const gss_OID mech_type;
5007c478bd9Sstevel@tonic-gate uid_t *uidOut;
5017c478bd9Sstevel@tonic-gate {
5027c478bd9Sstevel@tonic-gate 	gss_mechanism mech;
5037c478bd9Sstevel@tonic-gate 	gss_union_name_t intName;
5047c478bd9Sstevel@tonic-gate 	gss_name_t mechName = NULL;
5057c478bd9Sstevel@tonic-gate 	OM_uint32 major, tmpMinor;
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	if (!minor)
5087c478bd9Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 	*minor = 0;
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 	if (uidOut == NULL)
5137c478bd9Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 	if (name == NULL)
5167c478bd9Sstevel@tonic-gate 		return (GSS_S_CALL_INACCESSIBLE_READ);
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	intName = (gss_union_name_t)name;
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	if (mech_type != NULL)
5217c478bd9Sstevel@tonic-gate 		mech = __gss_get_mechanism(mech_type);
5227c478bd9Sstevel@tonic-gate 	else {
5237c478bd9Sstevel@tonic-gate 		/*
5247c478bd9Sstevel@tonic-gate 		 * if this is a MN, then try using the mech
5257c478bd9Sstevel@tonic-gate 		 * from the name; otherwise ask for default
5267c478bd9Sstevel@tonic-gate 		 */
5277c478bd9Sstevel@tonic-gate 		mech = __gss_get_mechanism(intName->mech_type);
5287c478bd9Sstevel@tonic-gate 	}
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 	if (mech == NULL || mech->pname_to_uid == NULL)
5317c478bd9Sstevel@tonic-gate 		return (GSS_S_UNAVAILABLE);
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 	/* may need to import the name if this is not MN */
5347c478bd9Sstevel@tonic-gate 	if (intName->mech_type == NULL) {
5357c478bd9Sstevel@tonic-gate 		major = __gss_import_internal_name(minor,
5367c478bd9Sstevel@tonic-gate 				mech_type, intName,
5377c478bd9Sstevel@tonic-gate 				&mechName);
5387c478bd9Sstevel@tonic-gate 		if (major != GSS_S_COMPLETE)
5397c478bd9Sstevel@tonic-gate 			return (major);
5407c478bd9Sstevel@tonic-gate 	} else
5417c478bd9Sstevel@tonic-gate 		mechName = intName->mech_name;
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 	/* now call the mechanism's pname function to do the work */
5457c478bd9Sstevel@tonic-gate 	major = mech->pname_to_uid(mech->context, minor, mechName, uidOut);
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 	if (intName->mech_name != mechName)
5487c478bd9Sstevel@tonic-gate 		(void) __gss_release_internal_name(&tmpMinor, &mech->mech_type,
5497c478bd9Sstevel@tonic-gate 				&mechName);
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 	return (major);
5527c478bd9Sstevel@tonic-gate } /* gss_pname_to_uid */
553