summaryrefslogtreecommitdiff
path: root/usr/src/lib/libgss/gssd_pname_to_uid.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libgss/gssd_pname_to_uid.c')
-rw-r--r--usr/src/lib/libgss/gssd_pname_to_uid.c569
1 files changed, 569 insertions, 0 deletions
diff --git a/usr/src/lib/libgss/gssd_pname_to_uid.c b/usr/src/lib/libgss/gssd_pname_to_uid.c
new file mode 100644
index 0000000000..f713bd3372
--- /dev/null
+++ b/usr/src/lib/libgss/gssd_pname_to_uid.c
@@ -0,0 +1,569 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <pwd.h>
+#include <grp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <thread.h>
+#include <synch.h>
+#include <syslog.h>
+#include <deflt.h>
+#include <mechglueP.h>
+#include "../../cmd/gss/gsscred/gsscred.h"
+
+static mutex_t uid_map_lock = DEFAULTMUTEX;
+static int uid_map_opt = 0;
+
+extern int _getgroupsbymember(const char *, gid_t[], int, int);
+
+/* local function used to call a mechanisms pname_to_uid */
+static OM_uint32 gss_pname_to_uid(OM_uint32*, const gss_name_t,
+ const gss_OID, uid_t *);
+
+static OM_uint32 private_gsscred_expname_to_unix_cred(const gss_buffer_t,
+ uid_t *, gid_t *, gid_t **, int *);
+
+/*
+ * The gsscred functions will first attempt to call the
+ * mechanism'm pname_to_uid function. In case this function
+ * returns an error or if it is not provided by a mechanism
+ * then the functions will attempt to look up the principal
+ * in the gsscred table.
+ * It is envisioned that the pname_to_uid function will be
+ * provided by only a few mechanism, which may have the principal
+ * name to unix credential mapping inherently present.
+ */
+
+/*
+ * Fetch gsscred options from conf file.
+ */
+static void
+get_conf_options(int *uid_map)
+{
+ register int flags;
+ char *ptr;
+ static char *conffile = "/etc/gss/gsscred.conf";
+ static mutex_t deflt_lock = DEFAULTMUTEX;
+
+
+ *uid_map = 0;
+ /*
+ * hold the lock for the deflt file access as its
+ * interface does not appear to be mt-safe
+ */
+ (void) mutex_lock(&deflt_lock);
+ if (defopen(conffile) == 0) {
+ flags = defcntl(DC_GETFLAGS, 0);
+ /* ignore case */
+ TURNOFF(flags, DC_CASE);
+ (void) defcntl(DC_SETFLAGS, flags);
+
+ if ((ptr = defread("SYSLOG_UID_MAPPING=")) != NULL &&
+ strcasecmp("yes", ptr) == 0) {
+ (void) defopen((char *)NULL);
+ (void) mutex_unlock(&deflt_lock);
+ *uid_map = 1;
+ return;
+ }
+ (void) defopen((char *)NULL);
+ }
+ (void) mutex_unlock(&deflt_lock);
+}
+
+void
+gsscred_set_options()
+{
+ int u;
+
+ get_conf_options(&u);
+ (void) mutex_lock(&uid_map_lock);
+ uid_map_opt = u;
+ (void) mutex_unlock(&uid_map_lock);
+}
+
+static int
+get_uid_map_opt()
+{
+ int u;
+
+ (void) mutex_lock(&uid_map_lock);
+ u = uid_map_opt;
+ (void) mutex_unlock(&uid_map_lock);
+ return (u);
+}
+
+/*
+ * This routine accepts a name in export name format and retrieves
+ * unix credentials associated with it.
+ */
+
+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)
+{
+ gss_name_t intName;
+ OM_uint32 minor, major;
+ const char *mechStr = NULL;
+ char *nameStr = NULL;
+ char *whoami = "gsscred_expname_to_unix_cred";
+ gss_buffer_desc namebuf;
+ int debug = get_uid_map_opt();
+
+ if (uidOut == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (expName == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ /* first check the mechanism for the mapping */
+ if (gss_import_name(&minor, expName, (gss_OID)GSS_C_NT_EXPORT_NAME,
+ &intName) == GSS_S_COMPLETE) {
+
+ if (debug) {
+ gss_union_name_t uintName = (gss_union_name_t)intName;
+
+ if (uintName->mech_type)
+ mechStr = __gss_oid_to_mech(
+ uintName->mech_type);
+
+ major = gss_display_name(&minor, intName,
+ &namebuf, NULL);
+ if (major == GSS_S_COMPLETE) {
+ nameStr = strdup(namebuf.value);
+ (void) gss_release_buffer(&minor, &namebuf);
+ }
+ }
+
+ if (try_mech) {
+ major = gss_pname_to_uid(&minor, intName,
+ NULL, uidOut);
+ if (major == GSS_S_COMPLETE) {
+
+ if (debug) {
+ syslog(LOG_AUTH|LOG_DEBUG,
+ "%s: mech provided local name"
+ " mapping (%s, %s, %d)", whoami,
+ mechStr ? mechStr : "<null>",
+ nameStr ? nameStr : "<null>",
+ *uidOut);
+ free(nameStr);
+ }
+
+ (void) gss_release_name(&minor, &intName);
+ if (gids && gidsLen && gidOut)
+ return (gss_get_group_info(*uidOut,
+ gidOut,
+ gids,
+ gidsLen));
+ return (GSS_S_COMPLETE);
+ }
+ }
+
+ (void) gss_release_name(&minor, &intName);
+ }
+
+ /*
+ * we fall back onto the gsscred table to provide the mapping
+ * start by making sure that the expName is an export name buffer
+ */
+ major = private_gsscred_expname_to_unix_cred(expName, uidOut, gidOut,
+ gids, gidsLen);
+
+ if (debug && major == GSS_S_COMPLETE) {
+ syslog(LOG_AUTH|LOG_DEBUG,
+ "%s: gsscred tbl provided"
+ " local name mapping (%s, %s, %d)",
+ whoami,
+ mechStr ? mechStr : "<unknown>",
+ nameStr ? nameStr : "<unknown>",
+ *uidOut);
+ free(nameStr);
+ } else if (debug) {
+ syslog(LOG_AUTH|LOG_DEBUG,
+ "%s: gsscred tbl could NOT"
+ " provide local name mapping (%s, %s)",
+ whoami,
+ mechStr ? mechStr : "<unknown>",
+ nameStr ? nameStr : "<unknown>");
+ free(nameStr);
+ }
+
+ return (major);
+
+} /* gsscred_expname_to_unix_cred */
+
+OM_uint32
+gsscred_expname_to_unix_cred(
+ const gss_buffer_t expName,
+ uid_t *uidOut,
+ gid_t *gidOut,
+ gid_t *gids[],
+ int *gidsLen)
+{
+ return (gsscred_expname_to_unix_cred_ext(expName, uidOut, gidOut, gids,
+ gidsLen, 1));
+}
+
+
+static const char *expNameTokId = "\x04\x01";
+static const int expNameTokIdLen = 2;
+/*
+ * private routine added to be called from gsscred_name_to_unix_cred
+ * and gsscred_expName_to_unix_cred.
+ */
+static OM_uint32
+private_gsscred_expname_to_unix_cred(expName, uidOut, gidOut, gids, gidsLen)
+const gss_buffer_t expName;
+uid_t *uidOut;
+gid_t *gidOut;
+gid_t *gids[];
+int *gidsLen;
+{
+
+ if (expName->length < expNameTokIdLen ||
+ (memcmp(expName->value, expNameTokId, expNameTokIdLen) != 0))
+ return (GSS_S_DEFECTIVE_TOKEN);
+
+ if (!gss_getGssCredEntry(expName, uidOut))
+ return (GSS_S_FAILURE);
+
+ /* did caller request group info also ? */
+ if (gids && gidsLen && gidOut)
+ return (gss_get_group_info(*uidOut, gidOut, gids, gidsLen));
+
+ return (GSS_S_COMPLETE);
+}
+
+/*
+ * Return a string of the authenticated name.
+ * It's a bit of hack/workaround/longroad but the current intName
+ * passed to gss_display_name insists on returning an empty string.
+ *
+ * Caller must free string memory.
+ */
+static
+char *make_name_str(
+ const gss_name_t intName,
+ const gss_OID mechType)
+
+{
+ gss_buffer_desc expName = GSS_C_EMPTY_BUFFER;
+ OM_uint32 major, minor;
+ gss_name_t canonName;
+ gss_name_t iName;
+ gss_buffer_desc namebuf;
+
+ if (major = gss_canonicalize_name(&minor, intName,
+ mechType, &canonName))
+ return (NULL);
+
+ major = gss_export_name(&minor, canonName, &expName);
+ (void) gss_release_name(&minor, &canonName);
+ if (major)
+ return (NULL);
+
+ if (gss_import_name(&minor, &expName,
+ (gss_OID)GSS_C_NT_EXPORT_NAME,
+ &iName) == GSS_S_COMPLETE) {
+
+ major = gss_display_name(&minor, iName, &namebuf, NULL);
+ if (major == GSS_S_COMPLETE) {
+ char *s;
+
+ if (namebuf.value)
+ s = strdup(namebuf.value);
+
+ (void) gss_release_buffer(&minor, &namebuf);
+ (void) gss_release_buffer(&minor, &expName);
+ (void) gss_release_buffer(&minor, (gss_buffer_t)iName);
+ return (s);
+ }
+ (void) gss_release_buffer(&minor, (gss_buffer_t)iName);
+ }
+
+ (void) gss_release_buffer(&minor, &expName);
+ return (NULL);
+}
+
+/*
+ * This routine accepts a name in gss internal name format together with
+ * a mechanim OID and retrieves a unix credentials for that entity.
+ */
+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)
+{
+ gss_name_t canonName;
+ gss_buffer_desc expName = GSS_C_EMPTY_BUFFER;
+ OM_uint32 major, minor;
+ int debug = get_uid_map_opt();
+
+ const char *mechStr;
+ char *whoami = "gsscred_name_to_unix_cred";
+ gss_buffer_desc namebuf;
+
+ if (intName == NULL || mechType == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ if (uidOut == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ mechStr = __gss_oid_to_mech(mechType);
+
+ /* first try the mechanism provided mapping */
+ if (try_mech && gss_pname_to_uid(&minor, intName, mechType, uidOut)
+ == GSS_S_COMPLETE) {
+
+ if (debug) {
+ char *s = make_name_str(intName, mechType);
+ syslog(LOG_AUTH|LOG_DEBUG,
+ "%s: mech provided local name"
+ " mapping (%s, %s, %d)", whoami,
+ mechStr ? mechStr : "<null>",
+ s ? s : "<null>",
+ *uidOut);
+ free(s);
+ }
+
+ if (gids && gidsLen && gidOut)
+ return (gss_get_group_info(*uidOut, gidOut, gids,
+ gidsLen));
+ return (GSS_S_COMPLETE);
+ }
+ /*
+ * falling back onto the gsscred table to provide the mapping
+ * start by canonicalizing the passed in name and then export it
+ */
+ if (major = gss_canonicalize_name(&minor, intName,
+ mechType, &canonName))
+ return (major);
+
+ major = gss_export_name(&minor, canonName, &expName);
+ (void) gss_release_name(&minor, &canonName);
+ if (major)
+ return (major);
+
+ major = private_gsscred_expname_to_unix_cred(&expName, uidOut, gidOut,
+ gids, gidsLen);
+
+
+ if (debug) {
+ gss_name_t iName;
+ OM_uint32 maj;
+ char *nameStr = NULL;
+
+ if (gss_import_name(&minor, &expName,
+ (gss_OID)GSS_C_NT_EXPORT_NAME,
+ &iName) == GSS_S_COMPLETE) {
+
+ maj = gss_display_name(&minor, iName, &namebuf,
+ NULL);
+ (void) gss_release_buffer(&minor, (gss_buffer_t)iName);
+ if (maj == GSS_S_COMPLETE) {
+ nameStr = strdup(namebuf.value);
+ (void) gss_release_buffer(&minor, &namebuf);
+ }
+ }
+
+ if (major == GSS_S_COMPLETE)
+ syslog(LOG_AUTH|LOG_DEBUG,
+ "%s: gsscred tbl provided"
+ " local name mapping (%s, %s, %d)",
+ whoami,
+ mechStr ? mechStr : "<unknown>",
+ nameStr ? nameStr : "<unknown>",
+ *uidOut);
+ else
+ syslog(LOG_AUTH|LOG_DEBUG,
+ "%s: gsscred tbl could NOT"
+ " provide local name mapping (%s, %s)",
+ whoami,
+ mechStr ? mechStr : "<unknown>",
+ nameStr ? nameStr : "<unknown>");
+
+ free(nameStr);
+ }
+
+ (void) gss_release_buffer(&minor, &expName);
+ return (major);
+} /* gsscred_name_to_unix_cred */
+
+
+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)
+{
+ return (gsscred_name_to_unix_cred_ext(intName, mechType,
+ uidOut, gidOut,
+ gids, gidsLen, 1));
+}
+
+
+
+/*
+ * This routine accepts a unix uid, and retrieves the group id
+ * and supplamentery group ids for that uid.
+ * Callers should be aware that the supplamentary group ids
+ * array may be empty even when this function returns success.
+ */
+OM_uint32
+gss_get_group_info(uid, gidOut, gids, gidsLen)
+const uid_t uid;
+gid_t *gidOut;
+gid_t *gids[];
+int *gidsLen;
+{
+ struct passwd *pw;
+ int maxgroups;
+
+ /* check for output parameters */
+ if (gidOut == NULL || gids == NULL || gidsLen == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ *gids = NULL;
+ *gidsLen = 0;
+
+ /* determine maximum number of groups possible */
+ maxgroups = sysconf(_SC_NGROUPS_MAX);
+ if (maxgroups < 1)
+ maxgroups = 16;
+
+ if ((pw = getpwuid(uid)) == NULL)
+ return (GSS_S_FAILURE);
+
+ /*
+ * we allocate for the maximum number of groups
+ * we do not reclaim the space when the actual number
+ * is lower, just set the size approprately.
+ */
+ *gids = (gid_t *)calloc(maxgroups, sizeof (gid_t));
+ if (*gids == NULL)
+ return (GSS_S_FAILURE);
+
+ *gidOut = pw->pw_gid;
+ (*gids)[0] = pw->pw_gid;
+ *gidsLen = _getgroupsbymember(pw->pw_name, *gids, maxgroups, 1);
+ /*
+ * we will try to remove the duplicate entry from the groups
+ * array. This can cause the group array to be empty.
+ */
+ if (*gidsLen < 1)
+ {
+ free(*gids);
+ *gids = NULL;
+ return (GSS_S_FAILURE);
+ } else if (*gidsLen == 1) {
+ free(*gids);
+ *gids = NULL;
+ *gidsLen = 0;
+ } else {
+ /* length is atleast 2 */
+ *gidsLen = *gidsLen -1;
+ (*gids)[0] = (*gids)[*gidsLen];
+ }
+
+ return (GSS_S_COMPLETE);
+} /* gss_get_group_info */
+
+
+static OM_uint32
+gss_pname_to_uid(minor, name, mech_type, uidOut)
+OM_uint32 *minor;
+const gss_name_t name;
+const gss_OID mech_type;
+uid_t *uidOut;
+{
+ gss_mechanism mech;
+ gss_union_name_t intName;
+ gss_name_t mechName = NULL;
+ OM_uint32 major, tmpMinor;
+
+ if (!minor)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ *minor = 0;
+
+ if (uidOut == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_WRITE);
+
+ if (name == NULL)
+ return (GSS_S_CALL_INACCESSIBLE_READ);
+
+ intName = (gss_union_name_t)name;
+
+ if (mech_type != NULL)
+ mech = __gss_get_mechanism(mech_type);
+ else {
+ /*
+ * if this is a MN, then try using the mech
+ * from the name; otherwise ask for default
+ */
+ mech = __gss_get_mechanism(intName->mech_type);
+ }
+
+ if (mech == NULL || mech->pname_to_uid == NULL)
+ return (GSS_S_UNAVAILABLE);
+
+ /* may need to import the name if this is not MN */
+ if (intName->mech_type == NULL) {
+ major = __gss_import_internal_name(minor,
+ mech_type, intName,
+ &mechName);
+ if (major != GSS_S_COMPLETE)
+ return (major);
+ } else
+ mechName = intName->mech_name;
+
+
+ /* now call the mechanism's pname function to do the work */
+ major = mech->pname_to_uid(mech->context, minor, mechName, uidOut);
+
+ if (intName->mech_name != mechName)
+ (void) __gss_release_internal_name(&tmpMinor, &mech->mech_type,
+ &mechName);
+
+ return (major);
+} /* gss_pname_to_uid */