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