#endif /* HAVE_GETAUTHUID */
#include "sudo.h"
+#include "redblack.h"
#ifndef lint
static const char rcsid[] = "$Sudo$";
#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 int cmp_byuid __P((const VOID *, const VOID *));
+static int cmp_byname __P((const VOID *, const VOID *));
+
+/*
+ * Compare by uid.
+ */
+static int
+cmp_byuid(v1, v2)
+ const VOID *v1;
+ const VOID *v2;
+{
+ const struct passwd *pw1 = (const struct passwd *) v1;
+ const struct passwd *pw2 = (const struct passwd *) v2;
+ return(pw1->pw_uid - pw2->pw_uid);
+}
+
+/*
+ * Compare by user name.
+ */
+static int
+cmp_byname(v1, v2)
+ const VOID *v1;
+ const VOID *v2;
+{
+ const struct passwd *pw1 = (const struct passwd *) v1;
+ const struct passwd *pw2 = (const struct passwd *) v2;
+ return(strcmp(pw1->pw_name, pw2->pw_name));
+}
/*
* Return a copy of the encrypted password for the user described by pw.
/*
* Dynamically allocate space for a struct password and the constituent parts
- * that we care about. Fills in pw_passwd from shadow file if necessary.
+ * that we care about. Fills in pw_passwd from shadow file.
*/
struct passwd *
-sudo_pwdup(pw, checkshadow)
+sudo_pwdup(pw)
const struct passwd *pw;
- int checkshadow;
{
char *cp;
const char *pw_passwd, *pw_shell;
struct passwd *newpw;
/* Get shadow password if available. */
- pw_passwd = checkshadow ? sudo_getepw(pw) : pw->pw_passwd;
+ pw_passwd = sudo_getepw(pw);
/* If shell field is empty, expand to _PATH_BSHELL. */
pw_shell = (pw->pw_shell == NULL || pw->pw_shell[0] == '\0')
sudo_getpwuid(uid)
uid_t uid;
{
- struct passwd *pw;
+ struct passwd key, *pw;
+ struct rbnode *node;
+ key.pw_uid = uid;
+ if ((node = rbfind(cache_byuid, &key)) != NULL)
+ return((struct passwd *) node->data);
if ((pw = getpwuid(uid)) == NULL)
return(NULL);
else
- return(sudo_pwdup(pw, 1));
+ pw = sudo_pwdup(pw);
+ rbinsert(cache_byname, (VOID *) pw);
+ rbinsert(cache_byuid, (VOID *) pw);
+ return(pw);
}
/*
sudo_getpwnam(name)
const char *name;
{
- struct passwd *pw;
+ struct passwd key, *pw;
+ struct rbnode *node;
+ key.pw_name = (char *) name;
+ if ((node = rbfind(cache_byname, &key)) != NULL)
+ return((struct passwd *) node->data);
if ((pw = getpwnam(name)) == NULL)
return(NULL);
else
- return(sudo_pwdup(pw, 1));
+ pw = sudo_pwdup(pw);
+ rbinsert(cache_byname, (VOID *) pw);
+ rbinsert(cache_byuid, (VOID *) pw);
+ return(pw);
+}
+
+/*
+ * Take a uid and return a faked up passwd struct.
+ */
+struct passwd *
+sudo_fakepwuid(uid)
+ uid_t uid;
+{
+ struct passwd *pw;
+
+ pw = emalloc(sizeof(struct passwd) + MAX_UID_T_LEN + 1);
+ memset(pw, 0, sizeof(struct passwd));
+ pw->pw_uid = uid;
+ 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);
+ return(pw);
+}
+
+/*
+ * Take a uid in string form "#123" and return a faked up passwd struct.
+ */
+struct passwd *
+sudo_fakepwnam(user)
+ char *user;
+{
+ struct passwd *pw;
+ size_t len;
+
+ len = strlen(user);
+ pw = emalloc(sizeof(struct passwd) + len + 1);
+ memset(pw, 0, sizeof(struct passwd));
+ 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);
+ return(pw);
}
void
#ifdef HAVE_GETAUTHUID
setauthent();
#endif
+ cache_byuid = rbcreate(cmp_byuid);
+ cache_byname = rbcreate(cmp_byname);
}
void
#ifdef HAVE_GETAUTHUID
endauthent();
#endif
+ rbdestroy(cache_byuid, (void (*)__P((VOID *))) free);
+ cache_byuid = NULL;
+ rbdestroy(cache_byname, NULL);
+ cache_byname = NULL;
}
}
entry = (struct childinfo *) emalloc(sizeof(*entry));
entry->pid = pid;
- entry->pw = sudo_pwdup(pw, 0);
+ entry->pw = pw;
entry->action = action;
entry->next = children.first;
children.first = entry;
prev->next = cur->next;
else
children.first = cur->next;
- free(cur->pw);
free(cur);
break;
}
return; /* cannot happen */
if (child->pw->pw_uid != uid) {
- free(child->pw);
- /* lookup uid in passwd db, using a stub on failure */
- if ((child->pw = sudo_getpwuid(uid)) == NULL) {
- child->pw = emalloc(sizeof(struct passwd) + MAX_UID_T_LEN + 1);
- memset(child->pw, 0, sizeof(struct passwd));
- child->pw->pw_uid = uid;
- child->pw->pw_name = (char *)child->pw + sizeof(struct passwd);
- (void) snprintf(child->pw->pw_name, MAX_UID_T_LEN + 1, "%lu",
- (unsigned long) uid);
- }
+ /* look up uid in passwd db, using a stub on failure */
+ if ((child->pw = sudo_getpwuid(uid)) == NULL)
+ child->pw = sudo_fakepwuid(uid);
}
}
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));
/* XXX - causes confusion when root is not listed in sudoers */
if (sudo_mode & (MODE_RUN | MODE_EDIT) && prev_user != NULL) {
if (user_uid == 0 && strcmp(prev_user, "root") != 0) {
- struct passwd *pw;
+ struct passwd *pw;
- if ((pw = sudo_getpwnam(prev_user)) != NULL) {
- free(sudo_user.pw);
- sudo_user.pw = pw;
- }
+ if ((pw = sudo_getpwnam(prev_user)) != NULL)
+ sudo_user.pw = pw;
}
}
log_error(USE_ERRNO|MSG_ONLY, "can't get hostname");
set_runaspw(*user_runas); /* may call log_error() */
- if (*user_runas[0] == '#' && runas_pw->pw_name && runas_pw->pw_name[0])
+ if (*user_runas[0] == '#' && runas_pw->pw_name[0] != '#')
*user_runas = estrdup(runas_pw->pw_name);
/*
if (runas_pw != NULL) {
if (user_runas != &def_runas_default)
return(TRUE); /* don't override -u option */
- free(runas_pw);
}
if (*user == '#') {
- runas_pw = sudo_getpwuid(atoi(user + 1));
- if (runas_pw == NULL) {
- runas_pw = emalloc(sizeof(struct passwd));
- (void) memset((VOID *)runas_pw, 0, sizeof(struct passwd));
- runas_pw->pw_uid = atoi(user + 1);
- }
+ if ((runas_pw = sudo_getpwuid(atoi(user + 1))) == NULL)
+ runas_pw = sudo_fakepwnam(user);
} else {
- runas_pw = sudo_getpwnam(user);
- if (runas_pw == NULL)
+ if ((runas_pw = sudo_getpwnam(user)) == NULL)
log_error(NO_MAIL|MSG_ONLY, "no passwd entry for %s!", user);
}
return(TRUE);
struct passwd *pw;
if (def_rootpw) {
- if (runas_pw->pw_uid == 0)
- pw = runas_pw;
- else if ((pw = sudo_getpwuid(0)) == NULL)
+ if ((pw = sudo_getpwuid(0)) == NULL)
log_error(0, "uid 0 does not exist in the passwd file!");
} else if (def_runaspw) {
- if (strcmp(def_runas_default, *user_runas) == 0)
- pw = runas_pw;
- else if ((pw = sudo_getpwnam(def_runas_default)) == NULL)
+ if ((pw = sudo_getpwnam(def_runas_default)) == NULL)
log_error(0, "user %s does not exist in the passwd file!",
def_runas_default);
} else if (def_targetpw) {