2 * Copyright (c) 2007-2009 Todd C. Miller <Todd.Miller@courtesan.com>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <sys/types.h>
20 #include <sys/param.h>
29 #endif /* STDC_HEADERS */
33 # ifdef HAVE_STRINGS_H
36 #endif /* HAVE_STRING_H */
39 #endif /* HAVE_UNISTD_H */
48 __unused static const char rcsid[] = "$Sudo: sudo_nss.c,v 1.8 2009/05/25 12:02:41 millert Exp $";
51 extern struct sudo_nss sudo_nss_file;
53 extern struct sudo_nss sudo_nss_ldap;
56 #if defined(HAVE_LDAP) && defined(_PATH_NSSWITCH_CONF)
58 * Read in /etc/nsswitch.conf
59 * Returns a tail queue of matches.
61 struct sudo_nss_list *
66 int saw_files = FALSE;
68 int got_match = FALSE;
69 static struct sudo_nss_list snl;
71 if ((fp = fopen(_PATH_NSSWITCH_CONF, "r")) == NULL)
74 while ((cp = sudo_parseln(fp)) != NULL) {
75 /* Skip blank or comment lines */
79 /* Look for a line starting with "sudoers:" */
80 if (strncasecmp(cp, "sudoers:", 8) != 0)
84 for ((cp = strtok(cp + 8, " \t")); cp != NULL; (cp = strtok(NULL, " \t"))) {
85 if (strcasecmp(cp, "files") == 0 && !saw_files) {
86 tq_append(&snl, &sudo_nss_file);
88 } else if (strcasecmp(cp, "ldap") == 0 && !saw_ldap) {
89 tq_append(&snl, &sudo_nss_ldap);
91 } else if (strcasecmp(cp, "[NOTFOUND=return]") == 0 && got_match) {
92 /* NOTFOUND affects the most recent entry */
93 tq_last(&snl)->ret_if_notfound = TRUE;
98 /* Only parse the first "sudoers:" line */
104 /* Default to files only if no matches */
106 tq_append(&snl, &sudo_nss_file);
111 #else /* HAVE_LDAP && _PATH_NSSWITCH_CONF */
113 # if defined(HAVE_LDAP) && defined(_PATH_NETSVC_CONF)
116 * Read in /etc/netsvc.conf (like nsswitch.conf on AIX)
117 * Returns a tail queue of matches.
119 struct sudo_nss_list *
124 int saw_files = FALSE;
125 int saw_ldap = FALSE;
126 int got_match = FALSE;
127 static struct sudo_nss_list snl;
129 if ((fp = fopen(_PATH_NETSVC_CONF, "r")) == NULL)
132 while ((cp = sudo_parseln(fp)) != NULL) {
133 /* Skip blank or comment lines */
137 /* Look for a line starting with "sudoers = " */
138 if (strncasecmp(cp, "sudoers", 7) != 0)
141 while (isspace((unsigned char)*cp))
147 for ((cp = strtok(cp, ",")); cp != NULL; (cp = strtok(NULL, ","))) {
148 /* Trim leading whitespace. */
149 while (isspace((unsigned char)*cp))
152 if (!saw_files && strncasecmp(cp, "files", 5) == 0 &&
153 (isspace((unsigned char)cp[5]) || cp[5] == '\0')) {
154 tq_append(&snl, &sudo_nss_file);
157 } else if (!saw_ldap && strncasecmp(cp, "ldap", 4) == 0 &&
158 (isspace((unsigned char)cp[4]) || cp[4] == '\0')) {
159 tq_append(&snl, &sudo_nss_ldap);
166 /* check for = auth qualifier */
167 if (got_match && *ep) {
169 while (isspace((unsigned char)*cp) || *cp == '=')
171 if (strncasecmp(cp, "auth", 4) == 0 &&
172 (isspace((unsigned char)cp[4]) || cp[4] == '\0')) {
173 tq_last(&snl)->ret_if_found = TRUE;
177 /* Only parse the first "sudoers" line */
183 /* Default to files only if no matches */
185 tq_append(&snl, &sudo_nss_file);
190 # else /* !_PATH_NETSVC_CONF && !_PATH_NSSWITCH_CONF */
193 * Non-nsswitch.conf version with hard-coded order.
195 struct sudo_nss_list *
198 static struct sudo_nss_list snl;
201 tq_append(&snl, &sudo_nss_ldap);
203 tq_append(&snl, &sudo_nss_file);
208 # endif /* !HAVE_LDAP || !_PATH_NETSVC_CONF */
210 #endif /* HAVE_LDAP && _PATH_NSSWITCH_CONF */
212 /* Reset user_groups based on passwd entry. */
217 #if defined(HAVE_INITGROUPS) && defined(HAVE_GETGROUPS)
218 if (pw != sudo_user.pw) {
219 (void) initgroups(pw->pw_name, pw->pw_gid);
220 if ((user_ngroups = getgroups(0, NULL)) > 0) {
221 user_groups = erealloc3(user_groups, user_ngroups,
222 sizeof(GETGROUPS_T));
223 if (getgroups(user_ngroups, user_groups) < 0)
224 log_error(USE_ERRNO|MSG_ONLY, "can't get group vector");
234 * Print out privileges for the specified user.
235 * We only get here if the user is allowed to run something on this host.
238 display_privs(snl, pw)
239 struct sudo_nss_list *snl;
242 struct sudo_nss *nss;
246 /* Reset group vector so group matching works correctly. */
249 lbuf_init(&lbuf, NULL, 4, 0);
251 /* Display defaults from all sources. */
253 tq_foreach_fwd(snl, nss)
254 count += nss->display_defaults(nss, pw, &lbuf);
256 printf("Matching Defaults entries for %s on this host:\n", pw->pw_name);
261 /* Display Runas and Cmnd-specific defaults from all sources. */
263 tq_foreach_fwd(snl, nss)
264 count += nss->display_bound_defaults(nss, pw, &lbuf);
266 printf("Runas and Command-specific defaults for %s:\n", pw->pw_name);
271 /* Display privileges from all sources. */
272 printf("User %s may run the following commands on this host:\n",
274 tq_foreach_fwd(snl, nss)
275 (void) nss->display_privs(nss, pw, &lbuf);
277 lbuf_print(&lbuf); /* print remainder, if any */
282 * Check user_cmnd against sudoers and print the matching entry if the
283 * command is allowed.
286 display_cmnd(snl, pw)
287 struct sudo_nss_list *snl;
290 struct sudo_nss *nss;
292 /* Reset group vector so group matching works correctly. */
295 tq_foreach_fwd(snl, nss) {
296 if (nss->display_cmnd(nss, pw) == 0)