/* * Read in /etc/nsswitch.conf * Returns a tail queue of matches. */ struct sudo_nss_list * sudo_read_nss(void) { FILE *fp; char *cp; int saw_files = FALSE; int saw_ldap = FALSE; int got_match = FALSE; static struct sudo_nss_list snl; if ((fp = fopen(_PATH_NSSWITCH_CONF, "r")) == NULL) goto nomatch; while ((cp = sudo_parseln(fp)) != NULL) { /* Skip blank or comment lines */ if (*cp == '\0') continue; /* Look for a line starting with "sudoers:" */ if (strncasecmp(cp, "sudoers:", 8) != 0) continue; /* Parse line */ for ((cp = strtok(cp + 8, " \t")); cp != NULL; (cp = strtok(NULL, " \t"))) { if (strcasecmp(cp, "files") == 0 && !saw_files) { tq_append(&snl, &sudo_nss_file); got_match = TRUE; } else if (strcasecmp(cp, "ldap") == 0 && !saw_ldap) { tq_append(&snl, &sudo_nss_ldap); got_match = TRUE; } else if (strcasecmp(cp, "[NOTFOUND=return]") == 0 && got_match) { /* NOTFOUND affects the most recent entry */ tq_last(&snl)->ret_if_notfound = TRUE; got_match = FALSE; } else got_match = FALSE; } /* Only parse the first "sudoers:" line */ break; } fclose(fp); nomatch: /* Default to files only if no matches */ if (tq_empty(&snl)) tq_append(&snl, &sudo_nss_file); return &snl; }
/* * Read in /etc/sudo.conf * Returns a list of plugins. */ static struct plugin_info_list * sudo_read_conf(const char *conf_file) { FILE *fp; char *cp, *name, *path; struct plugin_info *info; static struct plugin_info_list pil; /* XXX */ if ((fp = fopen(conf_file, "r")) == NULL) goto done; while ((cp = sudo_parseln(fp)) != NULL) { /* Skip blank or comment lines */ if (*cp == '\0') continue; /* Look for a line starting with "Path" */ if (strncasecmp(cp, "Path", 4) == 0) { /* Parse line */ if ((name = strtok(cp + 4, " \t")) == NULL || (path = strtok(NULL, " \t")) == NULL) { continue; } if (strcasecmp(name, "askpass") != 0) continue; askpass_path = estrdup(path); continue; } /* Look for a line starting with "Plugin" */ if (strncasecmp(cp, "Plugin", 6) == 0) { /* Parse line */ if ((name = strtok(cp + 6, " \t")) == NULL || (path = strtok(NULL, " \t")) == NULL) { continue; } info = emalloc(sizeof(*info)); info->symbol_name = estrdup(name); info->path = estrdup(path); info->prev = info; info->next = NULL; tq_append(&pil, info); continue; } } fclose(fp); done: if (tq_empty(&pil)) { /* Default policy plugin */ info = emalloc(sizeof(*info)); info->symbol_name = "sudoers_policy"; info->path = SUDOERS_PLUGIN; info->prev = info; info->next = NULL; tq_append(&pil, info); /* Default I/O plugin */ info = emalloc(sizeof(*info)); info->symbol_name = "sudoers_io"; info->path = SUDOERS_PLUGIN; info->prev = info; info->next = NULL; tq_append(&pil, info); } return &pil; }
/* * Read in /etc/netsvc.conf (like nsswitch.conf on AIX) * Returns a tail queue of matches. */ struct sudo_nss_list * sudo_read_nss(void) { FILE *fp; char *cp, *ep; int saw_files = FALSE; int saw_ldap = FALSE; int got_match = FALSE; static struct sudo_nss_list snl; if ((fp = fopen(_PATH_NETSVC_CONF, "r")) == NULL) goto nomatch; while ((cp = sudo_parseln(fp)) != NULL) { /* Skip blank or comment lines */ if (*cp == '\0') continue; /* Look for a line starting with "sudoers = " */ if (strncasecmp(cp, "sudoers", 7) != 0) continue; cp += 7; while (isspace((unsigned char)*cp)) cp++; if (*cp++ != '=') continue; /* Parse line */ for ((cp = strtok(cp, ",")); cp != NULL; (cp = strtok(NULL, ","))) { /* Trim leading whitespace. */ while (isspace((unsigned char)*cp)) cp++; if (!saw_files && strncasecmp(cp, "files", 5) == 0 && (isspace((unsigned char)cp[5]) || cp[5] == '\0')) { tq_append(&snl, &sudo_nss_file); got_match = TRUE; ep = &cp[5]; } else if (!saw_ldap && strncasecmp(cp, "ldap", 4) == 0 && (isspace((unsigned char)cp[4]) || cp[4] == '\0')) { tq_append(&snl, &sudo_nss_ldap); got_match = TRUE; ep = &cp[4]; } else { got_match = FALSE; } /* check for = auth qualifier */ if (got_match && *ep) { cp = ep; while (isspace((unsigned char)*cp) || *cp == '=') cp++; if (strncasecmp(cp, "auth", 4) == 0 && (isspace((unsigned char)cp[4]) || cp[4] == '\0')) { tq_last(&snl)->ret_if_found = TRUE; } } } /* Only parse the first "sudoers" line */ break; } fclose(fp); nomatch: /* Default to files only if no matches */ if (tq_empty(&snl)) tq_append(&snl, &sudo_nss_file); return &snl; }
/* * Check for user described by pw in a list of members. * If both lists are empty compare against def_runas_default. * Returns ALLOW, DENY or UNSPEC. */ static int _runaslist_matches(struct member_list *user_list, struct member_list *group_list) { struct member *m; struct alias *a; int rval; int user_matched = UNSPEC; int group_matched = UNSPEC; if (runas_pw != NULL) { /* If no runas user or runas group listed in sudoers, use default. */ if (tq_empty(user_list) && tq_empty(group_list)) return userpw_matches(def_runas_default, runas_pw->pw_name, runas_pw); tq_foreach_rev(user_list, m) { switch (m->type) { case ALL: user_matched = !m->negated; break; case NETGROUP: if (netgr_matches(m->name, NULL, NULL, runas_pw->pw_name)) user_matched = !m->negated; break; case USERGROUP: if (usergr_matches(m->name, runas_pw->pw_name, runas_pw)) user_matched = !m->negated; break; case ALIAS: if ((a = alias_find(m->name, RUNASALIAS)) != NULL) { rval = _runaslist_matches(&a->members, &empty); if (rval != UNSPEC) user_matched = m->negated ? !rval : rval; break; } /* FALLTHROUGH */ case WORD: if (userpw_matches(m->name, runas_pw->pw_name, runas_pw)) user_matched = !m->negated; break; } if (user_matched != UNSPEC) break; } } if (runas_gr != NULL) { if (user_matched == UNSPEC) { if (runas_pw == NULL || strcmp(runas_pw->pw_name, user_name) == 0) user_matched = ALLOW; /* only changing group */ } tq_foreach_rev(group_list, m) { switch (m->type) { case ALL: group_matched = !m->negated; break; case ALIAS: if ((a = alias_find(m->name, RUNASALIAS)) != NULL) { rval = _runaslist_matches(&a->members, &empty); if (rval != UNSPEC) group_matched = m->negated ? !rval : rval; break; } /* FALLTHROUGH */ case WORD: if (group_matches(m->name, runas_gr)) group_matched = !m->negated; break; } if (group_matched != UNSPEC) break; } if (group_matched == UNSPEC) { if (runas_pw != NULL && runas_pw->pw_gid == runas_gr->gr_gid) group_matched = ALLOW; /* runas group matches passwd db */ } } if (user_matched == DENY || group_matched == DENY) return DENY; if (user_matched == group_matched || runas_gr == NULL) return user_matched; return UNSPEC; }