Annotation of embedaddon/sudo/plugins/sudoers/sudoers.c, revision 1.1.1.6
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: #ifdef HAVE_BSD_AUTH_H
104: char *login_style;
105: #endif /* HAVE_BSD_AUTH_H */
106: int sudo_mode;
107:
108: static char *prev_user;
109: static char *runas_user;
110: static char *runas_group;
111: static struct sudo_nss_list *snl;
112:
113: /* XXX - must be extern for audit bits of sudo_auth.c */
114: int NewArgc;
115: char **NewArgv;
116:
1.1.1.4 misho 117: int
118: sudoers_policy_init(void *info, char * const envp[])
1.1 misho 119: {
120: volatile int sources = 0;
1.1.1.4 misho 121: struct sudo_nss *nss, *nss_next;
122: debug_decl(sudoers_policy_init, SUDO_DEBUG_PLUGIN)
1.1 misho 123:
124: bindtextdomain("sudoers", LOCALEDIR);
125:
126: sudo_setpwent();
127: sudo_setgrent();
128:
1.1.1.4 misho 129: /* Register fatal/fatalx callback. */
130: fatal_callback_register(sudoers_cleanup);
131:
1.1 misho 132: /* Initialize environment functions (including replacements). */
133: env_init(envp);
134:
135: /* Setup defaults data structures. */
136: init_defaults();
137:
1.1.1.4 misho 138: /* Parse info from front-end. */
139: sudo_mode = sudoers_policy_deserialize_info(info, &runas_user, &runas_group);
1.1 misho 140:
141: init_vars(envp); /* XXX - move this later? */
142:
143: /* Parse nsswitch.conf for sudoers order. */
144: snl = sudo_read_nss();
145:
146: /* LDAP or NSS may modify the euid so we need to be root for the open. */
147: set_perms(PERM_ROOT);
148:
149: /* Open and parse sudoers, set global defaults */
1.1.1.6 ! misho 150: TAILQ_FOREACH_SAFE(nss, snl, entries, nss_next) {
1.1.1.3 misho 151: if (nss->open(nss) == 0 && nss->parse(nss) == 0) {
152: sources++;
153: if (nss->setdefs(nss) != 0)
1.1.1.4 misho 154: log_warning(NO_STDERR, N_("problem with defaults entries"));
1.1.1.3 misho 155: } else {
1.1.1.6 ! misho 156: TAILQ_REMOVE(snl, nss, entries);
1.1.1.3 misho 157: }
1.1 misho 158: }
159: if (sources == 0) {
1.1.1.6 ! misho 160: warningx(U_("no valid sudoers sources found, quitting"));
1.1.1.2 misho 161: debug_return_bool(-1);
1.1 misho 162: }
163:
164: /* XXX - collect post-sudoers parse settings into a function */
165:
166: /*
167: * Initialize external group plugin, if any.
168: */
169: if (def_group_plugin) {
1.1.1.2 misho 170: if (group_plugin_load(def_group_plugin) != true)
1.1 misho 171: def_group_plugin = NULL;
172: }
173:
174: /*
175: * Set runas passwd/group entries based on command line or sudoers.
176: * Note that if runas_group was specified without runas_user we
177: * defer setting runas_pw so the match routines know to ignore it.
178: */
1.1.1.4 misho 179: /* XXX - qpm4u does more here as it may have already set runas_pw */
1.1 misho 180: if (runas_group != NULL) {
181: set_runasgr(runas_group);
182: if (runas_user != NULL)
183: set_runaspw(runas_user);
184: } else
185: set_runaspw(runas_user ? runas_user : def_runas_default);
186:
187: if (!update_defaults(SETDEF_RUNAS))
1.1.1.4 misho 188: log_warning(NO_STDERR, N_("problem with defaults entries"));
1.1 misho 189:
190: if (def_fqdn)
191: set_fqdn(); /* deferred until after sudoers is parsed */
192:
193: /* Set login class if applicable. */
1.1.1.2 misho 194: set_loginclass(runas_pw ? runas_pw : sudo_user.pw);
1.1 misho 195:
196: restore_perms();
197:
1.1.1.2 misho 198: debug_return_bool(true);
1.1 misho 199: }
200:
1.1.1.4 misho 201: int
1.1 misho 202: sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
1.1.1.4 misho 203: void *closure)
1.1 misho 204: {
205: char **edit_argv = NULL;
1.1.1.4 misho 206: char *iolog_path = NULL;
207: mode_t cmnd_umask = 0777;
1.1 misho 208: struct sudo_nss *nss;
1.1.1.4 misho 209: int cmnd_status = -1, oldlocale, validated;
1.1.1.2 misho 210: volatile int rval = true;
211: debug_decl(sudoers_policy_main, SUDO_DEBUG_PLUGIN)
1.1 misho 212:
1.1.1.4 misho 213: /* XXX - would like to move this to policy.c but need the cleanup. */
214: if (fatal_setjmp() != 0) {
215: /* error recovery via fatal(), fatalx() or log_fatal() */
1.1 misho 216: rval = -1;
217: goto done;
218: }
219:
220: /* Is root even allowed to run sudo? */
221: if (user_uid == 0 && !def_root_sudo) {
1.1.1.6 ! misho 222: warningx(U_("sudoers specifies that root is not allowed to sudo"));
1.1 misho 223: goto bad;
224: }
225:
226: set_perms(PERM_INITIAL);
227:
228: /* Environment variables specified on the command line. */
229: if (env_add != NULL && env_add[0] != NULL)
230: sudo_user.env_vars = env_add;
231:
232: /*
233: * Make a local copy of argc/argv, with special handling
234: * for pseudo-commands and the '-i' option.
235: */
236: if (argc == 0) {
237: NewArgc = 1;
238: NewArgv = emalloc2(NewArgc + 1, sizeof(char *));
239: NewArgv[0] = user_cmnd;
240: NewArgv[1] = NULL;
241: } else {
242: /* Must leave an extra slot before NewArgv for bash's --login */
243: NewArgc = argc;
244: NewArgv = emalloc2(NewArgc + 2, sizeof(char *));
245: memcpy(++NewArgv, argv, argc * sizeof(char *));
246: NewArgv[NewArgc] = NULL;
1.1.1.2 misho 247: if (ISSET(sudo_mode, MODE_LOGIN_SHELL) && runas_pw != NULL)
1.1 misho 248: NewArgv[0] = estrdup(runas_pw->pw_shell);
249: }
250:
251: /* If given the -P option, set the "preserve_groups" flag. */
252: if (ISSET(sudo_mode, MODE_PRESERVE_GROUPS))
1.1.1.2 misho 253: def_preserve_groups = true;
1.1 misho 254:
1.1.1.5 misho 255: /* Find command in path and apply per-command Defaults. */
1.1 misho 256: cmnd_status = set_cmnd();
257:
1.1.1.5 misho 258: /* Check for -C overriding def_closefrom. */
259: if (user_closefrom >= 0 && user_closefrom != def_closefrom) {
260: if (!def_closefrom_override) {
1.1.1.6 ! misho 261: warningx(U_("you are not permitted to use the -C option"));
1.1.1.5 misho 262: goto bad;
263: }
264: def_closefrom = user_closefrom;
265: }
266:
1.1 misho 267: /*
1.1.1.4 misho 268: * Check sudoers sources, using the locale specified in sudoers.
1.1 misho 269: */
1.1.1.4 misho 270: sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
1.1 misho 271: validated = FLAG_NO_USER | FLAG_NO_HOST;
1.1.1.6 ! misho 272: TAILQ_FOREACH(nss, snl, entries) {
1.1 misho 273: validated = nss->lookup(nss, validated, pwflag);
274:
275: if (ISSET(validated, VALIDATE_OK)) {
1.1.1.3 misho 276: /* Handle [SUCCESS=return] */
1.1 misho 277: if (nss->ret_if_found)
278: break;
279: } else {
280: /* Handle [NOTFOUND=return] */
281: if (nss->ret_if_notfound)
282: break;
283: }
284: }
285:
1.1.1.4 misho 286: /* Restore user's locale. */
287: sudoers_setlocale(oldlocale, NULL);
288:
1.1 misho 289: if (safe_cmnd == NULL)
290: safe_cmnd = estrdup(user_cmnd);
291:
292: /* If only a group was specified, set runas_pw based on invoking user. */
293: if (runas_pw == NULL)
294: set_runaspw(user_name);
295:
296: /*
297: * Look up the timestamp dir owner if one is specified.
298: */
299: if (def_timestampowner) {
1.1.1.6 ! misho 300: struct passwd *pw = NULL;
1.1 misho 301:
1.1.1.6 ! misho 302: if (*def_timestampowner == '#') {
! 303: const char *errstr;
! 304: uid_t uid = atoid(def_timestampowner + 1, NULL, NULL, &errstr);
! 305: if (errstr == NULL)
! 306: pw = sudo_getpwuid(uid);
! 307: }
! 308: if (pw == NULL)
1.1 misho 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"));
1.1.1.6 ! misho 329: warningx(U_("sorry, you must have a tty to run sudo"));
1.1.1.4 misho 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.1.6 ! misho 378: warningx(U_("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run."), user_cmnd, user_cmnd, user_cmnd);
1.1 misho 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]);
1.1.1.6 ! misho 383: warningx(U_("%s: command not found"), NewArgv[0]);
1.1.1.4 misho 384: } else {
385: audit_failure(NewArgv, N_("%s: command not found"), user_cmnd);
1.1.1.6 ! misho 386: warningx(U_("%s: command not found"), user_cmnd);
1.1.1.4 misho 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)) {
1.1.1.6 ! misho 394: warningx(U_("sorry, you are not allowed to preserve the environment"));
1.1 misho 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 */
1.1.1.6 ! misho 416: TAILQ_FOREACH(nss, snl, entries) {
1.1 misho 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)
1.1.1.6 ! misho 562: fatalx(U_("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.6 ! misho 656: fatalx(U_("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: /*
1.1.1.6 ! misho 696: * If we are expecting sudoers to be group readable by
! 697: * SUDOERS_GID but it is not, we must open the file as root,
! 698: * not uid 1.
1.1.1.3 misho 699: */
1.1.1.6 ! misho 700: if (sudoers_uid == ROOT_UID && ISSET(sudoers_mode, S_IRGRP)) {
! 701: if (!ISSET(sb.st_mode, S_IRGRP) || sb.st_gid != SUDOERS_GID) {
1.1.1.3 misho 702: restore_perms();
703: set_perms(PERM_ROOT);
704: }
705: }
706: /*
707: * Open sudoers and make sure we can read it so we can present
708: * the user with a reasonable error message (unlike the lexer).
709: */
1.1.1.2 misho 710: if ((fp = fopen(sudoers, "r")) == NULL) {
1.1.1.4 misho 711: log_warning(USE_ERRNO, N_("unable to open %s"), sudoers);
1.1.1.2 misho 712: } else {
713: if (sb.st_size != 0 && fgetc(fp) == EOF) {
1.1.1.4 misho 714: log_warning(USE_ERRNO, N_("unable to read %s"),
1.1.1.2 misho 715: sudoers);
716: fclose(fp);
717: fp = NULL;
718: } else {
719: /* Rewind fp and set close on exec flag. */
720: rewind(fp);
721: (void) fcntl(fileno(fp), F_SETFD, 1);
722: }
723: }
724: break;
725: case SUDO_PATH_MISSING:
1.1.1.4 misho 726: log_warning(USE_ERRNO, N_("unable to stat %s"), sudoers);
1.1.1.2 misho 727: break;
728: case SUDO_PATH_BAD_TYPE:
1.1.1.4 misho 729: log_warning(0, N_("%s is not a regular file"), sudoers);
1.1.1.2 misho 730: break;
731: case SUDO_PATH_WRONG_OWNER:
1.1.1.4 misho 732: log_warning(0, N_("%s is owned by uid %u, should be %u"),
1.1.1.2 misho 733: sudoers, (unsigned int) sb.st_uid, (unsigned int) sudoers_uid);
734: break;
735: case SUDO_PATH_WORLD_WRITABLE:
1.1.1.4 misho 736: log_warning(0, N_("%s is world writable"), sudoers);
1.1.1.2 misho 737: break;
738: case SUDO_PATH_GROUP_WRITABLE:
1.1.1.4 misho 739: log_warning(0, N_("%s is owned by gid %u, should be %u"),
1.1.1.2 misho 740: sudoers, (unsigned int) sb.st_gid, (unsigned int) sudoers_gid);
741: break;
742: default:
743: /* NOTREACHED */
744: break;
1.1 misho 745: }
746:
747: restore_perms(); /* change back to root */
1.1.1.2 misho 748:
749: debug_return_ptr(fp);
1.1 misho 750: }
751:
752: #ifdef HAVE_LOGIN_CAP_H
753: static void
754: set_loginclass(struct passwd *pw)
755: {
1.1.1.2 misho 756: const int errflags = NO_MAIL|MSG_ONLY;
757: login_cap_t *lc;
758: debug_decl(set_loginclass, SUDO_DEBUG_PLUGIN)
1.1 misho 759:
1.1.1.2 misho 760: if (!def_use_loginclass)
761: debug_return;
1.1 misho 762:
763: if (login_class && strcmp(login_class, "-") != 0) {
1.1.1.6 ! misho 764: if (user_uid != 0 && pw->pw_uid != 0)
! 765: fatalx(U_("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.6 ! misho 838: struct passwd *pw = NULL;
1.1.1.2 misho 839: debug_decl(set_runaspw, SUDO_DEBUG_PLUGIN)
840:
1.1 misho 841: if (*user == '#') {
1.1.1.6 ! misho 842: const char *errstr;
! 843: uid_t uid = atoid(user + 1, NULL, NULL, &errstr);
! 844: if (errstr == NULL) {
! 845: if ((pw = sudo_getpwuid(uid)) == NULL)
! 846: pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0);
! 847: }
! 848: }
! 849: if (pw == NULL) {
! 850: if ((pw = sudo_getpwnam(user)) == NULL)
1.1.1.4 misho 851: log_fatal(NO_MAIL|MSG_ONLY, N_("unknown user: %s"), user);
1.1 misho 852: }
1.1.1.6 ! misho 853: if (runas_pw != NULL)
! 854: sudo_pw_delref(runas_pw);
! 855: runas_pw = pw;
1.1.1.2 misho 856: debug_return;
1.1 misho 857: }
858:
859: /*
860: * Get group entry for the group we are going to run commands as
861: * and store it in runas_gr.
862: */
863: static void
864: set_runasgr(const char *group)
865: {
1.1.1.6 ! misho 866: struct group *gr = NULL;
1.1.1.2 misho 867: debug_decl(set_runasgr, SUDO_DEBUG_PLUGIN)
868:
1.1 misho 869: if (*group == '#') {
1.1.1.6 ! misho 870: const char *errstr;
! 871: gid_t gid = atoid(group + 1, NULL, NULL, &errstr);
! 872: if (errstr == NULL) {
! 873: if ((gr = sudo_getgrgid(gid)) == NULL)
! 874: gr = sudo_fakegrnam(group);
! 875: }
! 876: }
! 877: if (gr == NULL) {
! 878: if ((gr = sudo_getgrnam(group)) == NULL)
1.1.1.4 misho 879: log_fatal(NO_MAIL|MSG_ONLY, N_("unknown group: %s"), group);
1.1 misho 880: }
1.1.1.6 ! misho 881: if (runas_gr != NULL)
! 882: sudo_gr_delref(runas_gr);
! 883: runas_gr = gr;
1.1.1.2 misho 884: debug_return;
1.1 misho 885: }
886:
887: /*
888: * Callback for runas_default sudoers setting.
889: */
890: static int
891: cb_runas_default(const char *user)
892: {
893: /* Only reset runaspw if user didn't specify one. */
894: if (!runas_user && !runas_group)
895: set_runaspw(user);
1.1.1.2 misho 896: return true;
1.1 misho 897: }
898:
899: /*
1.1.1.4 misho 900: * Callback for sudoers_locale sudoers setting.
1.1 misho 901: */
902: static int
1.1.1.4 misho 903: cb_sudoers_locale(const char *locale)
1.1 misho 904: {
1.1.1.4 misho 905: sudoers_initlocale(NULL, locale);
906: return true;
1.1 misho 907: }
908:
1.1.1.4 misho 909: /*
910: * Cleanup hook for fatal()/fatalx()
911: */
912: void
913: sudoers_cleanup(void)
1.1 misho 914: {
1.1.1.4 misho 915: struct sudo_nss *nss;
916: debug_decl(sudoers_cleanup, SUDO_DEBUG_PLUGIN)
1.1 misho 917:
1.1.1.4 misho 918: if (snl != NULL) {
1.1.1.6 ! misho 919: TAILQ_FOREACH(nss, snl, entries) {
1.1.1.4 misho 920: nss->close(nss);
1.1.1.6 ! misho 921: }
1.1.1.2 misho 922: }
1.1.1.4 misho 923: if (def_group_plugin)
924: group_plugin_unload();
925: sudo_endpwent();
926: sudo_endgrent();
1.1.1.2 misho 927:
1.1.1.4 misho 928: debug_return;
1.1 misho 929: }
930:
931: static char *
1.1.1.4 misho 932: resolve_editor(const char *ed, size_t edlen, int nfiles, char **files, char ***argv_out)
1.1 misho 933: {
1.1.1.4 misho 934: char *cp, **nargv, *editor, *editor_path = NULL;
1.1.1.2 misho 935: int ac, i, nargc;
936: bool wasblank;
937: debug_decl(resolve_editor, SUDO_DEBUG_PLUGIN)
1.1 misho 938:
1.1.1.4 misho 939: /* Note: editor becomes part of argv_out and is not freed. */
940: editor = emalloc(edlen + 1);
941: memcpy(editor, ed, edlen);
942: editor[edlen] = '\0';
1.1 misho 943:
944: /*
945: * Split editor into an argument vector; editor is reused (do not free).
946: * The EDITOR and VISUAL environment variables may contain command
947: * line args so look for those and alloc space for them too.
948: */
949: nargc = 1;
1.1.1.2 misho 950: for (wasblank = false, cp = editor; *cp != '\0'; cp++) {
1.1 misho 951: if (isblank((unsigned char) *cp))
1.1.1.2 misho 952: wasblank = true;
1.1 misho 953: else if (wasblank) {
1.1.1.2 misho 954: wasblank = false;
1.1 misho 955: nargc++;
956: }
957: }
958: /* If we can't find the editor in the user's PATH, give up. */
959: cp = strtok(editor, " \t");
960: if (cp == NULL ||
961: find_path(cp, &editor_path, NULL, getenv("PATH"), 0) != FOUND) {
962: efree(editor);
1.1.1.2 misho 963: debug_return_str(NULL);
1.1 misho 964: }
965: nargv = (char **) emalloc2(nargc + 1 + nfiles + 1, sizeof(char *));
966: for (ac = 0; cp != NULL && ac < nargc; ac++) {
967: nargv[ac] = cp;
968: cp = strtok(NULL, " \t");
969: }
970: nargv[ac++] = "--";
971: for (i = 0; i < nfiles; )
972: nargv[ac++] = files[i++];
973: nargv[ac] = NULL;
974:
975: *argv_out = nargv;
1.1.1.2 misho 976: debug_return_str(editor_path);
1.1 misho 977: }
978:
979: /*
980: * Determine which editor to use. We don't need to worry about restricting
981: * this to a "safe" editor since it runs with the uid of the invoking user,
982: * not the runas (privileged) user.
983: */
984: static char *
985: find_editor(int nfiles, char **files, char ***argv_out)
986: {
1.1.1.4 misho 987: const char *cp, *ep, *editor;
988: char *editor_path = NULL, **ev, *ev0[4];
989: size_t len;
1.1.1.2 misho 990: debug_decl(find_editor, SUDO_DEBUG_PLUGIN)
1.1 misho 991:
992: /*
993: * If any of SUDO_EDITOR, VISUAL or EDITOR are set, choose the first one.
994: */
995: ev0[0] = "SUDO_EDITOR";
996: ev0[1] = "VISUAL";
997: ev0[2] = "EDITOR";
998: ev0[3] = NULL;
1.1.1.4 misho 999: for (ev = ev0; editor_path == NULL && *ev != NULL; ev++) {
1.1 misho 1000: if ((editor = getenv(*ev)) != NULL && *editor != '\0') {
1.1.1.4 misho 1001: editor_path = resolve_editor(editor, strlen(editor), nfiles,
1002: files, argv_out);
1.1 misho 1003: }
1004: }
1005: if (editor_path == NULL) {
1.1.1.4 misho 1006: /* def_editor could be a path, split it up, avoiding strtok() */
1007: cp = editor = def_editor;
1008: do {
1009: if ((ep = strchr(cp, ':')) != NULL)
1010: len = ep - cp;
1011: else
1012: len = strlen(cp);
1013: editor_path = resolve_editor(cp, len, nfiles, files, argv_out);
1014: cp = ep + 1;
1015: } while (ep != NULL && editor_path == NULL);
1.1 misho 1016: }
1017: if (!editor_path) {
1.1.1.4 misho 1018: audit_failure(NewArgv, N_("%s: command not found"), editor);
1.1.1.6 ! misho 1019: warningx(U_("%s: command not found"), editor);
1.1 misho 1020: }
1.1.1.2 misho 1021: debug_return_str(editor_path);
1.1 misho 1022: }
1023:
1024: #ifdef USE_ADMIN_FLAG
1025: static void
1026: create_admin_success_flag(void)
1027: {
1028: struct stat statbuf;
1029: char flagfile[PATH_MAX];
1030: int fd, n;
1.1.1.2 misho 1031: debug_decl(create_admin_success_flag, SUDO_DEBUG_PLUGIN)
1.1 misho 1032:
1033: /* Check whether the user is in the admin group. */
1034: if (!user_in_group(sudo_user.pw, "admin"))
1.1.1.2 misho 1035: debug_return;
1.1 misho 1036:
1037: /* Build path to flag file. */
1038: n = snprintf(flagfile, sizeof(flagfile), "%s/.sudo_as_admin_successful",
1039: user_dir);
1.1.1.6 ! misho 1040: if (n <= 0 || (size_t)n >= sizeof(flagfile))
1.1.1.2 misho 1041: debug_return;
1.1 misho 1042:
1043: /* Create admin flag file if it doesn't already exist. */
1044: set_perms(PERM_USER);
1045: if (stat(flagfile, &statbuf) != 0) {
1046: fd = open(flagfile, O_CREAT|O_WRONLY|O_EXCL, 0644);
1047: close(fd);
1048: }
1049: restore_perms();
1.1.1.2 misho 1050: debug_return;
1.1 misho 1051: }
1052: #else /* !USE_ADMIN_FLAG */
1053: static void
1054: create_admin_success_flag(void)
1055: {
1056: /* STUB */
1057: }
1058: #endif /* USE_ADMIN_FLAG */
1059:
1.1.1.4 misho 1060: static bool
1061: tty_present(void)
1.1.1.2 misho 1062: {
1.1.1.4 misho 1063: #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__)
1064: return user_ttypath != NULL;
1065: #else
1066: int fd = open(_PATH_TTY, O_RDWR|O_NOCTTY);
1067: if (fd != -1)
1068: close(fd);
1069: return fd != -1;
1070: #endif
1.1.1.2 misho 1071: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>