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