Annotation of embedaddon/sudo/plugins/sudoers/sudoers.c, revision 1.1.1.2
1.1 misho 1: /*
2: * Copyright (c) 1993-1996, 1998-2011 Todd C. Miller <Todd.Miller@courtesan.com>
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: * For a brief history of sudo, please see the HISTORY file included
21: * with this distribution.
22: */
23:
24: #define _SUDO_MAIN
25:
26: #ifdef __TANDEM
27: # include <floss.h>
28: #endif
29:
30: #include <config.h>
31:
32: #include <sys/types.h>
33: #include <sys/stat.h>
34: #include <sys/param.h>
35: #include <sys/socket.h>
36: #include <stdio.h>
37: #ifdef STDC_HEADERS
38: # include <stdlib.h>
39: # include <stddef.h>
40: #else
41: # ifdef HAVE_STDLIB_H
42: # include <stdlib.h>
43: # endif
44: #endif /* STDC_HEADERS */
45: #ifdef HAVE_STRING_H
46: # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
47: # include <memory.h>
48: # endif
49: # include <string.h>
50: #endif /* HAVE_STRING_H */
51: #ifdef HAVE_STRINGS_H
52: # include <strings.h>
53: #endif /* HAVE_STRINGS_H */
54: #ifdef HAVE_UNISTD_H
55: # include <unistd.h>
56: #endif /* HAVE_UNISTD_H */
57: #include <pwd.h>
58: #include <errno.h>
59: #include <fcntl.h>
60: #include <signal.h>
61: #include <grp.h>
62: #include <time.h>
63: #ifdef HAVE_SETLOCALE
64: # include <locale.h>
65: #endif
66: #include <netinet/in.h>
67: #include <netdb.h>
68: #ifdef HAVE_LOGIN_CAP_H
69: # include <login_cap.h>
70: # ifndef LOGIN_DEFROOTCLASS
71: # define LOGIN_DEFROOTCLASS "daemon"
72: # endif
1.1.1.2 ! misho 73: # ifndef LOGIN_SETENV
! 74: # define LOGIN_SETENV 0
! 75: # endif
1.1 misho 76: #endif
77: #ifdef HAVE_SELINUX
78: # include <selinux/selinux.h>
79: #endif
80: #include <ctype.h>
81: #include <setjmp.h>
1.1.1.2 ! misho 82: #ifndef HAVE_GETADDRINFO
! 83: # include "compat/getaddrinfo.h"
! 84: #endif
1.1 misho 85:
86: #include "sudoers.h"
87: #include "interfaces.h"
88: #include "sudoers_version.h"
89: #include "auth/sudo_auth.h"
1.1.1.2 ! misho 90: #include "secure_path.h"
1.1 misho 91:
92: /*
93: * Prototypes
94: */
95: static void init_vars(char * const *);
96: static int set_cmnd(void);
97: static void set_loginclass(struct passwd *);
98: static void set_runaspw(const char *);
99: static void set_runasgr(const char *);
100: static int cb_runas_default(const char *);
101: static int sudoers_policy_version(int verbose);
1.1.1.2 ! misho 102: static int deserialize_info(char * const args[], char * const settings[],
! 103: char * const user_info[]);
1.1 misho 104: static char *find_editor(int nfiles, char **files, char ***argv_out);
105: static void create_admin_success_flag(void);
106:
107: /*
108: * Globals
109: */
110: struct sudo_user sudo_user;
111: struct passwd *list_pw;
112: struct interface *interfaces;
113: int long_list;
114: uid_t timestamp_uid;
115: extern int errorlineno;
1.1.1.2 ! misho 116: extern bool parse_error;
1.1 misho 117: extern char *errorfile;
118: #ifdef HAVE_BSD_AUTH_H
119: char *login_style;
120: #endif /* HAVE_BSD_AUTH_H */
121: sudo_conv_t sudo_conv;
122: sudo_printf_t sudo_printf;
123: int sudo_mode;
124:
1.1.1.2 ! misho 125: static int sudo_version;
1.1 misho 126: static char *prev_user;
127: static char *runas_user;
128: static char *runas_group;
129: static struct sudo_nss_list *snl;
130: static const char *interfaces_string;
131: static sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp;
132:
133: /* XXX - must be extern for audit bits of sudo_auth.c */
134: int NewArgc;
135: char **NewArgv;
136:
1.1.1.2 ! misho 137: /* Declared here instead of plugin_error.c for static sudo builds. */
! 138: sigjmp_buf error_jmp;
1.1 misho 139:
140: static int
141: sudoers_policy_open(unsigned int version, sudo_conv_t conversation,
142: sudo_printf_t plugin_printf, char * const settings[],
1.1.1.2 ! misho 143: char * const user_info[], char * const envp[], char * const args[])
1.1 misho 144: {
145: volatile int sources = 0;
146: sigaction_t sa;
147: struct sudo_nss *nss;
1.1.1.2 ! misho 148: debug_decl(sudoers_policy_open, SUDO_DEBUG_PLUGIN)
1.1 misho 149:
1.1.1.2 ! misho 150: sudo_version = version;
1.1 misho 151: if (!sudo_conv)
152: sudo_conv = conversation;
153: if (!sudo_printf)
154: sudo_printf = plugin_printf;
155:
1.1.1.2 ! misho 156: /* Plugin args are only specified for API version 1.2 and higher. */
! 157: if (sudo_version < SUDO_API_MKVERSION(1, 2))
! 158: args = NULL;
! 159:
1.1 misho 160: if (sigsetjmp(error_jmp, 1)) {
1.1.1.2 ! misho 161: /* called via error(), errorx() or log_fatal() */
1.1 misho 162: rewind_perms();
1.1.1.2 ! misho 163: debug_return_bool(-1);
1.1 misho 164: }
165:
166: bindtextdomain("sudoers", LOCALEDIR);
167:
168: /*
169: * Signal setup:
170: * Ignore keyboard-generated signals so the user cannot interrupt
171: * us at some point and avoid the logging.
172: * Install handler to wait for children when they exit.
173: */
174: zero_bytes(&sa, sizeof(sa));
175: sigemptyset(&sa.sa_mask);
176: sa.sa_flags = SA_RESTART;
177: sa.sa_handler = SIG_IGN;
178: (void) sigaction(SIGINT, &sa, &saved_sa_int);
179: (void) sigaction(SIGQUIT, &sa, &saved_sa_quit);
180: (void) sigaction(SIGTSTP, &sa, &saved_sa_tstp);
181:
182: sudo_setpwent();
183: sudo_setgrent();
184:
185: /* Initialize environment functions (including replacements). */
186: env_init(envp);
187:
188: /* Setup defaults data structures. */
189: init_defaults();
190:
1.1.1.2 ! misho 191: /* Parse args, settings and user_info */
! 192: sudo_mode = deserialize_info(args, settings, user_info);
1.1 misho 193:
194: init_vars(envp); /* XXX - move this later? */
195:
196: /* Parse nsswitch.conf for sudoers order. */
197: snl = sudo_read_nss();
198:
199: /* LDAP or NSS may modify the euid so we need to be root for the open. */
200: set_perms(PERM_INITIAL);
201: set_perms(PERM_ROOT);
202:
203: /* Open and parse sudoers, set global defaults */
204: tq_foreach_fwd(snl, nss) {
205: if (nss->open(nss) == 0 && nss->parse(nss) == 0) {
206: sources++;
207: if (nss->setdefs(nss) != 0)
1.1.1.2 ! misho 208: log_error(NO_STDERR, _("problem with defaults entries"));
1.1 misho 209: }
210: }
211: if (sources == 0) {
212: warningx(_("no valid sudoers sources found, quitting"));
1.1.1.2 ! misho 213: debug_return_bool(-1);
1.1 misho 214: }
215:
216: /* XXX - collect post-sudoers parse settings into a function */
217:
218: /*
219: * Initialize external group plugin, if any.
220: */
221: if (def_group_plugin) {
1.1.1.2 ! misho 222: if (group_plugin_load(def_group_plugin) != true)
1.1 misho 223: def_group_plugin = NULL;
224: }
225:
226: /*
227: * Set runas passwd/group entries based on command line or sudoers.
228: * Note that if runas_group was specified without runas_user we
229: * defer setting runas_pw so the match routines know to ignore it.
230: */
231: if (runas_group != NULL) {
232: set_runasgr(runas_group);
233: if (runas_user != NULL)
234: set_runaspw(runas_user);
235: } else
236: set_runaspw(runas_user ? runas_user : def_runas_default);
237:
238: if (!update_defaults(SETDEF_RUNAS))
1.1.1.2 ! misho 239: log_error(NO_STDERR, _("problem with defaults entries"));
1.1 misho 240:
241: if (def_fqdn)
242: set_fqdn(); /* deferred until after sudoers is parsed */
243:
244: /* Set login class if applicable. */
1.1.1.2 ! misho 245: set_loginclass(runas_pw ? runas_pw : sudo_user.pw);
1.1 misho 246:
247: restore_perms();
248:
1.1.1.2 ! misho 249: debug_return_bool(true);
1.1 misho 250: }
251:
252: static void
253: sudoers_policy_close(int exit_status, int error_code)
254: {
1.1.1.2 ! misho 255: debug_decl(sudoers_policy_close, SUDO_DEBUG_PLUGIN)
! 256:
1.1 misho 257: if (sigsetjmp(error_jmp, 1)) {
1.1.1.2 ! misho 258: /* called via error(), errorx() or log_fatal() */
! 259: debug_return;
1.1 misho 260: }
261:
262: /* We do not currently log the exit status. */
263: if (error_code)
264: warningx(_("unable to execute %s: %s"), safe_cmnd, strerror(error_code));
265:
266: /* Close the session we opened in sudoers_policy_init_session(). */
267: if (ISSET(sudo_mode, MODE_RUN|MODE_EDIT))
268: (void)sudo_auth_end_session(runas_pw);
269:
270: /* Free remaining references to password and group entries. */
271: pw_delref(sudo_user.pw);
272: pw_delref(runas_pw);
273: if (runas_gr != NULL)
274: gr_delref(runas_gr);
275: if (user_group_list != NULL)
276: grlist_delref(user_group_list);
1.1.1.2 ! misho 277:
! 278: debug_return;
1.1 misho 279: }
280:
281: /*
282: * The init_session function is called before executing the command
283: * and before uid/gid changes occur.
284: */
285: static int
1.1.1.2 ! misho 286: sudoers_policy_init_session(struct passwd *pwd, char **user_env[])
1.1 misho 287: {
1.1.1.2 ! misho 288: debug_decl(sudoers_policy_init, SUDO_DEBUG_PLUGIN)
! 289:
! 290: /* user_env is only specified for API version 1.2 and higher. */
! 291: if (sudo_version < SUDO_API_MKVERSION(1, 2))
! 292: user_env = NULL;
! 293:
1.1 misho 294: if (sigsetjmp(error_jmp, 1)) {
1.1.1.2 ! misho 295: /* called via error(), errorx() or log_fatal() */
1.1 misho 296: return -1;
297: }
298:
1.1.1.2 ! misho 299: debug_return_bool(sudo_auth_begin_session(pwd, user_env));
1.1 misho 300: }
301:
302: static int
303: sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
304: char **command_infop[], char **argv_out[], char **user_env_out[])
305: {
306: static char *command_info[32]; /* XXX */
307: char **edit_argv = NULL;
308: struct sudo_nss *nss;
309: int cmnd_status = -1, validated;
310: volatile int info_len = 0;
1.1.1.2 ! misho 311: volatile int rval = true;
! 312: debug_decl(sudoers_policy_main, SUDO_DEBUG_PLUGIN)
1.1 misho 313:
314: if (sigsetjmp(error_jmp, 1)) {
1.1.1.2 ! misho 315: /* error recovery via error(), errorx() or log_fatal() */
1.1 misho 316: rval = -1;
317: goto done;
318: }
319:
320: /* Is root even allowed to run sudo? */
321: if (user_uid == 0 && !def_root_sudo) {
322: warningx(_("sudoers specifies that root is not allowed to sudo"));
323: goto bad;
324: }
325:
326: /* Check for -C overriding def_closefrom. */
327: if (user_closefrom >= 0 && user_closefrom != def_closefrom) {
328: if (!def_closefrom_override) {
329: warningx(_("you are not permitted to use the -C option"));
330: goto bad;
331: }
332: def_closefrom = user_closefrom;
333: }
334:
335: set_perms(PERM_INITIAL);
336:
337: /* Environment variables specified on the command line. */
338: if (env_add != NULL && env_add[0] != NULL)
339: sudo_user.env_vars = env_add;
340:
341: /*
342: * Make a local copy of argc/argv, with special handling
343: * for pseudo-commands and the '-i' option.
344: */
345: if (argc == 0) {
346: NewArgc = 1;
347: NewArgv = emalloc2(NewArgc + 1, sizeof(char *));
348: NewArgv[0] = user_cmnd;
349: NewArgv[1] = NULL;
350: } else {
351: /* Must leave an extra slot before NewArgv for bash's --login */
352: NewArgc = argc;
353: NewArgv = emalloc2(NewArgc + 2, sizeof(char *));
354: memcpy(++NewArgv, argv, argc * sizeof(char *));
355: NewArgv[NewArgc] = NULL;
1.1.1.2 ! misho 356: if (ISSET(sudo_mode, MODE_LOGIN_SHELL) && runas_pw != NULL)
1.1 misho 357: NewArgv[0] = estrdup(runas_pw->pw_shell);
358: }
359:
360: /* If given the -P option, set the "preserve_groups" flag. */
361: if (ISSET(sudo_mode, MODE_PRESERVE_GROUPS))
1.1.1.2 ! misho 362: def_preserve_groups = true;
1.1 misho 363:
364: /* Find command in path */
365: cmnd_status = set_cmnd();
366: if (cmnd_status == -1) {
367: rval = -1;
368: goto done;
369: }
370:
371: #ifdef HAVE_SETLOCALE
372: if (!setlocale(LC_ALL, def_sudoers_locale)) {
373: warningx(_("unable to set locale to \"%s\", using \"C\""),
374: def_sudoers_locale);
375: setlocale(LC_ALL, "C");
376: }
377: #endif
378:
379: /*
380: * Check sudoers sources.
381: */
382: validated = FLAG_NO_USER | FLAG_NO_HOST;
383: tq_foreach_fwd(snl, nss) {
384: validated = nss->lookup(nss, validated, pwflag);
385:
386: if (ISSET(validated, VALIDATE_OK)) {
387: /* Handle "= auth" in netsvc.conf */
388: if (nss->ret_if_found)
389: break;
390: } else {
391: /* Handle [NOTFOUND=return] */
392: if (nss->ret_if_notfound)
393: break;
394: }
395: }
396:
397: if (safe_cmnd == NULL)
398: safe_cmnd = estrdup(user_cmnd);
399:
400: #ifdef HAVE_SETLOCALE
401: setlocale(LC_ALL, "");
402: #endif
403:
404: /* If only a group was specified, set runas_pw based on invoking user. */
405: if (runas_pw == NULL)
406: set_runaspw(user_name);
407:
408: /*
409: * Look up the timestamp dir owner if one is specified.
410: */
411: if (def_timestampowner) {
412: struct passwd *pw;
413:
414: if (*def_timestampowner == '#')
415: pw = sudo_getpwuid(atoi(def_timestampowner + 1));
416: else
417: pw = sudo_getpwnam(def_timestampowner);
1.1.1.2 ! misho 418: if (pw != NULL) {
! 419: timestamp_uid = pw->pw_uid;
! 420: pw_delref(pw);
! 421: } else {
1.1 misho 422: log_error(0, _("timestamp owner (%s): No such user"),
423: def_timestampowner);
1.1.1.2 ! misho 424: timestamp_uid = ROOT_UID;
! 425: }
1.1 misho 426: }
427:
428: /* If no command line args and "shell_noargs" is not set, error out. */
429: if (ISSET(sudo_mode, MODE_IMPLIED_SHELL) && !def_shell_noargs) {
430: rval = -2; /* usage error */
431: goto done;
432: }
433:
434: /* Bail if a tty is required and we don't have one. */
435: if (def_requiretty) {
436: int fd = open(_PATH_TTY, O_RDWR|O_NOCTTY);
437: if (fd == -1) {
438: audit_failure(NewArgv, _("no tty"));
439: warningx(_("sorry, you must have a tty to run sudo"));
440: goto bad;
441: } else
442: (void) close(fd);
443: }
444:
445: /*
446: * We don't reset the environment for sudoedit or if the user
447: * specified the -E command line flag and they have setenv privs.
448: */
449: if (ISSET(sudo_mode, MODE_EDIT) ||
450: (ISSET(sudo_mode, MODE_PRESERVE_ENV) && def_setenv))
1.1.1.2 ! misho 451: def_env_reset = false;
1.1 misho 452:
453: /* Build a new environment that avoids any nasty bits. */
454: rebuild_env();
455:
456: /* Require a password if sudoers says so. */
457: rval = check_user(validated, sudo_mode);
1.1.1.2 ! misho 458: if (rval != true)
1.1 misho 459: goto done;
460:
461: /* If run as root with SUDO_USER set, set sudo_user.pw to that user. */
462: /* XXX - causes confusion when root is not listed in sudoers */
463: if (sudo_mode & (MODE_RUN | MODE_EDIT) && prev_user != NULL) {
464: if (user_uid == 0 && strcmp(prev_user, "root") != 0) {
465: struct passwd *pw;
466:
467: if ((pw = sudo_getpwnam(prev_user)) != NULL) {
468: if (sudo_user.pw != NULL)
469: pw_delref(sudo_user.pw);
470: sudo_user.pw = pw;
471: }
472: }
473: }
474:
475: /* If the user was not allowed to run the command we are done. */
476: if (!ISSET(validated, VALIDATE_OK)) {
477: if (ISSET(validated, FLAG_NO_USER | FLAG_NO_HOST)) {
478: audit_failure(NewArgv, _("No user or host"));
479: log_denial(validated, 1);
480: } else {
481: if (def_path_info) {
482: /*
483: * We'd like to not leak path info at all here, but that can
484: * *really* confuse the users. To really close the leak we'd
485: * have to say "not allowed to run foo" even when the problem
486: * is just "no foo in path" since the user can trivially set
487: * their path to just contain a single dir.
488: */
489: log_denial(validated,
490: !(cmnd_status == NOT_FOUND_DOT || cmnd_status == NOT_FOUND));
491: if (cmnd_status == NOT_FOUND)
492: warningx(_("%s: command not found"), user_cmnd);
493: else if (cmnd_status == NOT_FOUND_DOT)
494: warningx(_("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run."), user_cmnd, user_cmnd, user_cmnd);
495: } else {
496: /* Just tell the user they are not allowed to run foo. */
497: log_denial(validated, 1);
498: }
499: audit_failure(NewArgv, _("validation failure"));
500: }
501: goto bad;
502: }
503:
504: /* Create Ubuntu-style dot file to indicate sudo was successful. */
505: create_admin_success_flag();
506:
507: /* Finally tell the user if the command did not exist. */
508: if (cmnd_status == NOT_FOUND_DOT) {
509: audit_failure(NewArgv, _("command in current directory"));
510: warningx(_("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run."), user_cmnd, user_cmnd, user_cmnd);
511: goto bad;
512: } else if (cmnd_status == NOT_FOUND) {
513: audit_failure(NewArgv, _("%s: command not found"), user_cmnd);
514: warningx(_("%s: command not found"), user_cmnd);
515: goto bad;
516: }
517:
518: /* If user specified env vars make sure sudoers allows it. */
519: if (ISSET(sudo_mode, MODE_RUN) && !def_setenv) {
520: if (ISSET(sudo_mode, MODE_PRESERVE_ENV)) {
521: warningx(_("sorry, you are not allowed to preserve the environment"));
522: goto bad;
523: } else
524: validate_env_vars(sudo_user.env_vars);
525: }
526:
527: if (ISSET(sudo_mode, (MODE_RUN | MODE_EDIT)) && (def_log_input || def_log_output)) {
528: if (def_iolog_file && def_iolog_dir) {
529: command_info[info_len++] = expand_iolog_path("iolog_path=",
530: def_iolog_dir, def_iolog_file, &sudo_user.iolog_file);
531: sudo_user.iolog_file++;
532: }
533: if (def_log_input) {
534: command_info[info_len++] = estrdup("iolog_stdin=true");
535: command_info[info_len++] = estrdup("iolog_ttyin=true");
536: }
537: if (def_log_output) {
538: command_info[info_len++] = estrdup("iolog_stdout=true");
539: command_info[info_len++] = estrdup("iolog_stderr=true");
540: command_info[info_len++] = estrdup("iolog_ttyout=true");
541: }
542: if (def_compress_io)
543: command_info[info_len++] = estrdup("iolog_compress=true");
544: }
545:
546: log_allowed(validated);
547: if (ISSET(sudo_mode, MODE_CHECK))
548: rval = display_cmnd(snl, list_pw ? list_pw : sudo_user.pw);
549: else if (ISSET(sudo_mode, MODE_LIST))
550: display_privs(snl, list_pw ? list_pw : sudo_user.pw); /* XXX - return val */
551:
552: /* Cleanup sudoers sources */
553: tq_foreach_fwd(snl, nss) {
554: nss->close(nss);
555: }
556: if (def_group_plugin)
557: group_plugin_unload();
558:
559: if (ISSET(sudo_mode, (MODE_VALIDATE|MODE_CHECK|MODE_LIST))) {
560: /* rval already set appropriately */
561: goto done;
562: }
563:
564: /*
565: * Set umask based on sudoers.
566: * If user's umask is more restrictive, OR in those bits too
567: * unless umask_override is set.
568: */
569: if (def_umask != 0777) {
570: mode_t mask = def_umask;
571: if (!def_umask_override) {
572: mode_t omask = umask(mask);
573: mask |= omask;
574: umask(omask);
575: }
576: easprintf(&command_info[info_len++], "umask=0%o", (unsigned int)mask);
577: }
578:
579: if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
580: char *p;
581:
582: /* Convert /bin/sh -> -sh so shell knows it is a login shell */
583: if ((p = strrchr(NewArgv[0], '/')) == NULL)
584: p = NewArgv[0];
585: *p = '-';
586: NewArgv[0] = p;
587:
588: /* Set cwd to run user's homedir. */
589: command_info[info_len++] = fmt_string("cwd", runas_pw->pw_dir);
590:
591: /*
592: * Newer versions of bash require the --login option to be used
593: * in conjunction with the -c option even if the shell name starts
594: * with a '-'. Unfortunately, bash 1.x uses -login, not --login
595: * so this will cause an error for that.
596: */
597: if (NewArgc > 1 && strcmp(NewArgv[0], "-bash") == 0 &&
598: strcmp(NewArgv[1], "-c") == 0) {
599: /* Use the extra slot before NewArgv so we can store --login. */
600: NewArgv--;
601: NewArgc++;
602: NewArgv[0] = NewArgv[1];
603: NewArgv[1] = "--login";
604: }
605:
1.1.1.2 ! misho 606: #if defined(_AIX) || (defined(__linux__) && !defined(HAVE_PAM))
1.1 misho 607: /* Insert system-wide environment variables. */
1.1.1.2 ! misho 608: read_env_file(_PATH_ENVIRONMENT, true);
1.1 misho 609: #endif
1.1.1.2 ! misho 610: #ifdef HAVE_LOGIN_CAP_H
! 611: /* Set environment based on login class. */
! 612: if (login_class) {
! 613: login_cap_t *lc = login_getclass(login_class);
! 614: if (lc != NULL) {
! 615: setusercontext(lc, runas_pw, runas_pw->pw_uid, LOGIN_SETPATH|LOGIN_SETENV);
! 616: login_close(lc);
! 617: }
! 618: }
! 619: #endif /* HAVE_LOGIN_CAP_H */
1.1 misho 620: }
621:
622: /* Insert system-wide environment variables. */
623: if (def_env_file)
1.1.1.2 ! misho 624: read_env_file(def_env_file, false);
1.1 misho 625:
626: /* Insert user-specified environment variables. */
627: insert_env_vars(sudo_user.env_vars);
628:
629: /* Restore signal handlers before we exec. */
630: (void) sigaction(SIGINT, &saved_sa_int, NULL);
631: (void) sigaction(SIGQUIT, &saved_sa_quit, NULL);
632: (void) sigaction(SIGTSTP, &saved_sa_tstp, NULL);
633:
634: if (ISSET(sudo_mode, MODE_EDIT)) {
635: char *editor = find_editor(NewArgc - 1, NewArgv + 1, &edit_argv);
636: if (editor == NULL)
637: goto bad;
638: command_info[info_len++] = fmt_string("command", editor);
639: command_info[info_len++] = estrdup("sudoedit=true");
640: } else {
641: command_info[info_len++] = fmt_string("command", safe_cmnd);
642: }
643: if (def_stay_setuid) {
644: easprintf(&command_info[info_len++], "runas_uid=%u",
645: (unsigned int)user_uid);
646: easprintf(&command_info[info_len++], "runas_gid=%u",
647: (unsigned int)user_gid);
648: easprintf(&command_info[info_len++], "runas_euid=%u",
649: (unsigned int)runas_pw->pw_uid);
650: easprintf(&command_info[info_len++], "runas_egid=%u",
651: runas_gr ? (unsigned int)runas_gr->gr_gid :
652: (unsigned int)runas_pw->pw_gid);
653: } else {
654: easprintf(&command_info[info_len++], "runas_uid=%u",
655: (unsigned int)runas_pw->pw_uid);
656: easprintf(&command_info[info_len++], "runas_gid=%u",
657: runas_gr ? (unsigned int)runas_gr->gr_gid :
658: (unsigned int)runas_pw->pw_gid);
659: }
660: if (def_preserve_groups) {
661: command_info[info_len++] = "preserve_groups=true";
662: } else {
663: int i, len;
1.1.1.2 ! misho 664: gid_t egid;
1.1 misho 665: size_t glsize;
666: char *cp, *gid_list;
667: struct group_list *grlist = get_group_list(runas_pw);
668:
1.1.1.2 ! misho 669: /* We reserve an extra spot in the list for the effective gid. */
! 670: glsize = sizeof("runas_groups=") - 1 +
! 671: ((grlist->ngids + 1) * (MAX_UID_T_LEN + 1));
1.1 misho 672: gid_list = emalloc(glsize);
673: memcpy(gid_list, "runas_groups=", sizeof("runas_groups=") - 1);
674: cp = gid_list + sizeof("runas_groups=") - 1;
1.1.1.2 ! misho 675:
! 676: /* On BSD systems the effective gid is the first group in the list. */
! 677: egid = runas_gr ? (unsigned int)runas_gr->gr_gid :
! 678: (unsigned int)runas_pw->pw_gid;
! 679: len = snprintf(cp, glsize - (cp - gid_list), "%u", egid);
! 680: if (len < 0 || len >= glsize - (cp - gid_list))
! 681: errorx(1, _("internal error, runas_groups overflow"));
! 682: cp += len;
1.1 misho 683: for (i = 0; i < grlist->ngids; i++) {
1.1.1.2 ! misho 684: if (grlist->gids[i] != egid) {
! 685: len = snprintf(cp, glsize - (cp - gid_list), ",%u",
! 686: (unsigned int) grlist->gids[i]);
! 687: if (len < 0 || len >= glsize - (cp - gid_list))
! 688: errorx(1, _("internal error, runas_groups overflow"));
! 689: cp += len;
! 690: }
1.1 misho 691: }
692: command_info[info_len++] = gid_list;
693: grlist_delref(grlist);
694: }
695: if (def_closefrom >= 0)
696: easprintf(&command_info[info_len++], "closefrom=%d", def_closefrom);
697: if (def_noexec)
698: command_info[info_len++] = estrdup("noexec=true");
699: if (def_set_utmp)
700: command_info[info_len++] = estrdup("set_utmp=true");
701: if (def_use_pty)
702: command_info[info_len++] = estrdup("use_pty=true");
703: if (def_utmp_runas)
704: command_info[info_len++] = fmt_string("utmp_user", runas_pw->pw_name);
705: #ifdef HAVE_LOGIN_CAP_H
1.1.1.2 ! misho 706: if (def_use_loginclass)
! 707: command_info[info_len++] = fmt_string("login_class", login_class);
1.1 misho 708: #endif /* HAVE_LOGIN_CAP_H */
709: #ifdef HAVE_SELINUX
710: if (user_role != NULL)
711: command_info[info_len++] = fmt_string("selinux_role", user_role);
712: if (user_type != NULL)
713: command_info[info_len++] = fmt_string("selinux_type", user_type);
714: #endif /* HAVE_SELINUX */
715:
716: /* Must audit before uid change. */
717: audit_success(NewArgv);
718:
719: *command_infop = command_info;
720:
721: *argv_out = edit_argv ? edit_argv : NewArgv;
1.1.1.2 ! misho 722:
! 723: /* Get private version of the environment and zero out stashed copy. */
! 724: *user_env_out = env_get();
! 725: env_init(NULL);
1.1 misho 726:
727: goto done;
728:
729: bad:
1.1.1.2 ! misho 730: rval = false;
1.1 misho 731:
732: done:
733: rewind_perms();
734:
735: /* Close the password and group files and free up memory. */
736: sudo_endpwent();
737: sudo_endgrent();
738:
1.1.1.2 ! misho 739: debug_return_bool(rval);
1.1 misho 740: }
741:
742: static int
743: sudoers_policy_check(int argc, char * const argv[], char *env_add[],
744: char **command_infop[], char **argv_out[], char **user_env_out[])
745: {
1.1.1.2 ! misho 746: debug_decl(sudoers_policy_check, SUDO_DEBUG_PLUGIN)
! 747:
1.1 misho 748: if (!ISSET(sudo_mode, MODE_EDIT))
749: SET(sudo_mode, MODE_RUN);
750:
1.1.1.2 ! misho 751: debug_return_bool(sudoers_policy_main(argc, argv, 0, env_add, command_infop,
! 752: argv_out, user_env_out));
1.1 misho 753: }
754:
755: static int
756: sudoers_policy_validate(void)
757: {
1.1.1.2 ! misho 758: debug_decl(sudoers_policy_validate, SUDO_DEBUG_PLUGIN)
! 759:
1.1 misho 760: user_cmnd = "validate";
761: SET(sudo_mode, MODE_VALIDATE);
762:
1.1.1.2 ! misho 763: debug_return_bool(sudoers_policy_main(0, NULL, I_VERIFYPW, NULL, NULL, NULL, NULL));
1.1 misho 764: }
765:
766: static void
767: sudoers_policy_invalidate(int remove)
768: {
1.1.1.2 ! misho 769: debug_decl(sudoers_policy_invalidate, SUDO_DEBUG_PLUGIN)
! 770:
1.1 misho 771: user_cmnd = "kill";
772: if (sigsetjmp(error_jmp, 1) == 0) {
773: remove_timestamp(remove);
774: plugin_cleanup(0);
775: }
1.1.1.2 ! misho 776:
! 777: debug_return;
1.1 misho 778: }
779:
780: static int
781: sudoers_policy_list(int argc, char * const argv[], int verbose,
782: const char *list_user)
783: {
784: int rval;
1.1.1.2 ! misho 785: debug_decl(sudoers_policy_list, SUDO_DEBUG_PLUGIN)
1.1 misho 786:
787: user_cmnd = "list";
788: if (argc)
789: SET(sudo_mode, MODE_CHECK);
790: else
791: SET(sudo_mode, MODE_LIST);
792: if (verbose)
793: long_list = 1;
794: if (list_user) {
795: list_pw = sudo_getpwnam(list_user);
796: if (list_pw == NULL) {
797: warningx(_("unknown user: %s"), list_user);
1.1.1.2 ! misho 798: debug_return_bool(-1);
1.1 misho 799: }
800: }
801: rval = sudoers_policy_main(argc, argv, I_LISTPW, NULL, NULL, NULL, NULL);
802: if (list_user) {
803: pw_delref(list_pw);
804: list_pw = NULL;
805: }
806:
1.1.1.2 ! misho 807: debug_return_bool(rval);
1.1 misho 808: }
809:
810: /*
811: * Initialize timezone, set umask, fill in ``sudo_user'' struct and
812: * load the ``interfaces'' array.
813: */
814: static void
815: init_vars(char * const envp[])
816: {
817: char * const * ep;
1.1.1.2 ! misho 818: debug_decl(init_vars, SUDO_DEBUG_PLUGIN)
1.1 misho 819:
820: #ifdef HAVE_TZSET
821: (void) tzset(); /* set the timezone if applicable */
822: #endif /* HAVE_TZSET */
823:
824: for (ep = envp; *ep; ep++) {
825: /* XXX - don't fill in if empty string */
826: switch (**ep) {
827: case 'K':
828: if (strncmp("KRB5CCNAME=", *ep, 11) == 0)
829: user_ccname = *ep + 11;
830: break;
831: case 'P':
832: if (strncmp("PATH=", *ep, 5) == 0)
833: user_path = *ep + 5;
834: break;
835: case 'S':
836: if (!user_prompt && strncmp("SUDO_PROMPT=", *ep, 12) == 0)
837: user_prompt = *ep + 12;
838: else if (strncmp("SUDO_USER=", *ep, 10) == 0)
839: prev_user = *ep + 10;
840: break;
841: }
842: }
843:
844: /*
845: * Get a local copy of the user's struct passwd with the shadow password
846: * if necessary. It is assumed that euid is 0 at this point so we
847: * can read the shadow passwd file if necessary.
848: */
849: if ((sudo_user.pw = sudo_getpwuid(user_uid)) == NULL) {
850: /*
851: * It is not unusual for users to place "sudo -k" in a .logout
852: * file which can cause sudo to be run during reboot after the
853: * YP/NIS/NIS+/LDAP/etc daemon has died.
854: */
855: if (sudo_mode == MODE_KILL || sudo_mode == MODE_INVALIDATE)
856: errorx(1, _("unknown uid: %u"), (unsigned int) user_uid);
857:
1.1.1.2 ! misho 858: /* Need to make a fake struct passwd for the call to log_fatal(). */
1.1 misho 859: sudo_user.pw = sudo_fakepwnamid(user_name, user_uid, user_gid);
1.1.1.2 ! misho 860: log_fatal(0, _("unknown uid: %u"), (unsigned int) user_uid);
1.1 misho 861: /* NOTREACHED */
862: }
863:
864: /*
865: * Get group list.
866: */
867: if (user_group_list == NULL)
868: user_group_list = get_group_list(sudo_user.pw);
869:
870: /* Set runas callback. */
871: sudo_defs_table[I_RUNAS_DEFAULT].callback = cb_runas_default;
872:
1.1.1.2 ! misho 873: /* It is now safe to use log_fatal() and set_perms() */
! 874: debug_return;
1.1 misho 875: }
876:
877: /*
878: * Fill in user_cmnd, user_args, user_base and user_stat variables
879: * and apply any command-specific defaults entries.
880: */
881: static int
882: set_cmnd(void)
883: {
884: int rval;
885: char *path = user_path;
1.1.1.2 ! misho 886: debug_decl(set_cmnd, SUDO_DEBUG_PLUGIN)
1.1 misho 887:
888: /* Resolve the path and return. */
889: rval = FOUND;
1.1.1.2 ! misho 890: user_stat = ecalloc(1, sizeof(struct stat));
1.1 misho 891:
892: /* Default value for cmnd, overridden below. */
893: if (user_cmnd == NULL)
894: user_cmnd = NewArgv[0];
895:
896: if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) {
897: if (ISSET(sudo_mode, MODE_RUN | MODE_CHECK)) {
898: if (def_secure_path && !user_is_exempt())
899: path = def_secure_path;
900: set_perms(PERM_RUNAS);
901: rval = find_path(NewArgv[0], &user_cmnd, user_stat, path,
902: def_ignore_dot);
903: restore_perms();
904: if (rval != FOUND) {
905: /* Failed as root, try as invoking user. */
906: set_perms(PERM_USER);
907: rval = find_path(NewArgv[0], &user_cmnd, user_stat, path,
908: def_ignore_dot);
909: restore_perms();
910: }
911: }
912:
913: /* set user_args */
914: if (NewArgc > 1) {
915: char *to, *from, **av;
916: size_t size, n;
917:
918: /* Alloc and build up user_args. */
919: for (size = 0, av = NewArgv + 1; *av; av++)
920: size += strlen(*av) + 1;
921: user_args = emalloc(size);
922: if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) {
923: /*
924: * When running a command via a shell, the sudo front-end
925: * escapes potential meta chars. We unescape non-spaces
926: * for sudoers matching and logging purposes.
927: */
928: for (to = user_args, av = NewArgv + 1; (from = *av); av++) {
929: while (*from) {
930: if (from[0] == '\\' && !isspace((unsigned char)from[1]))
931: from++;
932: *to++ = *from++;
933: }
934: *to++ = ' ';
935: }
936: *--to = '\0';
937: } else {
938: for (to = user_args, av = NewArgv + 1; *av; av++) {
939: n = strlcpy(to, *av, size - (to - user_args));
940: if (n >= size - (to - user_args))
941: errorx(1, _("internal error, set_cmnd() overflow"));
942: to += n;
943: *to++ = ' ';
944: }
945: *--to = '\0';
946: }
947: }
948: }
949: if (strlen(user_cmnd) >= PATH_MAX)
950: errorx(1, _("%s: %s"), user_cmnd, strerror(ENAMETOOLONG));
951:
952: if ((user_base = strrchr(user_cmnd, '/')) != NULL)
953: user_base++;
954: else
955: user_base = user_cmnd;
956:
957: if (!update_defaults(SETDEF_CMND))
1.1.1.2 ! misho 958: log_error(NO_STDERR, _("problem with defaults entries"));
1.1 misho 959:
1.1.1.2 ! misho 960: debug_return_int(rval);
1.1 misho 961: }
962:
963: /*
964: * Open sudoers and sanity check mode/owner/type.
965: * Returns a handle to the sudoers file or NULL on error.
966: */
967: FILE *
1.1.1.2 ! misho 968: open_sudoers(const char *sudoers, bool doedit, bool *keepopen)
1.1 misho 969: {
1.1.1.2 ! misho 970: struct stat sb;
1.1 misho 971: FILE *fp = NULL;
1.1.1.2 ! misho 972: debug_decl(open_sudoers, SUDO_DEBUG_PLUGIN)
1.1 misho 973:
974: set_perms(PERM_SUDOERS);
975:
1.1.1.2 ! misho 976: switch (sudo_secure_file(sudoers, sudoers_uid, sudoers_gid, &sb)) {
! 977: case SUDO_PATH_SECURE:
! 978: if ((fp = fopen(sudoers, "r")) == NULL) {
! 979: log_error(USE_ERRNO, _("unable to open %s"), sudoers);
! 980: } else {
! 981: /*
! 982: * Make sure we can actually read sudoers so we can present the
! 983: * user with a reasonable error message (unlike the lexer).
! 984: */
! 985: if (sb.st_size != 0 && fgetc(fp) == EOF) {
! 986: log_error(USE_ERRNO, _("unable to read %s"),
! 987: sudoers);
! 988: fclose(fp);
! 989: fp = NULL;
! 990: } else {
! 991: /* Rewind fp and set close on exec flag. */
! 992: rewind(fp);
! 993: (void) fcntl(fileno(fp), F_SETFD, 1);
! 994: }
! 995: }
! 996: break;
! 997: case SUDO_PATH_MISSING:
! 998: log_error(USE_ERRNO, _("unable to stat %s"), sudoers);
! 999: break;
! 1000: case SUDO_PATH_BAD_TYPE:
! 1001: log_error(0, _("%s is not a regular file"), sudoers);
! 1002: break;
! 1003: case SUDO_PATH_WRONG_OWNER:
! 1004: log_error(0, _("%s is owned by uid %u, should be %u"),
! 1005: sudoers, (unsigned int) sb.st_uid, (unsigned int) sudoers_uid);
! 1006: break;
! 1007: case SUDO_PATH_WORLD_WRITABLE:
! 1008: log_error(0, _("%s is world writable"), sudoers);
! 1009: break;
! 1010: case SUDO_PATH_GROUP_WRITABLE:
! 1011: log_error(0, _("%s is owned by gid %u, should be %u"),
! 1012: sudoers, (unsigned int) sb.st_gid, (unsigned int) sudoers_gid);
! 1013: break;
! 1014: default:
! 1015: /* NOTREACHED */
! 1016: break;
1.1 misho 1017: }
1018:
1019: restore_perms(); /* change back to root */
1.1.1.2 ! misho 1020:
! 1021: debug_return_ptr(fp);
1.1 misho 1022: }
1023:
1024: #ifdef HAVE_LOGIN_CAP_H
1025: static void
1026: set_loginclass(struct passwd *pw)
1027: {
1.1.1.2 ! misho 1028: const int errflags = NO_MAIL|MSG_ONLY;
! 1029: login_cap_t *lc;
! 1030: debug_decl(set_loginclass, SUDO_DEBUG_PLUGIN)
1.1 misho 1031:
1.1.1.2 ! misho 1032: if (!def_use_loginclass)
! 1033: debug_return;
1.1 misho 1034:
1035: if (login_class && strcmp(login_class, "-") != 0) {
1036: if (user_uid != 0 &&
1037: strcmp(runas_user ? runas_user : def_runas_default, "root") != 0)
1038: errorx(1, _("only root can use `-c %s'"), login_class);
1039: } else {
1040: login_class = pw->pw_class;
1041: if (!login_class || !*login_class)
1042: login_class =
1043: (pw->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS;
1044: }
1045:
1.1.1.2 ! misho 1046: /* Make sure specified login class is valid. */
1.1 misho 1047: lc = login_getclass(login_class);
1048: if (!lc || !lc->lc_class || strcmp(lc->lc_class, login_class) != 0) {
1.1.1.2 ! misho 1049: /*
! 1050: * Don't make it a fatal error if the user didn't specify the login
! 1051: * class themselves. We do this because if login.conf gets
! 1052: * corrupted we want the admin to be able to use sudo to fix it.
! 1053: */
! 1054: if (login_class)
! 1055: log_fatal(errflags, _("unknown login class: %s"), login_class);
! 1056: else
! 1057: log_error(errflags, _("unknown login class: %s"), login_class);
! 1058: def_use_loginclass = false;
1.1 misho 1059: }
1.1.1.2 ! misho 1060: login_close(lc);
! 1061: debug_return;
1.1 misho 1062: }
1063: #else
1064: static void
1065: set_loginclass(struct passwd *pw)
1066: {
1067: }
1068: #endif /* HAVE_LOGIN_CAP_H */
1069:
1070: /*
1071: * Look up the fully qualified domain name and set user_host and user_shost.
1072: */
1073: void
1074: set_fqdn(void)
1075: {
1076: struct addrinfo *res0, hint;
1077: char *p;
1.1.1.2 ! misho 1078: debug_decl(set_fqdn, SUDO_DEBUG_PLUGIN)
1.1 misho 1079:
1080: zero_bytes(&hint, sizeof(hint));
1081: hint.ai_family = PF_UNSPEC;
1082: hint.ai_flags = AI_CANONNAME;
1083: if (getaddrinfo(user_host, NULL, &hint, &res0) != 0) {
1.1.1.2 ! misho 1084: log_error(MSG_ONLY, _("unable to resolve host %s"), user_host);
1.1 misho 1085: } else {
1086: if (user_shost != user_host)
1087: efree(user_shost);
1088: efree(user_host);
1089: user_host = estrdup(res0->ai_canonname);
1090: freeaddrinfo(res0);
1091: }
1092: if ((p = strchr(user_host, '.')) != NULL)
1093: user_shost = estrndup(user_host, (size_t)(p - user_host));
1094: else
1095: user_shost = user_host;
1.1.1.2 ! misho 1096: debug_return;
1.1 misho 1097: }
1098:
1099: /*
1100: * Get passwd entry for the user we are going to run commands as
1101: * and store it in runas_pw. By default, commands run as "root".
1102: */
1.1.1.2 ! misho 1103: static void
1.1 misho 1104: set_runaspw(const char *user)
1105: {
1.1.1.2 ! misho 1106: debug_decl(set_runaspw, SUDO_DEBUG_PLUGIN)
! 1107:
1.1 misho 1108: if (runas_pw != NULL)
1109: pw_delref(runas_pw);
1110: if (*user == '#') {
1111: if ((runas_pw = sudo_getpwuid(atoi(user + 1))) == NULL)
1112: runas_pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0);
1113: } else {
1114: if ((runas_pw = sudo_getpwnam(user)) == NULL)
1.1.1.2 ! misho 1115: log_fatal(NO_MAIL|MSG_ONLY, _("unknown user: %s"), user);
1.1 misho 1116: }
1.1.1.2 ! misho 1117: debug_return;
1.1 misho 1118: }
1119:
1120: /*
1121: * Get group entry for the group we are going to run commands as
1122: * and store it in runas_gr.
1123: */
1124: static void
1125: set_runasgr(const char *group)
1126: {
1.1.1.2 ! misho 1127: debug_decl(set_runasgr, SUDO_DEBUG_PLUGIN)
! 1128:
1.1 misho 1129: if (runas_gr != NULL)
1130: gr_delref(runas_gr);
1131: if (*group == '#') {
1132: if ((runas_gr = sudo_getgrgid(atoi(group + 1))) == NULL)
1133: runas_gr = sudo_fakegrnam(group);
1134: } else {
1135: if ((runas_gr = sudo_getgrnam(group)) == NULL)
1.1.1.2 ! misho 1136: log_fatal(NO_MAIL|MSG_ONLY, _("unknown group: %s"), group);
1.1 misho 1137: }
1.1.1.2 ! misho 1138: debug_return;
1.1 misho 1139: }
1140:
1141: /*
1142: * Callback for runas_default sudoers setting.
1143: */
1144: static int
1145: cb_runas_default(const char *user)
1146: {
1147: /* Only reset runaspw if user didn't specify one. */
1148: if (!runas_user && !runas_group)
1149: set_runaspw(user);
1.1.1.2 ! misho 1150: return true;
1.1 misho 1151: }
1152:
1153: /*
1154: * Cleanup hook for error()/errorx()
1155: */
1156: void
1157: plugin_cleanup(int gotsignal)
1158: {
1159: struct sudo_nss *nss;
1160:
1161: if (!gotsignal) {
1.1.1.2 ! misho 1162: debug_decl(plugin_cleanup, SUDO_DEBUG_PLUGIN)
1.1 misho 1163: if (snl != NULL) {
1164: tq_foreach_fwd(snl, nss)
1165: nss->close(nss);
1166: }
1167: if (def_group_plugin)
1168: group_plugin_unload();
1169: sudo_endpwent();
1170: sudo_endgrent();
1.1.1.2 ! misho 1171: debug_return;
1.1 misho 1172: }
1173: }
1174:
1175: static int
1176: sudoers_policy_version(int verbose)
1177: {
1.1.1.2 ! misho 1178: debug_decl(sudoers_policy_version, SUDO_DEBUG_PLUGIN)
! 1179:
1.1 misho 1180: if (sigsetjmp(error_jmp, 1)) {
1.1.1.2 ! misho 1181: /* error recovery via error(), errorx() or log_fatal() */
! 1182: debug_return_bool(-1);
1.1 misho 1183: }
1184:
1185: sudo_printf(SUDO_CONV_INFO_MSG, _("Sudoers policy plugin version %s\n"),
1186: PACKAGE_VERSION);
1187: sudo_printf(SUDO_CONV_INFO_MSG, _("Sudoers file grammar version %d\n"),
1188: SUDOERS_GRAMMAR_VERSION);
1189:
1190: if (verbose) {
1191: sudo_printf(SUDO_CONV_INFO_MSG, _("\nSudoers path: %s\n"), sudoers_file);
1192: #ifdef HAVE_LDAP
1193: # ifdef _PATH_NSSWITCH_CONF
1194: sudo_printf(SUDO_CONV_INFO_MSG, _("nsswitch path: %s\n"), _PATH_NSSWITCH_CONF);
1195: # endif
1196: sudo_printf(SUDO_CONV_INFO_MSG, _("ldap.conf path: %s\n"), _PATH_LDAP_CONF);
1197: sudo_printf(SUDO_CONV_INFO_MSG, _("ldap.secret path: %s\n"), _PATH_LDAP_SECRET);
1198: #endif
1199: dump_auth_methods();
1200: dump_defaults();
1201: sudo_printf(SUDO_CONV_INFO_MSG, "\n");
1.1.1.2 ! misho 1202: if (interfaces_string != NULL) {
! 1203: dump_interfaces(interfaces_string);
! 1204: sudo_printf(SUDO_CONV_INFO_MSG, "\n");
! 1205: }
1.1 misho 1206: }
1.1.1.2 ! misho 1207: debug_return_bool(true);
1.1 misho 1208: }
1209:
1210: static int
1.1.1.2 ! misho 1211: deserialize_info(char * const args[], char * const settings[], char * const user_info[])
1.1 misho 1212: {
1213: char * const *cur;
1214: const char *p, *groups = NULL;
1.1.1.2 ! misho 1215: const char *debug_flags = NULL;
1.1 misho 1216: int flags = 0;
1.1.1.2 ! misho 1217: debug_decl(deserialize_info, SUDO_DEBUG_PLUGIN)
1.1 misho 1218:
1219: #define MATCHES(s, v) (strncmp(s, v, sizeof(v) - 1) == 0)
1220:
1.1.1.2 ! misho 1221: /* Parse sudo.conf plugin args. */
! 1222: if (args != NULL) {
! 1223: for (cur = args; *cur != NULL; cur++) {
! 1224: if (MATCHES(*cur, "sudoers_file=")) {
! 1225: sudoers_file = *cur + sizeof("sudoers_file=") - 1;
! 1226: continue;
! 1227: }
! 1228: if (MATCHES(*cur, "sudoers_uid=")) {
! 1229: sudoers_uid = (uid_t) atoi(*cur + sizeof("sudoers_uid=") - 1);
! 1230: continue;
! 1231: }
! 1232: if (MATCHES(*cur, "sudoers_gid=")) {
! 1233: sudoers_gid = (gid_t) atoi(*cur + sizeof("sudoers_gid=") - 1);
! 1234: continue;
! 1235: }
! 1236: if (MATCHES(*cur, "sudoers_mode=")) {
! 1237: sudoers_mode = (mode_t) strtol(*cur + sizeof("sudoers_mode=") - 1,
! 1238: NULL, 8);
! 1239: continue;
! 1240: }
! 1241: }
! 1242: }
! 1243:
1.1 misho 1244: /* Parse command line settings. */
1245: user_closefrom = -1;
1246: for (cur = settings; *cur != NULL; cur++) {
1247: if (MATCHES(*cur, "closefrom=")) {
1248: user_closefrom = atoi(*cur + sizeof("closefrom=") - 1);
1249: continue;
1250: }
1.1.1.2 ! misho 1251: if (MATCHES(*cur, "debug_flags=")) {
! 1252: debug_flags = *cur + sizeof("debug_flags=") - 1;
1.1 misho 1253: continue;
1254: }
1255: if (MATCHES(*cur, "runas_user=")) {
1256: runas_user = *cur + sizeof("runas_user=") - 1;
1257: continue;
1258: }
1259: if (MATCHES(*cur, "runas_group=")) {
1260: runas_group = *cur + sizeof("runas_group=") - 1;
1261: continue;
1262: }
1263: if (MATCHES(*cur, "prompt=")) {
1264: user_prompt = *cur + sizeof("prompt=") - 1;
1.1.1.2 ! misho 1265: def_passprompt_override = true;
1.1 misho 1266: continue;
1267: }
1268: if (MATCHES(*cur, "set_home=")) {
1.1.1.2 ! misho 1269: if (atobool(*cur + sizeof("set_home=") - 1) == true)
1.1 misho 1270: SET(flags, MODE_RESET_HOME);
1271: continue;
1272: }
1273: if (MATCHES(*cur, "preserve_environment=")) {
1.1.1.2 ! misho 1274: if (atobool(*cur + sizeof("preserve_environment=") - 1) == true)
1.1 misho 1275: SET(flags, MODE_PRESERVE_ENV);
1276: continue;
1277: }
1278: if (MATCHES(*cur, "run_shell=")) {
1.1.1.2 ! misho 1279: if (atobool(*cur + sizeof("run_shell=") - 1) == true)
1.1 misho 1280: SET(flags, MODE_SHELL);
1281: continue;
1282: }
1283: if (MATCHES(*cur, "login_shell=")) {
1.1.1.2 ! misho 1284: if (atobool(*cur + sizeof("login_shell=") - 1) == true) {
1.1 misho 1285: SET(flags, MODE_LOGIN_SHELL);
1.1.1.2 ! misho 1286: def_env_reset = true;
1.1 misho 1287: }
1288: continue;
1289: }
1290: if (MATCHES(*cur, "implied_shell=")) {
1.1.1.2 ! misho 1291: if (atobool(*cur + sizeof("implied_shell=") - 1) == true)
1.1 misho 1292: SET(flags, MODE_IMPLIED_SHELL);
1293: continue;
1294: }
1295: if (MATCHES(*cur, "preserve_groups=")) {
1.1.1.2 ! misho 1296: if (atobool(*cur + sizeof("preserve_groups=") - 1) == true)
1.1 misho 1297: SET(flags, MODE_PRESERVE_GROUPS);
1298: continue;
1299: }
1300: if (MATCHES(*cur, "ignore_ticket=")) {
1.1.1.2 ! misho 1301: if (atobool(*cur + sizeof("ignore_ticket=") - 1) == true)
1.1 misho 1302: SET(flags, MODE_IGNORE_TICKET);
1303: continue;
1304: }
1305: if (MATCHES(*cur, "noninteractive=")) {
1.1.1.2 ! misho 1306: if (atobool(*cur + sizeof("noninteractive=") - 1) == true)
1.1 misho 1307: SET(flags, MODE_NONINTERACTIVE);
1308: continue;
1309: }
1310: if (MATCHES(*cur, "sudoedit=")) {
1.1.1.2 ! misho 1311: if (atobool(*cur + sizeof("sudoedit=") - 1) == true)
1.1 misho 1312: SET(flags, MODE_EDIT);
1313: continue;
1314: }
1315: if (MATCHES(*cur, "login_class=")) {
1316: login_class = *cur + sizeof("login_class=") - 1;
1.1.1.2 ! misho 1317: def_use_loginclass = true;
1.1 misho 1318: continue;
1319: }
1320: #ifdef HAVE_SELINUX
1321: if (MATCHES(*cur, "selinux_role=")) {
1322: user_role = *cur + sizeof("selinux_role=") - 1;
1323: continue;
1324: }
1325: if (MATCHES(*cur, "selinux_type=")) {
1326: user_type = *cur + sizeof("selinux_type=") - 1;
1327: continue;
1328: }
1329: #endif /* HAVE_SELINUX */
1330: #ifdef HAVE_BSD_AUTH_H
1331: if (MATCHES(*cur, "bsdauth_type=")) {
1332: login_style = *cur + sizeof("bsdauth_type=") - 1;
1333: continue;
1334: }
1335: #endif /* HAVE_BSD_AUTH_H */
1336: #if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME)
1337: if (MATCHES(*cur, "progname=")) {
1338: setprogname(*cur + sizeof("progname=") - 1);
1339: continue;
1340: }
1341: #endif
1342: if (MATCHES(*cur, "network_addrs=")) {
1343: interfaces_string = *cur + sizeof("network_addrs=") - 1;
1344: set_interfaces(interfaces_string);
1345: continue;
1346: }
1347: }
1348:
1349: for (cur = user_info; *cur != NULL; cur++) {
1350: if (MATCHES(*cur, "user=")) {
1351: user_name = estrdup(*cur + sizeof("user=") - 1);
1352: continue;
1353: }
1354: if (MATCHES(*cur, "uid=")) {
1355: user_uid = (uid_t) atoi(*cur + sizeof("uid=") - 1);
1356: continue;
1357: }
1358: if (MATCHES(*cur, "gid=")) {
1359: p = *cur + sizeof("gid=") - 1;
1360: user_gid = (gid_t) atoi(p);
1361: continue;
1362: }
1363: if (MATCHES(*cur, "groups=")) {
1364: groups = *cur + sizeof("groups=") - 1;
1365: continue;
1366: }
1367: if (MATCHES(*cur, "cwd=")) {
1368: user_cwd = estrdup(*cur + sizeof("cwd=") - 1);
1369: continue;
1370: }
1371: if (MATCHES(*cur, "tty=")) {
1372: user_tty = user_ttypath = estrdup(*cur + sizeof("tty=") - 1);
1373: if (strncmp(user_tty, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
1374: user_tty += sizeof(_PATH_DEV) - 1;
1375: continue;
1376: }
1377: if (MATCHES(*cur, "host=")) {
1378: user_host = user_shost = estrdup(*cur + sizeof("host=") - 1);
1379: if ((p = strchr(user_host, '.')))
1380: user_shost = estrndup(user_host, (size_t)(p - user_host));
1381: continue;
1382: }
1383: if (MATCHES(*cur, "lines=")) {
1384: sudo_user.lines = atoi(*cur + sizeof("lines=") - 1);
1385: continue;
1386: }
1387: if (MATCHES(*cur, "cols=")) {
1388: sudo_user.cols = atoi(*cur + sizeof("cols=") - 1);
1389: continue;
1390: }
1391: }
1392: if (user_cwd == NULL)
1393: user_cwd = "unknown";
1394: if (user_tty == NULL)
1395: user_tty = "unknown"; /* user_ttypath remains NULL */
1396:
1397: if (groups != NULL && groups[0] != '\0') {
1398: const char *cp;
1399: GETGROUPS_T *gids;
1400: int ngids;
1401:
1402: /* Count number of groups, including passwd gid. */
1403: ngids = 2;
1404: for (cp = groups; *cp != '\0'; cp++) {
1405: if (*cp == ',')
1406: ngids++;
1407: }
1408:
1409: /* The first gid in the list is the passwd group gid. */
1410: gids = emalloc2(ngids, sizeof(GETGROUPS_T));
1411: gids[0] = user_gid;
1412: ngids = 1;
1413: cp = groups;
1414: for (;;) {
1415: gids[ngids] = atoi(cp);
1416: if (gids[0] != gids[ngids])
1417: ngids++;
1418: cp = strchr(cp, ',');
1419: if (cp == NULL)
1420: break;
1421: cp++; /* skip over comma */
1422: }
1423: set_group_list(user_name, gids, ngids);
1424: efree(gids);
1425: }
1426:
1.1.1.2 ! misho 1427: /* Setup debugging if indicated. */
! 1428: if (debug_flags != NULL) {
! 1429: sudo_debug_init(NULL, debug_flags);
! 1430: for (cur = settings; *cur != NULL; cur++)
! 1431: sudo_debug_printf(SUDO_DEBUG_INFO, "settings: %s", *cur);
! 1432: for (cur = user_info; *cur != NULL; cur++)
! 1433: sudo_debug_printf(SUDO_DEBUG_INFO, "user_info: %s", *cur);
! 1434: }
! 1435:
1.1 misho 1436: #undef MATCHES
1.1.1.2 ! misho 1437: debug_return_int(flags);
1.1 misho 1438: }
1439:
1440: static char *
1441: resolve_editor(char *editor, int nfiles, char **files, char ***argv_out)
1442: {
1443: char *cp, **nargv, *editor_path = NULL;
1.1.1.2 ! misho 1444: int ac, i, nargc;
! 1445: bool wasblank;
! 1446: debug_decl(resolve_editor, SUDO_DEBUG_PLUGIN)
1.1 misho 1447:
1448: editor = estrdup(editor); /* becomes part of argv_out */
1449:
1450: /*
1451: * Split editor into an argument vector; editor is reused (do not free).
1452: * The EDITOR and VISUAL environment variables may contain command
1453: * line args so look for those and alloc space for them too.
1454: */
1455: nargc = 1;
1.1.1.2 ! misho 1456: for (wasblank = false, cp = editor; *cp != '\0'; cp++) {
1.1 misho 1457: if (isblank((unsigned char) *cp))
1.1.1.2 ! misho 1458: wasblank = true;
1.1 misho 1459: else if (wasblank) {
1.1.1.2 ! misho 1460: wasblank = false;
1.1 misho 1461: nargc++;
1462: }
1463: }
1464: /* If we can't find the editor in the user's PATH, give up. */
1465: cp = strtok(editor, " \t");
1466: if (cp == NULL ||
1467: find_path(cp, &editor_path, NULL, getenv("PATH"), 0) != FOUND) {
1468: efree(editor);
1.1.1.2 ! misho 1469: debug_return_str(NULL);
1.1 misho 1470: }
1471: nargv = (char **) emalloc2(nargc + 1 + nfiles + 1, sizeof(char *));
1472: for (ac = 0; cp != NULL && ac < nargc; ac++) {
1473: nargv[ac] = cp;
1474: cp = strtok(NULL, " \t");
1475: }
1476: nargv[ac++] = "--";
1477: for (i = 0; i < nfiles; )
1478: nargv[ac++] = files[i++];
1479: nargv[ac] = NULL;
1480:
1481: *argv_out = nargv;
1.1.1.2 ! misho 1482: debug_return_str(editor_path);
1.1 misho 1483: }
1484:
1485: /*
1486: * Determine which editor to use. We don't need to worry about restricting
1487: * this to a "safe" editor since it runs with the uid of the invoking user,
1488: * not the runas (privileged) user.
1489: */
1490: static char *
1491: find_editor(int nfiles, char **files, char ***argv_out)
1492: {
1493: char *cp, *editor, *editor_path = NULL, **ev, *ev0[4];
1.1.1.2 ! misho 1494: debug_decl(find_editor, SUDO_DEBUG_PLUGIN)
1.1 misho 1495:
1496: /*
1497: * If any of SUDO_EDITOR, VISUAL or EDITOR are set, choose the first one.
1498: */
1499: ev0[0] = "SUDO_EDITOR";
1500: ev0[1] = "VISUAL";
1501: ev0[2] = "EDITOR";
1502: ev0[3] = NULL;
1503: for (ev = ev0; *ev != NULL; ev++) {
1504: if ((editor = getenv(*ev)) != NULL && *editor != '\0') {
1505: editor_path = resolve_editor(editor, nfiles, files, argv_out);
1506: if (editor_path != NULL)
1507: break;
1508: }
1509: }
1510: if (editor_path == NULL) {
1511: /* def_editor could be a path, split it up */
1512: editor = estrdup(def_editor);
1513: cp = strtok(editor, ":");
1514: while (cp != NULL && editor_path == NULL) {
1515: editor_path = resolve_editor(cp, nfiles, files, argv_out);
1516: cp = strtok(NULL, ":");
1517: }
1518: if (editor_path)
1519: efree(editor);
1520: }
1521: if (!editor_path) {
1522: audit_failure(NewArgv, _("%s: command not found"), editor);
1523: warningx(_("%s: command not found"), editor);
1524: }
1.1.1.2 ! misho 1525: debug_return_str(editor_path);
1.1 misho 1526: }
1527:
1528: #ifdef USE_ADMIN_FLAG
1529: static void
1530: create_admin_success_flag(void)
1531: {
1532: struct stat statbuf;
1533: char flagfile[PATH_MAX];
1534: int fd, n;
1.1.1.2 ! misho 1535: debug_decl(create_admin_success_flag, SUDO_DEBUG_PLUGIN)
1.1 misho 1536:
1537: /* Check whether the user is in the admin group. */
1538: if (!user_in_group(sudo_user.pw, "admin"))
1.1.1.2 ! misho 1539: debug_return;
1.1 misho 1540:
1541: /* Build path to flag file. */
1542: n = snprintf(flagfile, sizeof(flagfile), "%s/.sudo_as_admin_successful",
1543: user_dir);
1544: if (n <= 0 || n >= sizeof(flagfile))
1.1.1.2 ! misho 1545: debug_return;
1.1 misho 1546:
1547: /* Create admin flag file if it doesn't already exist. */
1548: set_perms(PERM_USER);
1549: if (stat(flagfile, &statbuf) != 0) {
1550: fd = open(flagfile, O_CREAT|O_WRONLY|O_EXCL, 0644);
1551: close(fd);
1552: }
1553: restore_perms();
1.1.1.2 ! misho 1554: debug_return;
1.1 misho 1555: }
1556: #else /* !USE_ADMIN_FLAG */
1557: static void
1558: create_admin_success_flag(void)
1559: {
1560: /* STUB */
1561: }
1562: #endif /* USE_ADMIN_FLAG */
1563:
1.1.1.2 ! misho 1564: static void
! 1565: sudoers_policy_register_hooks(int version, int (*register_hook)(struct sudo_hook *hook))
! 1566: {
! 1567: struct sudo_hook hook;
! 1568:
! 1569: memset(&hook, 0, sizeof(hook));
! 1570: hook.hook_version = SUDO_HOOK_VERSION;
! 1571:
! 1572: hook.hook_type = SUDO_HOOK_SETENV;
! 1573: hook.hook_fn = sudoers_hook_setenv;
! 1574: register_hook(&hook);
! 1575:
! 1576: hook.hook_type = SUDO_HOOK_UNSETENV;
! 1577: hook.hook_fn = sudoers_hook_unsetenv;
! 1578: register_hook(&hook);
! 1579:
! 1580: hook.hook_type = SUDO_HOOK_GETENV;
! 1581: hook.hook_fn = sudoers_hook_getenv;
! 1582: register_hook(&hook);
! 1583:
! 1584: hook.hook_type = SUDO_HOOK_PUTENV;
! 1585: hook.hook_fn = sudoers_hook_putenv;
! 1586: register_hook(&hook);
! 1587: }
! 1588:
1.1 misho 1589: struct policy_plugin sudoers_policy = {
1590: SUDO_POLICY_PLUGIN,
1591: SUDO_API_VERSION,
1592: sudoers_policy_open,
1593: sudoers_policy_close,
1594: sudoers_policy_version,
1595: sudoers_policy_check,
1596: sudoers_policy_list,
1597: sudoers_policy_validate,
1598: sudoers_policy_invalidate,
1.1.1.2 ! misho 1599: sudoers_policy_init_session,
! 1600: sudoers_policy_register_hooks
1.1 misho 1601: };
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>