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