struct passwd * getpwent(void) { static struct passwd pw; static char pwbuf[LINE_MAX]; size_t len; id_t id; char *cp, *colon; const char *errstr; next_entry: if ((colon = fgets(pwbuf, sizeof(pwbuf), pwf)) == NULL) return NULL; memset(&pw, 0, sizeof(pw)); if ((colon = strchr(cp = colon, ':')) == NULL) goto next_entry; *colon++ = '\0'; pw.pw_name = cp; if ((colon = strchr(cp = colon, ':')) == NULL) goto next_entry; *colon++ = '\0'; pw.pw_passwd = cp; if ((colon = strchr(cp = colon, ':')) == NULL) goto next_entry; *colon++ = '\0'; id = sudo_strtoid(cp, NULL, NULL, &errstr); if (errstr != NULL) goto next_entry; pw.pw_uid = (uid_t)id; if ((colon = strchr(cp = colon, ':')) == NULL) goto next_entry; *colon++ = '\0'; id = sudo_strtoid(cp, NULL, NULL, &errstr); if (errstr != NULL) goto next_entry; pw.pw_gid = (gid_t)id; if ((colon = strchr(cp = colon, ':')) == NULL) goto next_entry; *colon++ = '\0'; pw.pw_gecos = cp; if ((colon = strchr(cp = colon, ':')) == NULL) goto next_entry; *colon++ = '\0'; pw.pw_dir = cp; pw.pw_shell = colon; len = strlen(colon); if (len > 0 && colon[len - 1] == '\n') colon[len - 1] = '\0'; return &pw; }
/* * Returns true if "user" is a member of "group", else false. */ static int sysgroup_query(const char *user, const char *group, const struct passwd *pwd) { char **member; struct group *grp; grp = sysgroup_getgrnam(group); if (grp == NULL && group[0] == '#' && group[1] != '\0') { const char *errstr; gid_t gid = sudo_strtoid(group + 1, NULL, NULL, &errstr); if (errstr == NULL) grp = sysgroup_getgrgid(gid); } if (grp != NULL) { if (grp->gr_mem != NULL) { for (member = grp->gr_mem; *member != NULL; member++) { if (strcasecmp(user, *member) == 0) { if (sysgroup_gr_delref) sysgroup_gr_delref(grp); return true; } } } if (sysgroup_gr_delref) sysgroup_gr_delref(grp); } return false; }
static int test_strtoid(int *ntests) { struct strtoid_data *d; const char *errstr; char *ep; int errors = 0; id_t value; for (d = strtoid_data; d->idstr != NULL; d++) { (*ntests)++; errstr = "some error"; value = sudo_strtoid(d->idstr, d->sep, &ep, &errstr); if (errstr != NULL) { if (d->id != (id_t)-1) { sudo_warnx_nodebug("FAIL: %s: %s", d->idstr, errstr); errors++; } } else if (value != d->id) { sudo_warnx_nodebug("FAIL: %s != %u", d->idstr, (unsigned int)d->id); errors++; } else if (d->ep != NULL && ep[0] != d->ep[0]) { sudo_warnx_nodebug("FAIL: ep[0] %d != %d", (int)(unsigned char)ep[0], (int)(unsigned char)d->ep[0]); errors++; } } return errors; }
/* * Take a uid in string form "#123" and return a faked up passwd struct. */ struct passwd * sudo_fakepwnam(const char *user, gid_t gid) { const char *errstr; uid_t uid; debug_decl(sudo_fakepwnam, SUDOERS_DEBUG_NSS) uid = (uid_t) sudo_strtoid(user + 1, NULL, NULL, &errstr); if (errstr != NULL) { sudo_debug_printf(SUDO_DEBUG_DEBUG|SUDO_DEBUG_DIAG, "uid %s %s", user, errstr); debug_return_ptr(NULL); } debug_return_ptr(sudo_mkpwent(user, uid, gid, NULL, NULL)); }
/* * Parse a comma-separated list of gids into an allocated array of GETGROUPS_T. * If a pointer to the base gid is specified, it is stored as the first element * in the array. * Returns the number of gids in the allocated array. */ int sudo_parse_gids_v1(const char *gidstr, const gid_t *basegid, GETGROUPS_T **gidsp) { int ngids = 0; GETGROUPS_T *gids; const char *cp = gidstr; const char *errstr; char *ep; debug_decl(sudo_parse_gids, SUDO_DEBUG_UTIL) /* Count groups. */ if (*cp != '\0') { ngids++; do { if (*cp++ == ',') ngids++; } while (*cp != '\0'); } /* Base gid is optional. */ if (basegid != NULL) ngids++; /* Allocate and fill in array. */ if (ngids != 0) { gids = reallocarray(NULL, ngids, sizeof(GETGROUPS_T)); if (gids == NULL) { sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); debug_return_int(-1); } ngids = 0; if (basegid != NULL) gids[ngids++] = *basegid; cp = gidstr; do { gids[ngids] = (GETGROUPS_T) sudo_strtoid(cp, ",", &ep, &errstr); if (errstr != NULL) { sudo_warnx(U_("%s: %s"), cp, U_(errstr)); free(gids); debug_return_int(-1); } if (basegid == NULL || gids[ngids] != *basegid) ngids++; cp = ep + 1; } while (*ep != '\0'); *gidsp = gids; } debug_return_int(ngids); }
struct group * getgrent(void) { static struct group gr; static char grbuf[LINE_MAX], *gr_mem[GRMEM_MAX+1]; size_t len; id_t id; char *cp, *colon; const char *errstr; int n; next_entry: if ((colon = fgets(grbuf, sizeof(grbuf), grf)) == NULL) return NULL; memset(&gr, 0, sizeof(gr)); if ((colon = strchr(cp = colon, ':')) == NULL) goto next_entry; *colon++ = '\0'; gr.gr_name = cp; if ((colon = strchr(cp = colon, ':')) == NULL) goto next_entry; *colon++ = '\0'; gr.gr_passwd = cp; if ((colon = strchr(cp = colon, ':')) == NULL) goto next_entry; *colon++ = '\0'; id = sudo_strtoid(cp, NULL, NULL, &errstr); if (errstr != NULL) goto next_entry; gr.gr_gid = (gid_t)id; len = strlen(colon); if (len > 0 && colon[len - 1] == '\n') colon[len - 1] = '\0'; if (*colon != '\0') { gr.gr_mem = gr_mem; cp = strtok(colon, ","); for (n = 0; cp != NULL && n < GRMEM_MAX; n++) { gr.gr_mem[n] = cp; cp = strtok(NULL, ","); } gr.gr_mem[n++] = NULL; } else gr.gr_mem = NULL; return &gr; }
/* * Deserialize args, settings and user_info arrays. * Fills in struct sudo_user and other common sudoers state. */ int sudoers_policy_deserialize_info(void *v, char **runas_user, char **runas_group) { struct sudoers_policy_open_info *info = v; char * const *cur; const char *p, *errstr, *groups = NULL; const char *remhost = NULL; int flags = 0; debug_decl(sudoers_policy_deserialize_info, SUDOERS_DEBUG_PLUGIN) #define MATCHES(s, v) (strncmp(s, v, sizeof(v) - 1) == 0) /* Parse sudo.conf plugin args. */ if (info->plugin_args != NULL) { for (cur = info->plugin_args; *cur != NULL; cur++) { if (MATCHES(*cur, "sudoers_file=")) { sudoers_file = *cur + sizeof("sudoers_file=") - 1; continue; } if (MATCHES(*cur, "sudoers_uid=")) { p = *cur + sizeof("sudoers_uid=") - 1; sudoers_uid = (uid_t) sudo_strtoid(p, NULL, NULL, &errstr); if (errstr != NULL) { sudo_warnx(U_("%s: %s"), *cur, U_(errstr)); goto bad; } continue; } if (MATCHES(*cur, "sudoers_gid=")) { p = *cur + sizeof("sudoers_gid=") - 1; sudoers_gid = (gid_t) sudo_strtoid(p, NULL, NULL, &errstr); if (errstr != NULL) { sudo_warnx(U_("%s: %s"), *cur, U_(errstr)); goto bad; } continue; } if (MATCHES(*cur, "sudoers_mode=")) { p = *cur + sizeof("sudoers_mode=") - 1; sudoers_mode = sudo_strtomode(p, &errstr); if (errstr != NULL) { sudo_warnx(U_("%s: %s"), *cur, U_(errstr)); goto bad; } continue; } if (MATCHES(*cur, "ldap_conf=")) { path_ldap_conf = *cur + sizeof("ldap_conf=") - 1; continue; } if (MATCHES(*cur, "ldap_secret=")) { path_ldap_secret = *cur + sizeof("ldap_secret=") - 1; continue; } } } /* Parse command line settings. */ user_closefrom = -1; for (cur = info->settings; *cur != NULL; cur++) { if (MATCHES(*cur, "closefrom=")) { errno = 0; p = *cur + sizeof("closefrom=") - 1; user_closefrom = strtonum(p, 4, INT_MAX, &errstr); if (user_closefrom == 0) { sudo_warnx(U_("%s: %s"), *cur, U_(errstr)); goto bad; } continue; } if (MATCHES(*cur, "runas_user="******"runas_user="******"runas_group=")) { *runas_group = *cur + sizeof("runas_group=") - 1; sudo_user.flags |= RUNAS_GROUP_SPECIFIED; continue; } if (MATCHES(*cur, "prompt=")) { user_prompt = *cur + sizeof("prompt=") - 1; def_passprompt_override = true; continue; } if (MATCHES(*cur, "set_home=")) { if (sudo_strtobool(*cur + sizeof("set_home=") - 1) == true) SET(flags, MODE_RESET_HOME); continue; } if (MATCHES(*cur, "preserve_environment=")) { if (sudo_strtobool(*cur + sizeof("preserve_environment=") - 1) == true) SET(flags, MODE_PRESERVE_ENV); continue; } if (MATCHES(*cur, "run_shell=")) { if (sudo_strtobool(*cur + sizeof("run_shell=") - 1) == true) SET(flags, MODE_SHELL); continue; } if (MATCHES(*cur, "login_shell=")) { if (sudo_strtobool(*cur + sizeof("login_shell=") - 1) == true) { SET(flags, MODE_LOGIN_SHELL); def_env_reset = true; } continue; } if (MATCHES(*cur, "implied_shell=")) { if (sudo_strtobool(*cur + sizeof("implied_shell=") - 1) == true) SET(flags, MODE_IMPLIED_SHELL); continue; } if (MATCHES(*cur, "preserve_groups=")) { if (sudo_strtobool(*cur + sizeof("preserve_groups=") - 1) == true) SET(flags, MODE_PRESERVE_GROUPS); continue; } if (MATCHES(*cur, "ignore_ticket=")) { if (sudo_strtobool(*cur + sizeof("ignore_ticket=") - 1) == true) SET(flags, MODE_IGNORE_TICKET); continue; } if (MATCHES(*cur, "noninteractive=")) { if (sudo_strtobool(*cur + sizeof("noninteractive=") - 1) == true) SET(flags, MODE_NONINTERACTIVE); continue; } if (MATCHES(*cur, "sudoedit=")) { if (sudo_strtobool(*cur + sizeof("sudoedit=") - 1) == true) SET(flags, MODE_EDIT); continue; } if (MATCHES(*cur, "login_class=")) { login_class = *cur + sizeof("login_class=") - 1; def_use_loginclass = true; continue; } #ifdef HAVE_PRIV_SET if (MATCHES(*cur, "runas_privs=")) { def_privs = *cur + sizeof("runas_privs=") - 1; continue; } if (MATCHES(*cur, "runas_limitprivs=")) { def_limitprivs = *cur + sizeof("runas_limitprivs=") - 1; continue; } #endif /* HAVE_PRIV_SET */ #ifdef HAVE_SELINUX if (MATCHES(*cur, "selinux_role=")) { user_role = *cur + sizeof("selinux_role=") - 1; continue; } if (MATCHES(*cur, "selinux_type=")) { user_type = *cur + sizeof("selinux_type=") - 1; continue; } #endif /* HAVE_SELINUX */ #ifdef HAVE_BSD_AUTH_H if (MATCHES(*cur, "bsdauth_type=")) { login_style = *cur + sizeof("bsdauth_type=") - 1; continue; } #endif /* HAVE_BSD_AUTH_H */ if (MATCHES(*cur, "network_addrs=")) { interfaces_string = *cur + sizeof("network_addrs=") - 1; set_interfaces(interfaces_string); continue; } if (MATCHES(*cur, "max_groups=")) { errno = 0; p = *cur + sizeof("max_groups=") - 1; sudo_user.max_groups = strtonum(p, 1, INT_MAX, &errstr); if (sudo_user.max_groups == 0) { sudo_warnx(U_("%s: %s"), *cur, U_(errstr)); goto bad; } continue; } if (MATCHES(*cur, "remote_host=")) { remhost = *cur + sizeof("remote_host=") - 1; continue; } } for (cur = info->user_info; *cur != NULL; cur++) { if (MATCHES(*cur, "user="******"user="******"uid=")) { p = *cur + sizeof("uid=") - 1; user_uid = (uid_t) sudo_strtoid(p, NULL, NULL, &errstr); if (errstr != NULL) { sudo_warnx(U_("%s: %s"), *cur, U_(errstr)); goto bad; } continue; } if (MATCHES(*cur, "gid=")) { p = *cur + sizeof("gid=") - 1; user_gid = (gid_t) sudo_strtoid(p, NULL, NULL, &errstr); if (errstr != NULL) { sudo_warnx(U_("%s: %s"), *cur, U_(errstr)); goto bad; } continue; } if (MATCHES(*cur, "groups=")) { groups = *cur + sizeof("groups=") - 1; continue; } if (MATCHES(*cur, "cwd=")) { user_cwd = sudo_estrdup(*cur + sizeof("cwd=") - 1); continue; } if (MATCHES(*cur, "tty=")) { user_tty = user_ttypath = sudo_estrdup(*cur + sizeof("tty=") - 1); if (strncmp(user_tty, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) user_tty += sizeof(_PATH_DEV) - 1; continue; } if (MATCHES(*cur, "host=")) { user_host = user_shost = sudo_estrdup(*cur + sizeof("host=") - 1); if ((p = strchr(user_host, '.'))) user_shost = sudo_estrndup(user_host, (size_t)(p - user_host)); continue; } if (MATCHES(*cur, "lines=")) { errno = 0; p = *cur + sizeof("lines=") - 1; sudo_user.lines = strtonum(p, 1, INT_MAX, &errstr); if (sudo_user.lines == 0) { sudo_warnx(U_("%s: %s"), *cur, U_(errstr)); goto bad; } continue; } if (MATCHES(*cur, "cols=")) { errno = 0; p = *cur + sizeof("cols=") - 1; sudo_user.cols = strtonum(p, 1, INT_MAX, &errstr); if (sudo_user.lines == 0) { sudo_warnx(U_("%s: %s"), *cur, U_(errstr)); goto bad; } continue; } if (MATCHES(*cur, "sid=")) { p = *cur + sizeof("sid=") - 1; sudo_user.sid = (pid_t) sudo_strtoid(p, NULL, NULL, &errstr); if (errstr != NULL) { sudo_warnx(U_("%s: %s"), *cur, U_(errstr)); goto bad; } continue; } } user_runhost = user_srunhost = sudo_estrdup(remhost ? remhost : user_host); if ((p = strchr(user_runhost, '.'))) user_srunhost = sudo_estrndup(user_runhost, (size_t)(p - user_runhost)); if (user_cwd == NULL) user_cwd = sudo_estrdup("unknown"); if (user_tty == NULL) user_tty = sudo_estrdup("unknown"); /* user_ttypath remains NULL */ if (groups != NULL && groups[0] != '\0') { /* sudo_parse_gids() will print a warning on error. */ user_ngids = sudo_parse_gids(groups, &user_gid, &user_gids); if (user_ngids == -1) goto bad; } /* Stash initial umask for later use. */ user_umask = umask(SUDO_UMASK); umask(user_umask); /* Dump settings and user info (XXX - plugin args) */ for (cur = info->settings; *cur != NULL; cur++) sudo_debug_printf(SUDO_DEBUG_INFO, "settings: %s", *cur); for (cur = info->user_info; *cur != NULL; cur++) sudo_debug_printf(SUDO_DEBUG_INFO, "user_info: %s", *cur); #undef MATCHES debug_return_int(flags); bad: debug_return_int(MODE_ERROR); }