Annotation of embedaddon/sudo/plugins/sudoers/sudoers.c, revision 1.1.1.5
1.1 misho 1: /*
1.1.1.4 misho 2: * Copyright (c) 1993-1996, 1998-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: * Sponsored in part by the Defense Advanced Research Projects
17: * Agency (DARPA) and Air Force Research Laboratory, Air Force
18: * Materiel Command, USAF, under agreement number F39502-99-1-0512.
19: */
20:
21: #define _SUDO_MAIN
22:
23: #ifdef __TANDEM
24: # include <floss.h>
25: #endif
26:
27: #include <config.h>
28:
29: #include <sys/types.h>
30: #include <sys/stat.h>
31: #include <sys/socket.h>
32: #include <stdio.h>
33: #ifdef STDC_HEADERS
34: # include <stdlib.h>
35: # include <stddef.h>
36: #else
37: # ifdef HAVE_STDLIB_H
38: # include <stdlib.h>
39: # endif
40: #endif /* STDC_HEADERS */
41: #ifdef HAVE_STRING_H
42: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
43: # include <memory.h>
44: # endif
45: # include <string.h>
46: #endif /* HAVE_STRING_H */
47: #ifdef HAVE_STRINGS_H
48: # include <strings.h>
49: #endif /* HAVE_STRINGS_H */
50: #ifdef HAVE_UNISTD_H
51: # include <unistd.h>
52: #endif /* HAVE_UNISTD_H */
53: #include <pwd.h>
54: #include <errno.h>
55: #include <fcntl.h>
56: #include <signal.h>
57: #include <grp.h>
58: #include <time.h>
59: #include <netdb.h>
60: #ifdef HAVE_LOGIN_CAP_H
61: # include <login_cap.h>
62: # ifndef LOGIN_DEFROOTCLASS
63: # define LOGIN_DEFROOTCLASS "daemon"
64: # endif
1.1.1.2 misho 65: # ifndef LOGIN_SETENV
66: # define LOGIN_SETENV 0
67: # endif
1.1 misho 68: #endif
69: #ifdef HAVE_SELINUX
70: # include <selinux/selinux.h>
71: #endif
72: #include <ctype.h>
1.1.1.2 misho 73: #ifndef HAVE_GETADDRINFO
74: # include "compat/getaddrinfo.h"
75: #endif
1.1 misho 76:
77: #include "sudoers.h"
78: #include "auth/sudo_auth.h"
1.1.1.2 misho 79: #include "secure_path.h"
1.1 misho 80:
81: /*
82: * Prototypes
83: */
1.1.1.4 misho 84: static char *find_editor(int nfiles, char **files, char ***argv_out);
85: static int cb_runas_default(const char *);
86: static int cb_sudoers_locale(const char *);
1.1 misho 87: static int set_cmnd(void);
1.1.1.4 misho 88: static void create_admin_success_flag(void);
89: static void init_vars(char * const *);
90: static void set_fqdn(void);
1.1 misho 91: static void set_loginclass(struct passwd *);
92: static void set_runasgr(const char *);
1.1.1.4 misho 93: static void set_runaspw(const char *);
94: static bool tty_present(void);
1.1 misho 95:
96: /*
97: * Globals
98: */
99: struct sudo_user sudo_user;
100: struct passwd *list_pw;
101: int long_list;
102: uid_t timestamp_uid;
103: extern int errorlineno;
1.1.1.2 misho 104: extern bool parse_error;
1.1 misho 105: extern char *errorfile;
106: #ifdef HAVE_BSD_AUTH_H
107: char *login_style;
108: #endif /* HAVE_BSD_AUTH_H */
109: int sudo_mode;
110:
111: static char *prev_user;
112: static char *runas_user;
113: static char *runas_group;
114: static struct sudo_nss_list *snl;
115:
116: /* XXX - must be extern for audit bits of sudo_auth.c */
117: int NewArgc;
118: char **NewArgv;
119:
1.1.1.4 misho 120: int
121: sudoers_policy_init(void *info, char * const envp[])
1.1 misho 122: {
123: volatile int sources = 0;
1.1.1.4 misho 124: struct sudo_nss *nss, *nss_next;
125: debug_decl(sudoers_policy_init, SUDO_DEBUG_PLUGIN)
1.1 misho 126:
127: bindtextdomain("sudoers", LOCALEDIR);
128:
129: sudo_setpwent();
130: sudo_setgrent();
131:
1.1.1.4 misho 132: /* Register fatal/fatalx callback. */
133: fatal_callback_register(sudoers_cleanup);
134:
1.1 misho 135: /* Initialize environment functions (including replacements). */
136: env_init(envp);
137:
138: /* Setup defaults data structures. */
139: init_defaults();
140:
1.1.1.4 misho 141: /* Parse info from front-end. */
142: sudo_mode = sudoers_policy_deserialize_info(info, &runas_user, &runas_group);
1.1 misho 143:
144: init_vars(envp); /* XXX - move this later? */
145:
146: /* Parse nsswitch.conf for sudoers order. */
147: snl = sudo_read_nss();
148:
149: /* LDAP or NSS may modify the euid so we need to be root for the open. */
150: set_perms(PERM_ROOT);
151:
152: /* Open and parse sudoers, set global defaults */
1.1.1.3 misho 153: for (nss = snl->first; nss != NULL; nss = nss_next) {
154: nss_next = nss->next;
155: if (nss->open(nss) == 0 && nss->parse(nss) == 0) {
156: sources++;
157: if (nss->setdefs(nss) != 0)
1.1.1.4 misho 158: log_warning(NO_STDERR, N_("problem with defaults entries"));
1.1.1.3 misho 159: } else {
160: tq_remove(snl, nss);
161: }
1.1 misho 162: }
163: if (sources == 0) {
164: warningx(_("no valid sudoers sources found, quitting"));
1.1.1.2 misho 165: debug_return_bool(-1);
1.1 misho 166: }
167:
168: /* XXX - collect post-sudoers parse settings into a function */
169:
170: /*
171: * Initialize external group plugin, if any.
172: */
173: if (def_group_plugin) {
1.1.1.2 misho 174: if (group_plugin_load(def_group_plugin) != true)
1.1 misho 175: def_group_plugin = NULL;
176: }
177:
178: /*
179: * Set runas passwd/group entries based on command line or sudoers.
180: * Note that if runas_group was specified without runas_user we
181: * defer setting runas_pw so the match routines know to ignore it.
182: */
1.1.1.4 misho 183: /* XXX - qpm4u does more here as it may have already set runas_pw */
1.1 misho 184: if (runas_group != NULL) {
185: set_runasgr(runas_group);
186: if (runas_user != NULL)
187: set_runaspw(runas_user);
188: } else
189: set_runaspw(runas_user ? runas_user : def_runas_default);
190:
191: if (!update_defaults(SETDEF_RUNAS))
1.1.1.4 misho 192: log_warning(NO_STDERR, N_("problem with defaults entries"));
1.1 misho 193:
194: if (def_fqdn)
195: set_fqdn(); /* deferred until after sudoers is parsed */
196:
197: /* Set login class if applicable. */
1.1.1.2 misho 198: set_loginclass(runas_pw ? runas_pw : sudo_user.pw);
1.1 misho 199:
200: restore_perms();
201:
1.1.1.2 misho 202: debug_return_bool(true);
1.1 misho 203: }
204:
1.1.1.4 misho 205: int
1.1 misho 206: sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
1.1.1.4 misho 207: void *closure)
1.1 misho 208: {
209: char **edit_argv = NULL;
1.1.1.4 misho 210: char *iolog_path = NULL;
211: mode_t cmnd_umask = 0777;
1.1 misho 212: struct sudo_nss *nss;
1.1.1.4 misho 213: int cmnd_status = -1, oldlocale, validated;
1.1.1.2 misho 214: volatile int rval = true;
215: debug_decl(sudoers_policy_main, SUDO_DEBUG_PLUGIN)
1.1 misho 216:
1.1.1.4 misho 217: /* XXX - would like to move this to policy.c but need the cleanup. */
218: if (fatal_setjmp() != 0) {
219: /* error recovery via fatal(), fatalx() or log_fatal() */
1.1 misho 220: rval = -1;
221: goto done;
222: }
223:
224: /* Is root even allowed to run sudo? */
225: if (user_uid == 0 && !def_root_sudo) {
226: warningx(_("sudoers specifies that root is not allowed to sudo"));
227: goto bad;
228: }
229:
230: set_perms(PERM_INITIAL);
231:
232: /* Environment variables specified on the command line. */
233: if (env_add != NULL && env_add[0] != NULL)
234: sudo_user.env_vars = env_add;
235:
236: /*
237: * Make a local copy of argc/argv, with special handling
238: * for pseudo-commands and the '-i' option.
239: */
240: if (argc == 0) {
241: NewArgc = 1;
242: NewArgv = emalloc2(NewArgc + 1, sizeof(char *));
243: NewArgv[0] = user_cmnd;
244: NewArgv[1] = NULL;
245: } else {
246: /* Must leave an extra slot before NewArgv for bash's --login */
247: NewArgc = argc;
248: NewArgv = emalloc2(NewArgc + 2, sizeof(char *));
249: memcpy(++NewArgv, argv, argc * sizeof(char *));
250: NewArgv[NewArgc] = NULL;
1.1.1.2 misho 251: if (ISSET(sudo_mode, MODE_LOGIN_SHELL) && runas_pw != NULL)
1.1 misho 252: NewArgv[0] = estrdup(runas_pw->pw_shell);
253: }
254:
255: /* If given the -P option, set the "preserve_groups" flag. */
256: if (ISSET(sudo_mode, MODE_PRESERVE_GROUPS))
1.1.1.2 misho 257: def_preserve_groups = true;
1.1 misho 258:
1.1.1.5 ! misho 259: /* Find command in path and apply per-command Defaults. */
1.1 misho 260: cmnd_status = set_cmnd();
261:
1.1.1.5 ! misho 262: /* Check for -C overriding def_closefrom. */
! 263: if (user_closefrom >= 0 && user_closefrom != def_closefrom) {
! 264: if (!def_closefrom_override) {
! 265: warningx(_("you are not permitted to use the -C option"));
! 266: goto bad;
! 267: }
! 268: def_closefrom = user_closefrom;
! 269: }
! 270:
1.1 misho 271: /*
1.1.1.4 misho 272: * Check sudoers sources, using the locale specified in sudoers.
1.1 misho 273: */
1.1.1.4 misho 274: sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
1.1 misho 275: validated = FLAG_NO_USER | FLAG_NO_HOST;
276: tq_foreach_fwd(snl, nss) {
277: validated = nss->lookup(nss, validated, pwflag);
278:
279: if (ISSET(validated, VALIDATE_OK)) {
1.1.1.3 misho 280: /* Handle [SUCCESS=return] */
1.1 misho 281: if (nss->ret_if_found)
282: break;
283: } else {
284: /* Handle [NOTFOUND=return] */
285: if (nss->ret_if_notfound)
286: break;
287: }
288: }
289:
1.1.1.4 misho 290: /* Restore user's locale. */
291: sudoers_setlocale(oldlocale, NULL);
292:
1.1 misho 293: if (safe_cmnd == NULL)
294: safe_cmnd = estrdup(user_cmnd);
295:
296: /* If only a group was specified, set runas_pw based on invoking user. */
297: if (runas_pw == NULL)
298: set_runaspw(user_name);
299:
300: /*
301: * Look up the timestamp dir owner if one is specified.
302: */
303: if (def_timestampowner) {
304: struct passwd *pw;
305:
306: if (*def_timestampowner == '#')
307: pw = sudo_getpwuid(atoi(def_timestampowner + 1));
308: else
309: pw = sudo_getpwnam(def_timestampowner);
1.1.1.2 misho 310: if (pw != NULL) {
311: timestamp_uid = pw->pw_uid;
1.1.1.3 misho 312: sudo_pw_delref(pw);
1.1.1.2 misho 313: } else {
1.1.1.4 misho 314: log_warning(0, N_("timestamp owner (%s): No such user"),
1.1 misho 315: def_timestampowner);
1.1.1.2 misho 316: timestamp_uid = ROOT_UID;
317: }
1.1 misho 318: }
319:
320: /* If no command line args and "shell_noargs" is not set, error out. */
321: if (ISSET(sudo_mode, MODE_IMPLIED_SHELL) && !def_shell_noargs) {
322: rval = -2; /* usage error */
323: goto done;
324: }
325:
326: /* Bail if a tty is required and we don't have one. */
1.1.1.4 misho 327: if (def_requiretty && !tty_present()) {
328: audit_failure(NewArgv, N_("no tty"));
329: warningx(_("sorry, you must have a tty to run sudo"));
330: goto bad;
1.1 misho 331: }
332:
333: /*
334: * We don't reset the environment for sudoedit or if the user
335: * specified the -E command line flag and they have setenv privs.
336: */
337: if (ISSET(sudo_mode, MODE_EDIT) ||
338: (ISSET(sudo_mode, MODE_PRESERVE_ENV) && def_setenv))
1.1.1.2 misho 339: def_env_reset = false;
1.1 misho 340:
341: /* Build a new environment that avoids any nasty bits. */
342: rebuild_env();
343:
344: /* Require a password if sudoers says so. */
345: rval = check_user(validated, sudo_mode);
1.1.1.3 misho 346: if (rval != true) {
347: if (!ISSET(validated, VALIDATE_OK))
1.1.1.4 misho 348: log_denial(validated, false);
1.1 misho 349: goto done;
1.1.1.3 misho 350: }
1.1 misho 351:
352: /* If run as root with SUDO_USER set, set sudo_user.pw to that user. */
353: /* XXX - causes confusion when root is not listed in sudoers */
354: if (sudo_mode & (MODE_RUN | MODE_EDIT) && prev_user != NULL) {
355: if (user_uid == 0 && strcmp(prev_user, "root") != 0) {
356: struct passwd *pw;
357:
358: if ((pw = sudo_getpwnam(prev_user)) != NULL) {
359: if (sudo_user.pw != NULL)
1.1.1.3 misho 360: sudo_pw_delref(sudo_user.pw);
1.1 misho 361: sudo_user.pw = pw;
362: }
363: }
364: }
365:
366: /* If the user was not allowed to run the command we are done. */
367: if (!ISSET(validated, VALIDATE_OK)) {
1.1.1.3 misho 368: log_failure(validated, cmnd_status);
1.1 misho 369: goto bad;
370: }
371:
372: /* Create Ubuntu-style dot file to indicate sudo was successful. */
373: create_admin_success_flag();
374:
375: /* Finally tell the user if the command did not exist. */
376: if (cmnd_status == NOT_FOUND_DOT) {
1.1.1.4 misho 377: audit_failure(NewArgv, N_("command in current directory"));
1.1 misho 378: warningx(_("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run."), user_cmnd, user_cmnd, user_cmnd);
379: goto bad;
380: } else if (cmnd_status == NOT_FOUND) {
1.1.1.4 misho 381: if (ISSET(sudo_mode, MODE_CHECK)) {
382: audit_failure(NewArgv, N_("%s: command not found"), NewArgv[0]);
383: warningx(_("%s: command not found"), NewArgv[0]);
384: } else {
385: audit_failure(NewArgv, N_("%s: command not found"), user_cmnd);
386: warningx(_("%s: command not found"), user_cmnd);
387: }
1.1 misho 388: goto bad;
389: }
390:
391: /* If user specified env vars make sure sudoers allows it. */
392: if (ISSET(sudo_mode, MODE_RUN) && !def_setenv) {
393: if (ISSET(sudo_mode, MODE_PRESERVE_ENV)) {
394: warningx(_("sorry, you are not allowed to preserve the environment"));
395: goto bad;
396: } else
397: validate_env_vars(sudo_user.env_vars);
398: }
399:
1.1.1.4 misho 400: if (ISSET(sudo_mode, (MODE_RUN | MODE_EDIT))) {
401: if ((def_log_input || def_log_output) && def_iolog_file && def_iolog_dir) {
402: const char prefix[] = "iolog_path=";
403: iolog_path = expand_iolog_path(prefix, def_iolog_dir,
404: def_iolog_file, &sudo_user.iolog_file);
1.1 misho 405: sudo_user.iolog_file++;
406: }
407: }
408:
409: log_allowed(validated);
410: if (ISSET(sudo_mode, MODE_CHECK))
411: rval = display_cmnd(snl, list_pw ? list_pw : sudo_user.pw);
412: else if (ISSET(sudo_mode, MODE_LIST))
413: display_privs(snl, list_pw ? list_pw : sudo_user.pw); /* XXX - return val */
414:
415: /* Cleanup sudoers sources */
416: tq_foreach_fwd(snl, nss) {
417: nss->close(nss);
418: }
419: if (def_group_plugin)
420: group_plugin_unload();
421:
422: if (ISSET(sudo_mode, (MODE_VALIDATE|MODE_CHECK|MODE_LIST))) {
423: /* rval already set appropriately */
424: goto done;
425: }
426:
427: /*
428: * Set umask based on sudoers.
429: * If user's umask is more restrictive, OR in those bits too
430: * unless umask_override is set.
431: */
432: if (def_umask != 0777) {
1.1.1.4 misho 433: cmnd_umask = def_umask;
434: if (!def_umask_override)
435: cmnd_umask |= user_umask;
1.1 misho 436: }
437:
438: if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
439: char *p;
440:
441: /* Convert /bin/sh -> -sh so shell knows it is a login shell */
442: if ((p = strrchr(NewArgv[0], '/')) == NULL)
443: p = NewArgv[0];
444: *p = '-';
445: NewArgv[0] = p;
446:
447: /*
448: * Newer versions of bash require the --login option to be used
449: * in conjunction with the -c option even if the shell name starts
450: * with a '-'. Unfortunately, bash 1.x uses -login, not --login
451: * so this will cause an error for that.
452: */
453: if (NewArgc > 1 && strcmp(NewArgv[0], "-bash") == 0 &&
454: strcmp(NewArgv[1], "-c") == 0) {
455: /* Use the extra slot before NewArgv so we can store --login. */
456: NewArgv--;
457: NewArgc++;
458: NewArgv[0] = NewArgv[1];
459: NewArgv[1] = "--login";
460: }
461:
1.1.1.2 misho 462: #if defined(_AIX) || (defined(__linux__) && !defined(HAVE_PAM))
1.1 misho 463: /* Insert system-wide environment variables. */
1.1.1.2 misho 464: read_env_file(_PATH_ENVIRONMENT, true);
1.1 misho 465: #endif
1.1.1.2 misho 466: #ifdef HAVE_LOGIN_CAP_H
467: /* Set environment based on login class. */
468: if (login_class) {
469: login_cap_t *lc = login_getclass(login_class);
470: if (lc != NULL) {
471: setusercontext(lc, runas_pw, runas_pw->pw_uid, LOGIN_SETPATH|LOGIN_SETENV);
472: login_close(lc);
473: }
474: }
475: #endif /* HAVE_LOGIN_CAP_H */
1.1 misho 476: }
477:
478: /* Insert system-wide environment variables. */
479: if (def_env_file)
1.1.1.2 misho 480: read_env_file(def_env_file, false);
1.1 misho 481:
482: /* Insert user-specified environment variables. */
483: insert_env_vars(sudo_user.env_vars);
484:
485: if (ISSET(sudo_mode, MODE_EDIT)) {
1.1.1.4 misho 486: efree(safe_cmnd);
487: safe_cmnd = find_editor(NewArgc - 1, NewArgv + 1, &edit_argv);
488: if (safe_cmnd == NULL)
1.1 misho 489: goto bad;
490: }
491:
492: /* Must audit before uid change. */
493: audit_success(NewArgv);
494:
1.1.1.4 misho 495: /* Setup execution environment to pass back to front-end. */
496: rval = sudoers_policy_exec_setup(edit_argv ? edit_argv : NewArgv,
497: env_get(), cmnd_umask, iolog_path, closure);
1.1 misho 498:
1.1.1.4 misho 499: /* Zero out stashed copy of environment, it is owned by the front-end. */
1.1.1.2 misho 500: env_init(NULL);
1.1 misho 501:
502: goto done;
503:
504: bad:
1.1.1.2 misho 505: rval = false;
1.1 misho 506:
507: done:
1.1.1.4 misho 508: fatal_disable_setjmp();
1.1 misho 509: rewind_perms();
510:
511: /* Close the password and group files and free up memory. */
512: sudo_endpwent();
513: sudo_endgrent();
514:
1.1.1.2 misho 515: debug_return_bool(rval);
1.1 misho 516: }
517:
518: /*
1.1.1.4 misho 519: * Initialize timezone and fill in ``sudo_user'' struct.
1.1 misho 520: */
521: static void
522: init_vars(char * const envp[])
523: {
524: char * const * ep;
1.1.1.5 ! misho 525: bool unknown_user = false;
1.1.1.2 misho 526: debug_decl(init_vars, SUDO_DEBUG_PLUGIN)
1.1 misho 527:
1.1.1.4 misho 528: sudoers_initlocale(setlocale(LC_ALL, NULL), def_sudoers_locale);
1.1 misho 529:
530: for (ep = envp; *ep; ep++) {
531: /* XXX - don't fill in if empty string */
532: switch (**ep) {
533: case 'K':
534: if (strncmp("KRB5CCNAME=", *ep, 11) == 0)
535: user_ccname = *ep + 11;
536: break;
537: case 'P':
538: if (strncmp("PATH=", *ep, 5) == 0)
539: user_path = *ep + 5;
540: break;
541: case 'S':
542: if (!user_prompt && strncmp("SUDO_PROMPT=", *ep, 12) == 0)
543: user_prompt = *ep + 12;
544: else if (strncmp("SUDO_USER=", *ep, 10) == 0)
545: prev_user = *ep + 10;
546: break;
547: }
548: }
549:
550: /*
1.1.1.4 misho 551: * Get a local copy of the user's struct passwd if we don't already
552: * have one.
1.1 misho 553: */
1.1.1.4 misho 554: if (sudo_user.pw == NULL) {
555: if ((sudo_user.pw = sudo_getpwnam(user_name)) == NULL) {
556: /*
557: * It is not unusual for users to place "sudo -k" in a .logout
558: * file which can cause sudo to be run during reboot after the
559: * YP/NIS/NIS+/LDAP/etc daemon has died.
560: */
561: if (sudo_mode == MODE_KILL || sudo_mode == MODE_INVALIDATE)
562: fatalx(_("unknown uid: %u"), (unsigned int) user_uid);
1.1 misho 563:
1.1.1.4 misho 564: /* Need to make a fake struct passwd for the call to log_fatal(). */
565: sudo_user.pw = sudo_mkpwent(user_name, user_uid, user_gid, NULL, NULL);
1.1.1.5 ! misho 566: unknown_user = true;
1.1.1.4 misho 567: }
1.1 misho 568: }
569:
570: /*
1.1.1.5 ! misho 571: * Get group list and store initialize permissions.
1.1 misho 572: */
573: if (user_group_list == NULL)
1.1.1.3 misho 574: user_group_list = sudo_get_grlist(sudo_user.pw);
1.1.1.5 ! misho 575: set_perms(PERM_INITIAL);
1.1 misho 576:
577: /* Set runas callback. */
578: sudo_defs_table[I_RUNAS_DEFAULT].callback = cb_runas_default;
579:
1.1.1.4 misho 580: /* Set locale callback. */
581: sudo_defs_table[I_SUDOERS_LOCALE].callback = cb_sudoers_locale;
582:
583: /* Set maxseq callback. */
584: sudo_defs_table[I_MAXSEQ].callback = io_set_max_sessid;
585:
1.1.1.2 misho 586: /* It is now safe to use log_fatal() and set_perms() */
1.1.1.5 ! misho 587: if (unknown_user)
! 588: log_fatal(0, N_("unknown uid: %u"), (unsigned int) user_uid);
1.1.1.2 misho 589: debug_return;
1.1 misho 590: }
591:
592: /*
593: * Fill in user_cmnd, user_args, user_base and user_stat variables
594: * and apply any command-specific defaults entries.
595: */
596: static int
597: set_cmnd(void)
598: {
599: int rval;
600: char *path = user_path;
1.1.1.2 misho 601: debug_decl(set_cmnd, SUDO_DEBUG_PLUGIN)
1.1 misho 602:
603: /* Resolve the path and return. */
604: rval = FOUND;
1.1.1.2 misho 605: user_stat = ecalloc(1, sizeof(struct stat));
1.1 misho 606:
607: /* Default value for cmnd, overridden below. */
608: if (user_cmnd == NULL)
609: user_cmnd = NewArgv[0];
610:
611: if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) {
612: if (ISSET(sudo_mode, MODE_RUN | MODE_CHECK)) {
613: if (def_secure_path && !user_is_exempt())
614: path = def_secure_path;
615: set_perms(PERM_RUNAS);
616: rval = find_path(NewArgv[0], &user_cmnd, user_stat, path,
617: def_ignore_dot);
618: restore_perms();
619: if (rval != FOUND) {
620: /* Failed as root, try as invoking user. */
621: set_perms(PERM_USER);
622: rval = find_path(NewArgv[0], &user_cmnd, user_stat, path,
623: def_ignore_dot);
624: restore_perms();
625: }
626: }
627:
628: /* set user_args */
629: if (NewArgc > 1) {
630: char *to, *from, **av;
631: size_t size, n;
632:
633: /* Alloc and build up user_args. */
634: for (size = 0, av = NewArgv + 1; *av; av++)
635: size += strlen(*av) + 1;
636: user_args = emalloc(size);
637: if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) {
638: /*
639: * When running a command via a shell, the sudo front-end
640: * escapes potential meta chars. We unescape non-spaces
641: * for sudoers matching and logging purposes.
642: */
643: for (to = user_args, av = NewArgv + 1; (from = *av); av++) {
644: while (*from) {
645: if (from[0] == '\\' && !isspace((unsigned char)from[1]))
646: from++;
647: *to++ = *from++;
648: }
649: *to++ = ' ';
650: }
651: *--to = '\0';
652: } else {
653: for (to = user_args, av = NewArgv + 1; *av; av++) {
654: n = strlcpy(to, *av, size - (to - user_args));
655: if (n >= size - (to - user_args))
1.1.1.4 misho 656: fatalx(_("internal error, %s overflow"), "set_cmnd()");
1.1 misho 657: to += n;
658: *to++ = ' ';
659: }
660: *--to = '\0';
661: }
662: }
663: }
1.1.1.4 misho 664: if (strlen(user_cmnd) >= PATH_MAX) {
665: errno = ENAMETOOLONG;
666: fatal("%s", user_cmnd);
667: }
1.1 misho 668:
669: if ((user_base = strrchr(user_cmnd, '/')) != NULL)
670: user_base++;
671: else
672: user_base = user_cmnd;
673:
674: if (!update_defaults(SETDEF_CMND))
1.1.1.4 misho 675: log_warning(NO_STDERR, N_("problem with defaults entries"));
1.1 misho 676:
1.1.1.2 misho 677: debug_return_int(rval);
1.1 misho 678: }
679:
680: /*
681: * Open sudoers and sanity check mode/owner/type.
682: * Returns a handle to the sudoers file or NULL on error.
683: */
684: FILE *
1.1.1.2 misho 685: open_sudoers(const char *sudoers, bool doedit, bool *keepopen)
1.1 misho 686: {
1.1.1.2 misho 687: struct stat sb;
1.1 misho 688: FILE *fp = NULL;
1.1.1.2 misho 689: debug_decl(open_sudoers, SUDO_DEBUG_PLUGIN)
1.1 misho 690:
691: set_perms(PERM_SUDOERS);
692:
1.1.1.2 misho 693: switch (sudo_secure_file(sudoers, sudoers_uid, sudoers_gid, &sb)) {
694: case SUDO_PATH_SECURE:
1.1.1.3 misho 695: /*
696: * If we are expecting sudoers to be group readable but
697: * it is not, we must open the file as root, not uid 1.
698: */
699: if (sudoers_uid == ROOT_UID && (sudoers_mode & S_IRGRP)) {
700: if ((sb.st_mode & S_IRGRP) == 0) {
701: restore_perms();
702: set_perms(PERM_ROOT);
703: }
704: }
705: /*
706: * Open sudoers and make sure we can read it so we can present
707: * the user with a reasonable error message (unlike the lexer).
708: */
1.1.1.2 misho 709: if ((fp = fopen(sudoers, "r")) == NULL) {
1.1.1.4 misho 710: log_warning(USE_ERRNO, N_("unable to open %s"), sudoers);
1.1.1.2 misho 711: } else {
712: if (sb.st_size != 0 && fgetc(fp) == EOF) {
1.1.1.4 misho 713: log_warning(USE_ERRNO, N_("unable to read %s"),
1.1.1.2 misho 714: sudoers);
715: fclose(fp);
716: fp = NULL;
717: } else {
718: /* Rewind fp and set close on exec flag. */
719: rewind(fp);
720: (void) fcntl(fileno(fp), F_SETFD, 1);
721: }
722: }
723: break;
724: case SUDO_PATH_MISSING:
1.1.1.4 misho 725: log_warning(USE_ERRNO, N_("unable to stat %s"), sudoers);
1.1.1.2 misho 726: break;
727: case SUDO_PATH_BAD_TYPE:
1.1.1.4 misho 728: log_warning(0, N_("%s is not a regular file"), sudoers);
1.1.1.2 misho 729: break;
730: case SUDO_PATH_WRONG_OWNER:
1.1.1.4 misho 731: log_warning(0, N_("%s is owned by uid %u, should be %u"),
1.1.1.2 misho 732: sudoers, (unsigned int) sb.st_uid, (unsigned int) sudoers_uid);
733: break;
734: case SUDO_PATH_WORLD_WRITABLE:
1.1.1.4 misho 735: log_warning(0, N_("%s is world writable"), sudoers);
1.1.1.2 misho 736: break;
737: case SUDO_PATH_GROUP_WRITABLE:
1.1.1.4 misho 738: log_warning(0, N_("%s is owned by gid %u, should be %u"),
1.1.1.2 misho 739: sudoers, (unsigned int) sb.st_gid, (unsigned int) sudoers_gid);
740: break;
741: default:
742: /* NOTREACHED */
743: break;
1.1 misho 744: }
745:
746: restore_perms(); /* change back to root */
1.1.1.2 misho 747:
748: debug_return_ptr(fp);
1.1 misho 749: }
750:
751: #ifdef HAVE_LOGIN_CAP_H
752: static void
753: set_loginclass(struct passwd *pw)
754: {
1.1.1.2 misho 755: const int errflags = NO_MAIL|MSG_ONLY;
756: login_cap_t *lc;
757: debug_decl(set_loginclass, SUDO_DEBUG_PLUGIN)
1.1 misho 758:
1.1.1.2 misho 759: if (!def_use_loginclass)
760: debug_return;
1.1 misho 761:
762: if (login_class && strcmp(login_class, "-") != 0) {
763: if (user_uid != 0 &&
764: strcmp(runas_user ? runas_user : def_runas_default, "root") != 0)
1.1.1.4 misho 765: fatalx(_("only root can use `-c %s'"), login_class);
1.1 misho 766: } else {
767: login_class = pw->pw_class;
768: if (!login_class || !*login_class)
769: login_class =
770: (pw->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS;
771: }
772:
1.1.1.2 misho 773: /* Make sure specified login class is valid. */
1.1 misho 774: lc = login_getclass(login_class);
775: if (!lc || !lc->lc_class || strcmp(lc->lc_class, login_class) != 0) {
1.1.1.2 misho 776: /*
777: * Don't make it a fatal error if the user didn't specify the login
778: * class themselves. We do this because if login.conf gets
779: * corrupted we want the admin to be able to use sudo to fix it.
780: */
781: if (login_class)
1.1.1.4 misho 782: log_fatal(errflags, N_("unknown login class: %s"), login_class);
1.1.1.2 misho 783: else
1.1.1.4 misho 784: log_warning(errflags, N_("unknown login class: %s"), login_class);
1.1.1.2 misho 785: def_use_loginclass = false;
1.1 misho 786: }
1.1.1.2 misho 787: login_close(lc);
788: debug_return;
1.1 misho 789: }
790: #else
791: static void
792: set_loginclass(struct passwd *pw)
793: {
794: }
795: #endif /* HAVE_LOGIN_CAP_H */
796:
1.1.1.3 misho 797: #ifndef AI_FQDN
798: # define AI_FQDN AI_CANONNAME
799: #endif
800:
1.1 misho 801: /*
802: * Look up the fully qualified domain name and set user_host and user_shost.
1.1.1.3 misho 803: * Use AI_FQDN if available since "canonical" is not always the same as fqdn.
1.1 misho 804: */
1.1.1.4 misho 805: static void
1.1 misho 806: set_fqdn(void)
807: {
808: struct addrinfo *res0, hint;
809: char *p;
1.1.1.2 misho 810: debug_decl(set_fqdn, SUDO_DEBUG_PLUGIN)
1.1 misho 811:
1.1.1.5 ! misho 812: memset(&hint, 0, sizeof(hint));
1.1 misho 813: hint.ai_family = PF_UNSPEC;
1.1.1.3 misho 814: hint.ai_flags = AI_FQDN;
1.1 misho 815: if (getaddrinfo(user_host, NULL, &hint, &res0) != 0) {
1.1.1.4 misho 816: log_warning(MSG_ONLY, N_("unable to resolve host %s"), user_host);
1.1 misho 817: } else {
818: if (user_shost != user_host)
819: efree(user_shost);
820: efree(user_host);
821: user_host = estrdup(res0->ai_canonname);
822: freeaddrinfo(res0);
1.1.1.3 misho 823: if ((p = strchr(user_host, '.')) != NULL)
824: user_shost = estrndup(user_host, (size_t)(p - user_host));
825: else
826: user_shost = user_host;
1.1 misho 827: }
1.1.1.2 misho 828: debug_return;
1.1 misho 829: }
830:
831: /*
832: * Get passwd entry for the user we are going to run commands as
833: * and store it in runas_pw. By default, commands run as "root".
834: */
1.1.1.2 misho 835: static void
1.1 misho 836: set_runaspw(const char *user)
837: {
1.1.1.2 misho 838: debug_decl(set_runaspw, SUDO_DEBUG_PLUGIN)
839:
1.1 misho 840: if (runas_pw != NULL)
1.1.1.3 misho 841: sudo_pw_delref(runas_pw);
1.1 misho 842: if (*user == '#') {
843: if ((runas_pw = sudo_getpwuid(atoi(user + 1))) == NULL)
844: runas_pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0);
845: } else {
846: if ((runas_pw = sudo_getpwnam(user)) == NULL)
1.1.1.4 misho 847: log_fatal(NO_MAIL|MSG_ONLY, N_("unknown user: %s"), user);
1.1 misho 848: }
1.1.1.2 misho 849: debug_return;
1.1 misho 850: }
851:
852: /*
853: * Get group entry for the group we are going to run commands as
854: * and store it in runas_gr.
855: */
856: static void
857: set_runasgr(const char *group)
858: {
1.1.1.2 misho 859: debug_decl(set_runasgr, SUDO_DEBUG_PLUGIN)
860:
1.1 misho 861: if (runas_gr != NULL)
1.1.1.3 misho 862: sudo_gr_delref(runas_gr);
1.1 misho 863: if (*group == '#') {
864: if ((runas_gr = sudo_getgrgid(atoi(group + 1))) == NULL)
865: runas_gr = sudo_fakegrnam(group);
866: } else {
867: if ((runas_gr = sudo_getgrnam(group)) == NULL)
1.1.1.4 misho 868: log_fatal(NO_MAIL|MSG_ONLY, N_("unknown group: %s"), group);
1.1 misho 869: }
1.1.1.2 misho 870: debug_return;
1.1 misho 871: }
872:
873: /*
874: * Callback for runas_default sudoers setting.
875: */
876: static int
877: cb_runas_default(const char *user)
878: {
879: /* Only reset runaspw if user didn't specify one. */
880: if (!runas_user && !runas_group)
881: set_runaspw(user);
1.1.1.2 misho 882: return true;
1.1 misho 883: }
884:
885: /*
1.1.1.4 misho 886: * Callback for sudoers_locale sudoers setting.
1.1 misho 887: */
888: static int
1.1.1.4 misho 889: cb_sudoers_locale(const char *locale)
1.1 misho 890: {
1.1.1.4 misho 891: sudoers_initlocale(NULL, locale);
892: return true;
1.1 misho 893: }
894:
1.1.1.4 misho 895: /*
896: * Cleanup hook for fatal()/fatalx()
897: */
898: void
899: sudoers_cleanup(void)
1.1 misho 900: {
1.1.1.4 misho 901: struct sudo_nss *nss;
902: debug_decl(sudoers_cleanup, SUDO_DEBUG_PLUGIN)
1.1 misho 903:
1.1.1.4 misho 904: if (snl != NULL) {
905: tq_foreach_fwd(snl, nss)
906: nss->close(nss);
1.1.1.2 misho 907: }
1.1.1.4 misho 908: if (def_group_plugin)
909: group_plugin_unload();
910: sudo_endpwent();
911: sudo_endgrent();
1.1.1.2 misho 912:
1.1.1.4 misho 913: debug_return;
1.1 misho 914: }
915:
916: static char *
1.1.1.4 misho 917: resolve_editor(const char *ed, size_t edlen, int nfiles, char **files, char ***argv_out)
1.1 misho 918: {
1.1.1.4 misho 919: char *cp, **nargv, *editor, *editor_path = NULL;
1.1.1.2 misho 920: int ac, i, nargc;
921: bool wasblank;
922: debug_decl(resolve_editor, SUDO_DEBUG_PLUGIN)
1.1 misho 923:
1.1.1.4 misho 924: /* Note: editor becomes part of argv_out and is not freed. */
925: editor = emalloc(edlen + 1);
926: memcpy(editor, ed, edlen);
927: editor[edlen] = '\0';
1.1 misho 928:
929: /*
930: * Split editor into an argument vector; editor is reused (do not free).
931: * The EDITOR and VISUAL environment variables may contain command
932: * line args so look for those and alloc space for them too.
933: */
934: nargc = 1;
1.1.1.2 misho 935: for (wasblank = false, cp = editor; *cp != '\0'; cp++) {
1.1 misho 936: if (isblank((unsigned char) *cp))
1.1.1.2 misho 937: wasblank = true;
1.1 misho 938: else if (wasblank) {
1.1.1.2 misho 939: wasblank = false;
1.1 misho 940: nargc++;
941: }
942: }
943: /* If we can't find the editor in the user's PATH, give up. */
944: cp = strtok(editor, " \t");
945: if (cp == NULL ||
946: find_path(cp, &editor_path, NULL, getenv("PATH"), 0) != FOUND) {
947: efree(editor);
1.1.1.2 misho 948: debug_return_str(NULL);
1.1 misho 949: }
950: nargv = (char **) emalloc2(nargc + 1 + nfiles + 1, sizeof(char *));
951: for (ac = 0; cp != NULL && ac < nargc; ac++) {
952: nargv[ac] = cp;
953: cp = strtok(NULL, " \t");
954: }
955: nargv[ac++] = "--";
956: for (i = 0; i < nfiles; )
957: nargv[ac++] = files[i++];
958: nargv[ac] = NULL;
959:
960: *argv_out = nargv;
1.1.1.2 misho 961: debug_return_str(editor_path);
1.1 misho 962: }
963:
964: /*
965: * Determine which editor to use. We don't need to worry about restricting
966: * this to a "safe" editor since it runs with the uid of the invoking user,
967: * not the runas (privileged) user.
968: */
969: static char *
970: find_editor(int nfiles, char **files, char ***argv_out)
971: {
1.1.1.4 misho 972: const char *cp, *ep, *editor;
973: char *editor_path = NULL, **ev, *ev0[4];
974: size_t len;
1.1.1.2 misho 975: debug_decl(find_editor, SUDO_DEBUG_PLUGIN)
1.1 misho 976:
977: /*
978: * If any of SUDO_EDITOR, VISUAL or EDITOR are set, choose the first one.
979: */
980: ev0[0] = "SUDO_EDITOR";
981: ev0[1] = "VISUAL";
982: ev0[2] = "EDITOR";
983: ev0[3] = NULL;
1.1.1.4 misho 984: for (ev = ev0; editor_path == NULL && *ev != NULL; ev++) {
1.1 misho 985: if ((editor = getenv(*ev)) != NULL && *editor != '\0') {
1.1.1.4 misho 986: editor_path = resolve_editor(editor, strlen(editor), nfiles,
987: files, argv_out);
1.1 misho 988: }
989: }
990: if (editor_path == NULL) {
1.1.1.4 misho 991: /* def_editor could be a path, split it up, avoiding strtok() */
992: cp = editor = def_editor;
993: do {
994: if ((ep = strchr(cp, ':')) != NULL)
995: len = ep - cp;
996: else
997: len = strlen(cp);
998: editor_path = resolve_editor(cp, len, nfiles, files, argv_out);
999: cp = ep + 1;
1000: } while (ep != NULL && editor_path == NULL);
1.1 misho 1001: }
1002: if (!editor_path) {
1.1.1.4 misho 1003: audit_failure(NewArgv, N_("%s: command not found"), editor);
1.1 misho 1004: warningx(_("%s: command not found"), editor);
1005: }
1.1.1.2 misho 1006: debug_return_str(editor_path);
1.1 misho 1007: }
1008:
1009: #ifdef USE_ADMIN_FLAG
1010: static void
1011: create_admin_success_flag(void)
1012: {
1013: struct stat statbuf;
1014: char flagfile[PATH_MAX];
1015: int fd, n;
1.1.1.2 misho 1016: debug_decl(create_admin_success_flag, SUDO_DEBUG_PLUGIN)
1.1 misho 1017:
1018: /* Check whether the user is in the admin group. */
1019: if (!user_in_group(sudo_user.pw, "admin"))
1.1.1.2 misho 1020: debug_return;
1.1 misho 1021:
1022: /* Build path to flag file. */
1023: n = snprintf(flagfile, sizeof(flagfile), "%s/.sudo_as_admin_successful",
1024: user_dir);
1025: if (n <= 0 || n >= sizeof(flagfile))
1.1.1.2 misho 1026: debug_return;
1.1 misho 1027:
1028: /* Create admin flag file if it doesn't already exist. */
1029: set_perms(PERM_USER);
1030: if (stat(flagfile, &statbuf) != 0) {
1031: fd = open(flagfile, O_CREAT|O_WRONLY|O_EXCL, 0644);
1032: close(fd);
1033: }
1034: restore_perms();
1.1.1.2 misho 1035: debug_return;
1.1 misho 1036: }
1037: #else /* !USE_ADMIN_FLAG */
1038: static void
1039: create_admin_success_flag(void)
1040: {
1041: /* STUB */
1042: }
1043: #endif /* USE_ADMIN_FLAG */
1044:
1.1.1.4 misho 1045: static bool
1046: tty_present(void)
1.1.1.2 misho 1047: {
1.1.1.4 misho 1048: #if defined(HAVE_STRUCT_KINFO_PROC2_P_TDEV) || defined(HAVE_STRUCT_KINFO_PROC_P_TDEV) || defined(HAVE_STRUCT_KINFO_PROC_KI_TDEV) || defined(HAVE_STRUCT_KINFO_PROC_KP_EPROC_E_TDEV) || defined(HAVE_STRUCT_PSINFO_PR_TTYDEV) || defined(HAVE_PSTAT_GETPROC) || defined(__linux__)
1049: return user_ttypath != NULL;
1050: #else
1051: int fd = open(_PATH_TTY, O_RDWR|O_NOCTTY);
1052: if (fd != -1)
1053: close(fd);
1054: return fd != -1;
1055: #endif
1.1.1.2 misho 1056: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>