2 * Copyright (c) 2007-2011 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 */
32 #endif /* HAVE_STRING_H */
35 #endif /* HAVE_STRINGS_H */
38 #endif /* HAVE_UNISTD_H */
46 extern struct sudo_nss sudo_nss_file;
48 extern struct sudo_nss sudo_nss_ldap;
51 #if defined(HAVE_LDAP) && defined(_PATH_NSSWITCH_CONF)
53 * Read in /etc/nsswitch.conf
54 * Returns a tail queue of matches.
56 struct sudo_nss_list *
61 int saw_files = FALSE;
63 int got_match = FALSE;
64 static struct sudo_nss_list snl;
66 if ((fp = fopen(_PATH_NSSWITCH_CONF, "r")) == NULL)
69 while ((cp = sudo_parseln(fp)) != NULL) {
70 /* Skip blank or comment lines */
74 /* Look for a line starting with "sudoers:" */
75 if (strncasecmp(cp, "sudoers:", 8) != 0)
79 for ((cp = strtok(cp + 8, " \t")); cp != NULL; (cp = strtok(NULL, " \t"))) {
80 if (strcasecmp(cp, "files") == 0 && !saw_files) {
81 tq_append(&snl, &sudo_nss_file);
83 } else if (strcasecmp(cp, "ldap") == 0 && !saw_ldap) {
84 tq_append(&snl, &sudo_nss_ldap);
86 } else if (strcasecmp(cp, "[NOTFOUND=return]") == 0 && got_match) {
87 /* NOTFOUND affects the most recent entry */
88 tq_last(&snl)->ret_if_notfound = TRUE;
93 /* Only parse the first "sudoers:" line */
99 /* Default to files only if no matches */
101 tq_append(&snl, &sudo_nss_file);
106 #else /* HAVE_LDAP && _PATH_NSSWITCH_CONF */
108 # if defined(HAVE_LDAP) && defined(_PATH_NETSVC_CONF)
111 * Read in /etc/netsvc.conf (like nsswitch.conf on AIX)
112 * Returns a tail queue of matches.
114 struct sudo_nss_list *
119 int saw_files = FALSE;
120 int saw_ldap = FALSE;
121 int got_match = FALSE;
122 static struct sudo_nss_list snl;
124 if ((fp = fopen(_PATH_NETSVC_CONF, "r")) == NULL)
127 while ((cp = sudo_parseln(fp)) != NULL) {
128 /* Skip blank or comment lines */
132 /* Look for a line starting with "sudoers = " */
133 if (strncasecmp(cp, "sudoers", 7) != 0)
136 while (isspace((unsigned char)*cp))
142 for ((cp = strtok(cp, ",")); cp != NULL; (cp = strtok(NULL, ","))) {
143 /* Trim leading whitespace. */
144 while (isspace((unsigned char)*cp))
147 if (!saw_files && strncasecmp(cp, "files", 5) == 0 &&
148 (isspace((unsigned char)cp[5]) || cp[5] == '\0')) {
149 tq_append(&snl, &sudo_nss_file);
152 } else if (!saw_ldap && strncasecmp(cp, "ldap", 4) == 0 &&
153 (isspace((unsigned char)cp[4]) || cp[4] == '\0')) {
154 tq_append(&snl, &sudo_nss_ldap);
161 /* check for = auth qualifier */
162 if (got_match && *ep) {
164 while (isspace((unsigned char)*cp) || *cp == '=')
166 if (strncasecmp(cp, "auth", 4) == 0 &&
167 (isspace((unsigned char)cp[4]) || cp[4] == '\0')) {
168 tq_last(&snl)->ret_if_found = TRUE;
172 /* Only parse the first "sudoers" line */
178 /* Default to files only if no matches */
180 tq_append(&snl, &sudo_nss_file);
185 # else /* !_PATH_NETSVC_CONF && !_PATH_NSSWITCH_CONF */
188 * Non-nsswitch.conf version with hard-coded order.
190 struct sudo_nss_list *
193 static struct sudo_nss_list snl;
196 tq_append(&snl, &sudo_nss_ldap);
198 tq_append(&snl, &sudo_nss_file);
203 # endif /* !HAVE_LDAP || !_PATH_NETSVC_CONF */
205 #endif /* HAVE_LDAP && _PATH_NSSWITCH_CONF */
207 /* Reset user_groups based on passwd entry. */
209 reset_groups(struct passwd *pw)
211 #if defined(HAVE_INITGROUPS) && defined(HAVE_GETGROUPS)
212 if (pw != sudo_user.pw) {
213 # ifdef HAVE_SETAUTHDB
214 aix_setauthdb(pw->pw_name);
216 if (initgroups(pw->pw_name, pw->pw_gid) == -1)
217 log_error(USE_ERRNO|MSG_ONLY, "can't reset group vector");
220 if ((user_ngroups = getgroups(0, NULL)) > 0) {
221 user_groups = emalloc2(user_ngroups, sizeof(GETGROUPS_T));
222 if (getgroups(user_ngroups, user_groups) < 0)
223 log_error(USE_ERRNO|MSG_ONLY, "can't get group vector");
225 # ifdef HAVE_SETAUTHDB
233 output(const char *buf)
235 struct sudo_conv_message msg;
236 struct sudo_conv_reply repl;
238 /* Call conversation function */
239 memset(&msg, 0, sizeof(msg));
240 msg.msg_type = SUDO_CONV_INFO_MSG;
242 memset(&repl, 0, sizeof(repl));
243 if (sudo_conv(1, &msg, &repl) == -1)
245 return (int)strlen(buf);
249 * Print out privileges for the specified user.
250 * We only get here if the user is allowed to run something on this host.
253 display_privs(struct sudo_nss_list *snl, struct passwd *pw)
255 struct sudo_nss *nss;
256 struct lbuf defs, privs;
259 /* Reset group vector so group matching works correctly. */
262 lbuf_init(&defs, output, 4, NULL, sudo_user.cols);
263 lbuf_init(&privs, output, 4, NULL, sudo_user.cols);
265 /* Display defaults from all sources. */
266 lbuf_append(&defs, "Matching Defaults entries for ", pw->pw_name,
267 " on this host:\n", NULL);
269 tq_foreach_fwd(snl, nss) {
270 count += nss->display_defaults(nss, pw, &defs);
273 lbuf_append(&defs, "\n\n", NULL);
277 /* Display Runas and Cmnd-specific defaults from all sources. */
279 lbuf_append(&defs, "Runas and Command-specific defaults for ", pw->pw_name,
282 tq_foreach_fwd(snl, nss) {
283 count += nss->display_bound_defaults(nss, pw, &defs);
286 lbuf_append(&defs, "\n\n", NULL);
290 /* Display privileges from all sources. */
291 lbuf_append(&privs, "User ", pw->pw_name,
292 " may run the following commands on this host:\n", NULL);
294 tq_foreach_fwd(snl, nss) {
295 count += nss->display_privs(nss, pw, &privs);
301 printf("User %s is not allowed to run sudo on %s.\n", pw->pw_name,
306 lbuf_destroy(&privs);
310 * Check user_cmnd against sudoers and print the matching entry if the
311 * command is allowed.
312 * Returns TRUE if the command is allowed, else FALSE.
315 display_cmnd(struct sudo_nss_list *snl, struct passwd *pw)
317 struct sudo_nss *nss;
319 /* Reset group vector so group matching works correctly. */
322 tq_foreach_fwd(snl, nss) {
323 if (nss->display_cmnd(nss, pw) == 0)