/* * static.c * * static idmapping functions for gss principals. * * Copyright (c) 2008 David Härdeman . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include "conffile.h" #include "nfsidmap.h" #include "nfsidmap_plugin.h" /* * Static Translation Methods * * These functions use getpwnam to find uid/gid(s) for gss principals * which are first mapped to local user names using static mappings * in idmapd.conf. */ struct pwbuf { struct passwd pwbuf; char buf[1]; }; struct grbuf { struct group grbuf; char buf[1]; }; struct uid_mapping { LIST_ENTRY (uid_mapping) link; uid_t uid; char * principal; char * localname; }; struct gid_mapping { LIST_ENTRY (gid_mapping) link; gid_t gid; char * principal; char * localgroup; }; static __inline__ u_int8_t uid_hash (uid_t uid) { return uid % 256; } static __inline__ u_int8_t gid_hash (gid_t gid) { return gid % 256; } //Hash tables of uid and guids to principals mappings. //We reuse some queue/hash functions from cfg.c. LIST_HEAD (uid_mappings, uid_mapping) uid_mappings[256]; LIST_HEAD (gid_mappings, gid_mapping) gid_mappings[256]; static struct passwd *static_getpwnam(const char *name, const char *UNUSED(domain), int *err_p) { struct passwd *pw; struct pwbuf *buf; size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX); char *localname; int err; buf = malloc(sizeof(*buf) + buflen); if (!buf) { err = ENOMEM; goto err; } localname = conf_get_str("Static", (char *)name); if (!localname) { err = ENOENT; goto err_free_buf; } again: err = getpwnam_r(localname, &buf->pwbuf, buf->buf, buflen, &pw); if (err == EINTR) goto again; if (!pw) { if (err == 0) err = ENOENT; IDMAP_LOG(0, ("static_getpwnam: localname '%s' for '%s' not found", localname, name)); goto err_free_buf; } IDMAP_LOG(4, ("static_getpwnam: name '%s' mapped to '%s'", name, localname)); *err_p = 0; return pw; err_free_buf: free(buf); err: *err_p = err; return NULL; } static struct group *static_getgrnam(const char *name, const char *UNUSED(domain), int *err_p) { struct group *gr; struct grbuf *buf; size_t buflen = sysconf(_SC_GETGR_R_SIZE_MAX); char *localgroup; int err; buf = malloc(sizeof(*buf) + buflen); if (!buf) { err = ENOMEM; goto err; } localgroup = conf_get_str("Static", (char *)name); if (!localgroup) { err = ENOENT; goto err_free_buf; } again: err = getgrnam_r(localgroup, &buf->grbuf, buf->buf, buflen, &gr); if (err == EINTR) goto again; if (!gr) { if (err == 0) err = ENOENT; IDMAP_LOG(0, ("static_getgrnam: local group '%s' for '%s' not found", localgroup, name)); goto err_free_buf; } IDMAP_LOG(4, ("static_getgrnam: group '%s' mapped to '%s'", name, localgroup)); *err_p = 0; return gr; err_free_buf: free(buf); err: *err_p = err; return NULL; } static int static_gss_princ_to_ids(char *secname, char *princ, uid_t *uid, uid_t *gid, extra_mapping_params **UNUSED(ex)) { struct passwd *pw; int err; /* XXX: Is this necessary? */ if (strcmp(secname, "krb5") != 0 && strcmp(secname, "spkm3") != 0) return -EINVAL; pw = static_getpwnam(princ, NULL, &err); if (pw) { *uid = pw->pw_uid; *gid = pw->pw_gid; free(pw); } return -err; } static int static_gss_princ_to_grouplist(char *secname, char *princ, gid_t *groups, int *ngroups, extra_mapping_params **UNUSED(ex)) { struct passwd *pw; int err; /* XXX: Is this necessary? */ if (strcmp(secname, "krb5") != 0 && strcmp(secname, "spkm3") != 0) return -EINVAL; pw = static_getpwnam(princ, NULL, &err); if (pw) { if (getgrouplist(pw->pw_name, pw->pw_gid, groups, ngroups) < 0) err = -ERANGE; free(pw); } return -err; } static int static_name_to_uid(char *name, uid_t *uid) { struct passwd *pw; int err; pw = static_getpwnam(name, NULL, &err); if (pw) { *uid = pw->pw_uid; free(pw); } return -err; } static int static_name_to_gid(char *name, gid_t *gid) { struct group *gr; int err; gr = static_getgrnam(name, NULL, &err); if (gr) { *gid = gr->gr_gid; free(gr); } return -err; } static int static_uid_to_name(uid_t uid, char *UNUSED(domain), char *name, size_t UNUSED(len)) { struct uid_mapping * um; for (um = LIST_FIRST (&uid_mappings[uid_hash (uid)]); um; um = LIST_NEXT (um, link)) { if (um->uid == uid) { strcpy(name, um->principal); return 0; } } return -ENOENT; } static int static_gid_to_name(gid_t gid, char *UNUSED(domain), char *name, size_t UNUSED(len)) { struct gid_mapping * gm; for (gm = LIST_FIRST (&gid_mappings[gid_hash (gid)]); gm; gm = LIST_NEXT (gm, link)) { if (gm->gid == gid) { strcpy(name, gm->principal); return 0; } } return -ENOENT; } /* * We buffer all UID's for which static mappings is defined in advance, so the * uid_to_name functions will be fast enough. */ static int static_init(void) { int err; struct conf_list * princ_list = NULL; struct conf_list_node * cln, *next; struct uid_mapping * unode; struct gid_mapping * gnode; struct passwd * pw = NULL; struct group * gr = NULL; unsigned int i; //init hash_table first for (i = 0; i < sizeof uid_mappings / sizeof uid_mappings[0]; i++) LIST_INIT (&uid_mappings[i]); if (nfsidmap_conf_path) conf_init_file(nfsidmap_conf_path); //get all principals for which we have mappings princ_list = conf_get_tag_list("Static", NULL); if (!princ_list) { return -ENOENT; } /* As we can not distinguish between mappings for users and groups, we try to * resolve all mappings for both cases. */ //resolve uid of localname account for all such principals and cache it for (cln = TAILQ_FIRST (&princ_list->fields); cln; cln = next) { next = TAILQ_NEXT (cln, link); pw = static_getpwnam(cln->field, NULL, &err); if (!pw) { continue; } unode = calloc (1, sizeof *unode); if (!unode) { warnx("static_init: calloc (1, %lu) failed", (unsigned long)sizeof *unode); free(pw); conf_free_list(princ_list); return -ENOMEM; } unode->uid = pw->pw_uid; unode->principal = strdup(cln->field); unode->localname = conf_get_str("Static", cln->field); if (!unode->localname) { free(pw); free(unode->principal); free(unode); conf_free_list(princ_list); return -ENOENT; } free(pw); LIST_INSERT_HEAD (&uid_mappings[uid_hash(unode->uid)], unode, link); } //resolve gid of localgroup accounts and cache it for (cln = TAILQ_FIRST (&princ_list->fields); cln; cln = next) { next = TAILQ_NEXT (cln, link); gr = static_getgrnam(cln->field, NULL, &err); if (!gr) { continue; } gnode = calloc (1, sizeof *gnode); if (!gnode) { warnx("static_init: calloc (1, %lu) failed", (unsigned long)sizeof *gnode); free(gr); conf_free_list(princ_list); return -ENOMEM; } gnode->gid = gr->gr_gid; gnode->principal = strdup(cln->field); gnode->localgroup = conf_get_str("Static", cln->field); if (!gnode->localgroup) { free(gr); free(gnode->principal); free(gnode); conf_free_list(princ_list); return -ENOENT; } free(gr); LIST_INSERT_HEAD (&gid_mappings[gid_hash(gnode->gid)], gnode, link); } conf_free_list(princ_list); return 0; } struct trans_func static_trans = { .name = "static", .init = static_init, .name_to_uid = static_name_to_uid, .name_to_gid = static_name_to_gid, .uid_to_name = static_uid_to_name, .gid_to_name = static_gid_to_name, .princ_to_ids = static_gss_princ_to_ids, .gss_princ_to_grouplist = static_gss_princ_to_grouplist, }; struct trans_func *libnfsidmap_plugin_init(void) { return (&static_trans); }