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