/*
- * Copyright (c) 1996, 1998-2002 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 1996, 1998-2004 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <pwd.h>
+#include <grp.h>
#ifdef HAVE_GETSPNAM
# include <shadow.h>
#endif /* HAVE_GETSPNAM */
#if defined(HAVE_GETPRPWNAM) && defined(__alpha)
int crypt_type = INT_MAX;
#endif /* HAVE_GETPRPWNAM && __alpha */
-static struct rbtree *cache_byuid;
-static struct rbtree *cache_byname;
+static struct rbtree *pwcache_byuid, *pwcache_byname;
+static struct rbtree *grcache_bygid, *grcache_byname;
-static int cmp_byuid __P((const VOID *, const VOID *));
-static int cmp_byname __P((const VOID *, const VOID *));
+static int cmp_pwuid __P((const VOID *, const VOID *));
+static int cmp_pwnam __P((const VOID *, const VOID *));
static void pw_free __P((VOID *));
+static int cmp_grgid __P((const VOID *, const VOID *));
+static int cmp_grnam __P((const VOID *, const VOID *));
/*
* Compare by uid.
*/
static int
-cmp_byuid(v1, v2)
+cmp_pwuid(v1, v2)
const VOID *v1;
const VOID *v2;
{
* Compare by user name.
*/
static int
-cmp_byname(v1, v2)
+cmp_pwnam(v1, v2)
const VOID *v1;
const VOID *v2;
{
* Dynamically allocate space for a struct password and the constituent parts
* that we care about. Fills in pw_passwd from shadow file.
*/
-struct passwd *
+static struct passwd *
sudo_pwdup(pw)
const struct passwd *pw;
{
struct rbnode *node;
key.pw_uid = uid;
- if ((node = rbfind(cache_byuid, &key)) != NULL)
+ if ((node = rbfind(pwcache_byuid, &key)) != NULL)
return((struct passwd *) node->data);
if ((pw = getpwuid(uid)) == NULL)
return(NULL);
else
pw = sudo_pwdup(pw);
- rbinsert(cache_byname, (VOID *) pw);
- rbinsert(cache_byuid, (VOID *) pw);
+ rbinsert(pwcache_byname, (VOID *) pw);
+ rbinsert(pwcache_byuid, (VOID *) pw);
return(pw);
}
struct rbnode *node;
key.pw_name = (char *) name;
- if ((node = rbfind(cache_byname, &key)) != NULL)
+ if ((node = rbfind(pwcache_byname, &key)) != NULL)
return((struct passwd *) node->data);
if ((pw = getpwnam(name)) == NULL)
return(NULL);
else
pw = sudo_pwdup(pw);
- rbinsert(cache_byname, (VOID *) pw);
- rbinsert(cache_byuid, (VOID *) pw);
+ rbinsert(pwcache_byname, (VOID *) pw);
+ rbinsert(pwcache_byuid, (VOID *) pw);
return(pw);
}
pw->pw_name = (char *)pw + sizeof(struct passwd);
(void) snprintf(pw->pw_name, MAX_UID_T_LEN + 1, "#%lu",
(unsigned long) uid);
- rbinsert(cache_byname, (VOID *) pw);
- rbinsert(cache_byuid, (VOID *) pw);
+ rbinsert(pwcache_byname, (VOID *) pw);
+ rbinsert(pwcache_byuid, (VOID *) pw);
return(pw);
}
*/
struct passwd *
sudo_fakepwnam(user)
- char *user;
+ const char *user;
{
struct passwd *pw;
size_t len;
pw->pw_uid = (uid_t) atoi(user + 1);
pw->pw_name = (char *)pw + sizeof(struct passwd);
strlcpy(pw->pw_name, user, len + 1);
- rbinsert(cache_byname, (VOID *) pw);
- rbinsert(cache_byuid, (VOID *) pw);
+ rbinsert(pwcache_byname, (VOID *) pw);
+ rbinsert(pwcache_byuid, (VOID *) pw);
return(pw);
}
#ifdef HAVE_GETAUTHUID
setauthent();
#endif
- cache_byuid = rbcreate(cmp_byuid);
- cache_byname = rbcreate(cmp_byname);
+ pwcache_byuid = rbcreate(cmp_pwuid);
+ pwcache_byname = rbcreate(cmp_pwnam);
}
void
#ifdef HAVE_GETAUTHUID
endauthent();
#endif
- rbdestroy(cache_byuid, pw_free);
- cache_byuid = NULL;
- rbdestroy(cache_byname, NULL);
- cache_byname = NULL;
+ rbdestroy(pwcache_byuid, pw_free);
+ pwcache_byuid = NULL;
+ rbdestroy(pwcache_byname, NULL);
+ pwcache_byname = NULL;
}
static void
zero_bytes(pw->pw_passwd, strlen(pw->pw_passwd));
free(pw);
}
+
+/*
+ * Compare by gid.
+ */
+static int
+cmp_grgid(v1, v2)
+ const VOID *v1;
+ const VOID *v2;
+{
+ const struct group *grp1 = (const struct group *) v1;
+ const struct group *grp2 = (const struct group *) v2;
+ return(grp1->gr_gid - grp2->gr_gid);
+}
+
+/*
+ * Compare by group name.
+ */
+static int
+cmp_grnam(v1, v2)
+ const VOID *v1;
+ const VOID *v2;
+{
+ const struct group *grp1 = (const struct group *) v1;
+ const struct group *grp2 = (const struct group *) v2;
+ return(strcmp(grp1->gr_name, grp2->gr_name));
+}
+
+void
+sudo_setgrent()
+{
+ setgrent();
+ grcache_bygid = rbcreate(cmp_grgid);
+ grcache_byname = rbcreate(cmp_grnam);
+}
+
+void
+sudo_endgrent()
+{
+ endgrent();
+ rbdestroy(grcache_bygid, free);
+ grcache_bygid = NULL;
+ rbdestroy(grcache_byname, NULL);
+ grcache_byname = NULL;
+}
+
+static struct group *
+sudo_grdup(gr)
+ const struct group *gr;
+{
+ char *cp;
+ size_t nsize, psize, csize, num, total, len;
+ struct group *newgr;
+
+ /* Allocate in one big chunk for easy freeing. */
+ nsize = psize = csize = num = 0;
+ total = sizeof(struct group);
+ if (gr->gr_name) {
+ nsize = strlen(gr->gr_name) + 1;
+ total += nsize;
+ }
+ if (gr->gr_passwd) {
+ psize = strlen(gr->gr_passwd) + 1;
+ total += psize;
+ }
+ if (gr->gr_mem) {
+ for (num = 0; gr->gr_mem[num] != NULL; num++)
+ total += strlen(gr->gr_mem[num]) + 1;
+ num++;
+ total += sizeof(char *) * num;
+ }
+ if ((cp = malloc(total)) == NULL)
+ return (NULL);
+ newgr = (struct group *)cp;
+
+ /*
+ * Copy in group contents and make strings relative to space
+ * at the end of the buffer.
+ */
+ (void)memcpy(newgr, gr, sizeof(struct group));
+ cp += sizeof(struct group);
+ if (nsize) {
+ (void)memcpy(cp, gr->gr_name, nsize);
+ newgr->gr_name = cp;
+ cp += nsize;
+ }
+ if (psize) {
+ (void)memcpy(cp, gr->gr_passwd, psize);
+ newgr->gr_passwd = cp;
+ cp += psize;
+ }
+ if (gr->gr_mem) {
+ newgr->gr_mem = (char **)cp;
+ cp += sizeof(char *) * num;
+ for (num = 0; gr->gr_mem[num] != NULL; num++) {
+ len = strlen(gr->gr_mem[num]) + 1;
+ memcpy(cp, gr->gr_mem[num], len);
+ newgr->gr_mem[num] = cp;
+ cp += len;
+ }
+ newgr->gr_mem[num] = NULL;
+ }
+
+ return (newgr);
+}
+
+/*
+ * Get a group entry by gid and allocate space for it.
+ */
+struct group *
+sudo_getgruid(gid)
+ gid_t gid;
+{
+ struct group key, *gr;
+ struct rbnode *node;
+
+ key.gr_gid = gid;
+ if ((node = rbfind(grcache_bygid, &key)) != NULL)
+ return((struct group *) node->data);
+ if ((gr = getgrgid(gid)) == NULL)
+ return(NULL);
+ else
+ gr = sudo_grdup(gr);
+ rbinsert(grcache_byname, (VOID *) gr);
+ rbinsert(grcache_bygid, (VOID *) gr);
+ return(gr);
+}
+
+/*
+ * Get a group entry by name and allocate space for it.
+ */
+struct group *
+sudo_getgrnam(name)
+ const char *name;
+{
+ struct group key, *gr;
+ struct rbnode *node;
+
+ key.gr_name = (char *) name;
+ if ((node = rbfind(grcache_byname, &key)) != NULL)
+ return((struct group *) node->data);
+ if ((gr = getgrnam(name)) == NULL)
+ return(NULL);
+ else
+ gr = sudo_grdup(gr);
+ rbinsert(grcache_byname, (VOID *) gr);
+ rbinsert(grcache_bygid, (VOID *) gr);
+ return(gr);
+}
+
extern int sudo_edit __P((int, char **));
extern char **rebuild_env __P((char **, int, int));
extern char **zero_env __P((char **));
-extern struct passwd *sudo_fakepwnam __P((const char *));
-extern struct passwd *sudo_getpwnam __P((const char *));
-extern struct passwd *sudo_getpwuid __P((uid_t));
/*
* Globals
*/
initial_setup();
sudo_setpwent();
+ sudo_setgrent();
/* Parse our arguments. */
sudo_mode = parse_args(Argc, Argv);
struct passwd *pw;
if (*def_timestampowner == '#')
- pw = getpwuid(atoi(def_timestampowner + 1));
+ pw = sudo_getpwuid(atoi(def_timestampowner + 1));
else
- pw = getpwnam(def_timestampowner);
+ pw = sudo_getpwnam(def_timestampowner);
if (!pw)
log_error(0, "timestamp owner (%s): No such user",
def_timestampowner);
/* Close the password and group files */
sudo_endpwent();
- endgrent();
+ sudo_endgrent();
/* Install the real environment. */
environ = new_environ;
/* It is now safe to use log_error() and set_perms() */
+ if ((user_ngroups = getgroups(0, NULL)) > 0) {
+ user_groups = emalloc2(user_ngroups, sizeof(gid_t));
+ if (getgroups(user_ngroups, user_groups) < 0)
+ log_error(USE_ERRNO|MSG_ONLY, "can't get group vector");
+ }
+
if (def_fqdn)
set_fqdn(); /* may call log_error() */