Annotation of embedaddon/sudo/plugins/sudoers/sudo_nss.c, revision 1.1.1.6
1.1 misho 1: /*
1.1.1.4 misho 2: * Copyright (c) 2007-2013 Todd C. Miller <Todd.Miller@courtesan.com>
1.1 misho 3: *
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.
7: *
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.
15: */
16:
17: #include <config.h>
18:
19: #include <sys/types.h>
1.1.1.3 misho 20: #include <sys/stat.h>
21:
1.1 misho 22: #include <stdio.h>
23: #ifdef STDC_HEADERS
24: # include <stdlib.h>
25: # include <stddef.h>
26: #else
27: # ifdef HAVE_STDLIB_H
28: # include <stdlib.h>
29: # endif
30: #endif /* STDC_HEADERS */
31: #ifdef HAVE_STRING_H
32: # include <string.h>
33: #endif /* HAVE_STRING_H */
34: #ifdef HAVE_STRINGS_H
35: # include <strings.h>
36: #endif /* HAVE_STRINGS_H */
37: #ifdef HAVE_UNISTD_H
38: # include <unistd.h>
39: #endif /* HAVE_UNISTD_H */
40: #include <pwd.h>
41: #include <grp.h>
42: #include <ctype.h>
43:
44: #include "sudoers.h"
45: #include "lbuf.h"
46:
47: extern struct sudo_nss sudo_nss_file;
48: #ifdef HAVE_LDAP
49: extern struct sudo_nss sudo_nss_ldap;
50: #endif
1.1.1.3 misho 51: #ifdef HAVE_SSSD
52: extern struct sudo_nss sudo_nss_sss;
53: #endif
1.1 misho 54:
1.1.1.3 misho 55: #if (defined(HAVE_LDAP) || defined(HAVE_SSSD)) && defined(_PATH_NSSWITCH_CONF)
1.1 misho 56: /*
57: * Read in /etc/nsswitch.conf
58: * Returns a tail queue of matches.
59: */
60: struct sudo_nss_list *
61: sudo_read_nss(void)
62: {
63: FILE *fp;
1.1.1.4 misho 64: char *cp, *line = NULL;
65: size_t linesize = 0;
1.1.1.3 misho 66: #ifdef HAVE_SSSD
67: bool saw_sss = false;
68: #endif
1.1.1.2 misho 69: bool saw_files = false;
70: bool saw_ldap = false;
71: bool got_match = false;
1.1.1.6 ! misho 72: static struct sudo_nss_list snl = TAILQ_HEAD_INITIALIZER(snl);
1.1.1.2 misho 73: debug_decl(sudo_read_nss, SUDO_DEBUG_NSS)
1.1 misho 74:
75: if ((fp = fopen(_PATH_NSSWITCH_CONF, "r")) == NULL)
76: goto nomatch;
77:
1.1.1.4 misho 78: while (sudo_parseln(&line, &linesize, NULL, fp) != -1) {
1.1 misho 79: /* Skip blank or comment lines */
1.1.1.4 misho 80: if (*line == '\0')
1.1 misho 81: continue;
82:
83: /* Look for a line starting with "sudoers:" */
1.1.1.4 misho 84: if (strncasecmp(line, "sudoers:", 8) != 0)
1.1 misho 85: continue;
86:
87: /* Parse line */
1.1.1.4 misho 88: for ((cp = strtok(line + 8, " \t")); cp != NULL; (cp = strtok(NULL, " \t"))) {
1.1 misho 89: if (strcasecmp(cp, "files") == 0 && !saw_files) {
1.1.1.6 ! misho 90: TAILQ_INSERT_TAIL(&snl, &sudo_nss_file, entries);
1.1.1.2 misho 91: got_match = true;
1.1.1.4 misho 92: #ifdef HAVE_LDAP
1.1 misho 93: } else if (strcasecmp(cp, "ldap") == 0 && !saw_ldap) {
1.1.1.6 ! misho 94: TAILQ_INSERT_TAIL(&snl, &sudo_nss_ldap, entries);
1.1.1.2 misho 95: got_match = true;
1.1.1.4 misho 96: #endif
1.1.1.3 misho 97: #ifdef HAVE_SSSD
98: } else if (strcasecmp(cp, "sss") == 0 && !saw_sss) {
1.1.1.6 ! misho 99: TAILQ_INSERT_TAIL(&snl, &sudo_nss_sss, entries);
1.1.1.3 misho 100: got_match = true;
101: #endif
1.1 misho 102: } else if (strcasecmp(cp, "[NOTFOUND=return]") == 0 && got_match) {
103: /* NOTFOUND affects the most recent entry */
1.1.1.6 ! misho 104: TAILQ_LAST(&snl, sudo_nss_list)->ret_if_notfound = true;
1.1.1.2 misho 105: got_match = false;
1.1.1.3 misho 106: } else if (strcasecmp(cp, "[SUCCESS=return]") == 0 && got_match) {
107: /* SUCCESS affects the most recent entry */
1.1.1.6 ! misho 108: TAILQ_LAST(&snl, sudo_nss_list)->ret_if_found = true;
1.1.1.3 misho 109: got_match = false;
1.1 misho 110: } else
1.1.1.2 misho 111: got_match = false;
1.1 misho 112: }
113: /* Only parse the first "sudoers:" line */
114: break;
115: }
1.1.1.4 misho 116: free(line);
1.1 misho 117: fclose(fp);
118:
119: nomatch:
120: /* Default to files only if no matches */
1.1.1.6 ! misho 121: if (TAILQ_EMPTY(&snl))
! 122: TAILQ_INSERT_TAIL(&snl, &sudo_nss_file, entries);
1.1 misho 123:
1.1.1.2 misho 124: debug_return_ptr(&snl);
1.1 misho 125: }
126:
1.1.1.3 misho 127: #else /* (HAVE_LDAP || HAVE_SSSD) && _PATH_NSSWITCH_CONF */
1.1 misho 128:
1.1.1.3 misho 129: # if (defined(HAVE_LDAP) || defined(HAVE_SSSD)) && defined(_PATH_NETSVC_CONF)
1.1 misho 130:
131: /*
132: * Read in /etc/netsvc.conf (like nsswitch.conf on AIX)
133: * Returns a tail queue of matches.
134: */
135: struct sudo_nss_list *
136: sudo_read_nss(void)
137: {
138: FILE *fp;
1.1.1.4 misho 139: char *cp, *ep, *line = NULL;
1.1.1.6 ! misho 140: size_t linesize = 0;
1.1.1.3 misho 141: #ifdef HAVE_SSSD
142: bool saw_sss = false;
143: #endif
1.1.1.2 misho 144: bool saw_files = false;
145: bool saw_ldap = false;
146: bool got_match = false;
1.1.1.6 ! misho 147: static struct sudo_nss_list snl = TAILQ_HEAD_INITIALIZER(snl);
1.1.1.2 misho 148: debug_decl(sudo_read_nss, SUDO_DEBUG_NSS)
1.1 misho 149:
150: if ((fp = fopen(_PATH_NETSVC_CONF, "r")) == NULL)
151: goto nomatch;
152:
1.1.1.4 misho 153: while (sudo_parseln(&line, &linesize, NULL, fp) != -1) {
1.1 misho 154: /* Skip blank or comment lines */
1.1.1.4 misho 155: if (*(cp = line) == '\0')
1.1 misho 156: continue;
157:
158: /* Look for a line starting with "sudoers = " */
159: if (strncasecmp(cp, "sudoers", 7) != 0)
160: continue;
161: cp += 7;
162: while (isspace((unsigned char)*cp))
163: cp++;
164: if (*cp++ != '=')
165: continue;
166:
167: /* Parse line */
168: for ((cp = strtok(cp, ",")); cp != NULL; (cp = strtok(NULL, ","))) {
169: /* Trim leading whitespace. */
170: while (isspace((unsigned char)*cp))
171: cp++;
172:
173: if (!saw_files && strncasecmp(cp, "files", 5) == 0 &&
174: (isspace((unsigned char)cp[5]) || cp[5] == '\0')) {
1.1.1.6 ! misho 175: TAILQ_INSERT_TAIL(&snl, &sudo_nss_file, entries);
1.1.1.2 misho 176: got_match = true;
1.1 misho 177: ep = &cp[5];
1.1.1.4 misho 178: #ifdef HAVE_LDAP
1.1 misho 179: } else if (!saw_ldap && strncasecmp(cp, "ldap", 4) == 0 &&
180: (isspace((unsigned char)cp[4]) || cp[4] == '\0')) {
1.1.1.6 ! misho 181: TAILQ_INSERT_TAIL(&snl, &sudo_nss_ldap, entries);
1.1.1.2 misho 182: got_match = true;
1.1 misho 183: ep = &cp[4];
1.1.1.4 misho 184: #endif
1.1.1.3 misho 185: #ifdef HAVE_SSSD
186: } else if (!saw_sss && strncasecmp(cp, "sss", 3) == 0 &&
187: (isspace((unsigned char)cp[3]) || cp[3] == '\0')) {
1.1.1.6 ! misho 188: TAILQ_INSERT_TAIL(&snl, &sudo_nss_sss, entries);
1.1.1.3 misho 189: got_match = true;
190: ep = &cp[3];
191: #endif
1.1 misho 192: } else {
1.1.1.2 misho 193: got_match = false;
1.1 misho 194: }
195:
196: /* check for = auth qualifier */
197: if (got_match && *ep) {
198: cp = ep;
199: while (isspace((unsigned char)*cp) || *cp == '=')
200: cp++;
201: if (strncasecmp(cp, "auth", 4) == 0 &&
202: (isspace((unsigned char)cp[4]) || cp[4] == '\0')) {
1.1.1.6 ! misho 203: TAILQ_LAST(&snl, sudo_nss_list)->ret_if_found = true;
1.1 misho 204: }
205: }
206: }
207: /* Only parse the first "sudoers" line */
208: break;
209: }
210: fclose(fp);
211:
212: nomatch:
213: /* Default to files only if no matches */
1.1.1.6 ! misho 214: if (TAILQ_EMPTY(&snl))
! 215: TAILQ_INSERT_TAIL(&snl, &sudo_nss_file, entries);
1.1 misho 216:
1.1.1.2 misho 217: debug_return_ptr(&snl);
1.1 misho 218: }
219:
220: # else /* !_PATH_NETSVC_CONF && !_PATH_NSSWITCH_CONF */
221:
222: /*
223: * Non-nsswitch.conf version with hard-coded order.
224: */
225: struct sudo_nss_list *
226: sudo_read_nss(void)
227: {
1.1.1.6 ! misho 228: static struct sudo_nss_list snl = TAILQ_HEAD_INITIALIZER(snl);
1.1.1.2 misho 229: debug_decl(sudo_read_nss, SUDO_DEBUG_NSS)
1.1 misho 230:
1.1.1.3 misho 231: # ifdef HAVE_SSSD
1.1.1.6 ! misho 232: TAILQ_INSERT_TAIL(&snl, &sudo_nss_sss, entries);
1.1.1.3 misho 233: # endif
1.1 misho 234: # ifdef HAVE_LDAP
1.1.1.6 ! misho 235: TAILQ_INSERT_TAIL(&snl, &sudo_nss_ldap, entries);
1.1 misho 236: # endif
1.1.1.6 ! misho 237: TAILQ_INSERT_TAIL(&snl, &sudo_nss_file, entries);
1.1 misho 238:
1.1.1.2 misho 239: debug_return_ptr(&snl);
1.1 misho 240: }
241:
242: # endif /* !HAVE_LDAP || !_PATH_NETSVC_CONF */
243:
244: #endif /* HAVE_LDAP && _PATH_NSSWITCH_CONF */
245:
246: static int
247: output(const char *buf)
248: {
249: struct sudo_conv_message msg;
250: struct sudo_conv_reply repl;
1.1.1.2 misho 251: debug_decl(output, SUDO_DEBUG_NSS)
1.1 misho 252:
253: /* Call conversation function */
254: memset(&msg, 0, sizeof(msg));
255: msg.msg_type = SUDO_CONV_INFO_MSG;
256: msg.msg = buf;
257: memset(&repl, 0, sizeof(repl));
258: if (sudo_conv(1, &msg, &repl) == -1)
1.1.1.2 misho 259: debug_return_int(0);
260: debug_return_int(strlen(buf));
1.1 misho 261: }
262:
263: /*
264: * Print out privileges for the specified user.
1.1.1.5 misho 265: * We only get here if the user is allowed to run something.
1.1 misho 266: */
267: void
268: display_privs(struct sudo_nss_list *snl, struct passwd *pw)
269: {
270: struct sudo_nss *nss;
271: struct lbuf defs, privs;
1.1.1.3 misho 272: struct stat sb;
273: int cols, count, olen;
1.1.1.2 misho 274: debug_decl(display_privs, SUDO_DEBUG_NSS)
1.1 misho 275:
1.1.1.3 misho 276: cols = sudo_user.cols;
277: if (fstat(STDOUT_FILENO, &sb) == 0 && S_ISFIFO(sb.st_mode))
278: cols = 0;
279: lbuf_init(&defs, output, 4, NULL, cols);
1.1.1.4 misho 280: lbuf_init(&privs, output, 8, NULL, cols);
1.1 misho 281:
282: /* Display defaults from all sources. */
1.1.1.5 misho 283: lbuf_append(&defs, _("Matching Defaults entries for %s on %s:\n"),
284: pw->pw_name, user_srunhost);
1.1 misho 285: count = 0;
1.1.1.6 ! misho 286: TAILQ_FOREACH(nss, snl, entries) {
1.1 misho 287: count += nss->display_defaults(nss, pw, &defs);
288: }
289: if (count)
290: lbuf_append(&defs, "\n\n");
291: else
292: defs.len = 0;
293:
294: /* Display Runas and Cmnd-specific defaults from all sources. */
295: olen = defs.len;
296: lbuf_append(&defs, _("Runas and Command-specific defaults for %s:\n"),
297: pw->pw_name);
298: count = 0;
1.1.1.6 ! misho 299: TAILQ_FOREACH(nss, snl, entries) {
1.1 misho 300: count += nss->display_bound_defaults(nss, pw, &defs);
301: }
302: if (count)
303: lbuf_append(&defs, "\n\n");
304: else
305: defs.len = olen;
306:
307: /* Display privileges from all sources. */
308: lbuf_append(&privs,
1.1.1.5 misho 309: _("User %s may run the following commands on %s:\n"),
310: pw->pw_name, user_srunhost);
1.1 misho 311: count = 0;
1.1.1.6 ! misho 312: TAILQ_FOREACH(nss, snl, entries) {
1.1 misho 313: count += nss->display_privs(nss, pw, &privs);
314: }
1.1.1.3 misho 315: if (count == 0) {
316: defs.len = 0;
317: privs.len = 0;
318: lbuf_append(&privs, _("User %s is not allowed to run sudo on %s.\n"),
319: pw->pw_name, user_shost);
1.1 misho 320: }
1.1.1.3 misho 321: lbuf_print(&defs);
322: lbuf_print(&privs);
1.1 misho 323:
324: lbuf_destroy(&defs);
325: lbuf_destroy(&privs);
1.1.1.2 misho 326:
327: debug_return;
1.1 misho 328: }
329:
330: /*
331: * Check user_cmnd against sudoers and print the matching entry if the
332: * command is allowed.
1.1.1.2 misho 333: * Returns true if the command is allowed, else false.
1.1 misho 334: */
1.1.1.2 misho 335: bool
1.1 misho 336: display_cmnd(struct sudo_nss_list *snl, struct passwd *pw)
337: {
338: struct sudo_nss *nss;
1.1.1.2 misho 339: debug_decl(display_cmnd, SUDO_DEBUG_NSS)
1.1 misho 340:
1.1.1.6 ! misho 341: TAILQ_FOREACH(nss, snl, entries) {
1.1 misho 342: if (nss->display_cmnd(nss, pw) == 0)
1.1.1.2 misho 343: debug_return_bool(true);
1.1 misho 344: }
1.1.1.2 misho 345: debug_return_bool(false);
1.1 misho 346: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>