/* * Take a user, uid and gid and return a faked up passwd struct. */ struct passwd * sudo_fakepwnamid(const char *user, uid_t uid, gid_t gid) { struct cache_item_pw *pwitem; struct passwd *pw; struct rbnode *node; size_t len, namelen; int i; debug_decl(sudo_fakepwnam, SUDO_DEBUG_NSS) namelen = strlen(user); len = sizeof(*pwitem) + namelen + 1 /* pw_name */ + sizeof("*") /* pw_passwd */ + sizeof("") /* pw_gecos */ + sizeof("/") /* pw_dir */ + sizeof(_PATH_BSHELL); for (i = 0; i < 2; i++) { pwitem = ecalloc(1, len); pw = &pwitem->pw; pw->pw_uid = uid; pw->pw_gid = gid; pw->pw_name = (char *)(pwitem + 1); memcpy(pw->pw_name, user, namelen + 1); pw->pw_passwd = pw->pw_name + namelen + 1; memcpy(pw->pw_passwd, "*", 2); pw->pw_gecos = pw->pw_passwd + 2; pw->pw_gecos[0] = '\0'; pw->pw_dir = pw->pw_gecos + 1; memcpy(pw->pw_dir, "/", 2); pw->pw_shell = pw->pw_dir + 2; memcpy(pw->pw_shell, _PATH_BSHELL, sizeof(_PATH_BSHELL)); pwitem->cache.refcnt = 1; pwitem->cache.d.pw = pw; if (i == 0) { /* Store by uid, overwriting cached version. */ pwitem->cache.k.uid = pw->pw_uid; if ((node = rbinsert(pwcache_byuid, &pwitem->cache)) != NULL) { sudo_pw_delref_item(node->data); node->data = &pwitem->cache; } } else { /* Store by name, overwriting cached version. */ pwitem->cache.k.name = pw->pw_name; if ((node = rbinsert(pwcache_byname, &pwitem->cache)) != NULL) { sudo_pw_delref_item(node->data); node->data = &pwitem->cache; } } } pwitem->cache.refcnt++; debug_return_ptr(pw); }
void sudo_pw_delref(struct passwd *pw) { debug_decl(sudo_pw_delref, SUDO_DEBUG_NSS) sudo_pw_delref_item(ptr_to_item(pw)); debug_return; }
/* * Take a user, uid, gid, home and shell and return a faked up passwd struct. * If home or shell are NULL default values will be used. */ struct passwd * sudo_mkpwent(const char *user, uid_t uid, gid_t gid, const char *home, const char *shell) { struct cache_item_pw *pwitem; struct cache_item *item; struct passwd *pw; size_t len, name_len, home_len, shell_len; int i; debug_decl(sudo_mkpwent, SUDOERS_DEBUG_NSS) /* Optional arguments. */ if (home == NULL) home = "/"; if (shell == NULL) shell = _PATH_BSHELL; name_len = strlen(user); home_len = strlen(home); shell_len = strlen(shell); len = sizeof(*pwitem) + name_len + 1 /* pw_name */ + sizeof("*") /* pw_passwd */ + sizeof("") /* pw_gecos */ + home_len + 1 /* pw_dir */ + shell_len + 1 /* pw_shell */; for (i = 0; i < 2; i++) { struct rbtree *pwcache; struct rbnode *node; pwitem = sudo_ecalloc(1, len); pw = &pwitem->pw; pw->pw_uid = uid; pw->pw_gid = gid; pw->pw_name = (char *)(pwitem + 1); memcpy(pw->pw_name, user, name_len + 1); pw->pw_passwd = pw->pw_name + name_len + 1; memcpy(pw->pw_passwd, "*", 2); pw->pw_gecos = pw->pw_passwd + 2; pw->pw_gecos[0] = '\0'; pw->pw_dir = pw->pw_gecos + 1; memcpy(pw->pw_dir, home, home_len + 1); pw->pw_shell = pw->pw_dir + home_len + 1; memcpy(pw->pw_shell, shell, shell_len + 1); item = &pwitem->cache; item->refcnt = 1; item->d.pw = pw; if (i == 0) { /* Store by uid if it doesn't already exist. */ item->k.uid = pw->pw_uid; pwcache = pwcache_byuid; } else { /* Store by name if it doesn't already exist. */ item->k.name = pw->pw_name; pwcache = pwcache_byname; } if ((node = rbinsert(pwcache, item)) != NULL) { /* Already exists. */ item = node->data; if (item->d.pw == NULL) { /* Negative cache entry, replace with ours. */ sudo_pw_delref_item(item); item = node->data = &pwitem->cache; } else { /* Good entry, discard our fake one. */ sudo_efree(pwitem); } } } item->refcnt++; debug_return_ptr(item->d.pw); }