#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);
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 *);
static void
get_conf_options(int *uid_map)
{
int flags;
char *ptr;
void *defp;
static char *conffile = "/etc/gss/gsscred.conf";
*uid_map = 0;
if ((defp = defopen_r(conffile)) != NULL) {
flags = defcntl_r(DC_GETFLAGS, 0, defp);
TURNOFF(flags, DC_CASE);
(void) defcntl_r(DC_SETFLAGS, flags, defp);
if ((ptr = defread_r("SYSLOG_UID_MAPPING=", defp)) != NULL &&
strcasecmp("yes", ptr) == 0) {
*uid_map = 1;
}
defclose_r(defp);
}
}
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);
}
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);
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);
}
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);
}
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;
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);
if (gids && gidsLen && gidOut)
return (gss_get_group_info(*uidOut, gidOut, gids, gidsLen));
return (GSS_S_COMPLETE);
}
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);
}
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);
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);
}
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);
}
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));
}
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;
if (gidOut == NULL || gids == NULL || gidsLen == NULL)
return (GSS_S_CALL_INACCESSIBLE_WRITE);
*gids = NULL;
*gidsLen = 0;
maxgroups = sysconf(_SC_NGROUPS_MAX);
if (maxgroups < 1)
maxgroups = 16;
if ((pw = getpwuid(uid)) == NULL)
return (GSS_S_FAILURE);
*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);
if (*gidsLen < 1)
{
free(*gids);
*gids = NULL;
return (GSS_S_FAILURE);
} else if (*gidsLen == 1) {
free(*gids);
*gids = NULL;
*gidsLen = 0;
} else {
*gidsLen = *gidsLen -1;
(*gids)[0] = (*gids)[*gidsLen];
}
return (GSS_S_COMPLETE);
}
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 {
mech = __gss_get_mechanism(intName->mech_type);
}
if (mech == NULL || mech->pname_to_uid == NULL)
return (GSS_S_UNAVAILABLE);
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;
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);
}