Diff for /embedaddon/sudo/plugins/sudoers/sudoers.c between versions 1.1.1.2 and 1.1.1.4

version 1.1.1.2, 2012/05/29 12:26:49 version 1.1.1.4, 2013/07/22 10:46:12
Line 1 Line 1
 /*  /*
 * Copyright (c) 1993-1996, 1998-2011 Todd C. Miller <Todd.Miller@courtesan.com> * Copyright (c) 1993-1996, 1998-2013 Todd C. Miller <Todd.Miller@courtesan.com>
  *   *
  * Permission to use, copy, modify, and distribute this software for any   * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above   * purpose with or without fee is hereby granted, provided that the above
Line 16 Line 16
  * Sponsored in part by the Defense Advanced Research Projects   * Sponsored in part by the Defense Advanced Research Projects
  * Agency (DARPA) and Air Force Research Laboratory, Air Force   * Agency (DARPA) and Air Force Research Laboratory, Air Force
  * Materiel Command, USAF, under agreement number F39502-99-1-0512.   * Materiel Command, USAF, under agreement number F39502-99-1-0512.
  *  
  * For a brief history of sudo, please see the HISTORY file included  
  * with this distribution.  
  */   */
   
 #define _SUDO_MAIN  #define _SUDO_MAIN
Line 31 Line 28
   
 #include <sys/types.h>  #include <sys/types.h>
 #include <sys/stat.h>  #include <sys/stat.h>
 #include <sys/param.h>  
 #include <sys/socket.h>  #include <sys/socket.h>
 #include <stdio.h>  #include <stdio.h>
 #ifdef STDC_HEADERS  #ifdef STDC_HEADERS
Line 60 Line 56
 #include <signal.h>  #include <signal.h>
 #include <grp.h>  #include <grp.h>
 #include <time.h>  #include <time.h>
 #ifdef HAVE_SETLOCALE  
 # include <locale.h>  
 #endif  
 #include <netinet/in.h>  
 #include <netdb.h>  #include <netdb.h>
 #ifdef HAVE_LOGIN_CAP_H  #ifdef HAVE_LOGIN_CAP_H
 # include <login_cap.h>  # include <login_cap.h>
Line 78 Line 70
 # include <selinux/selinux.h>  # include <selinux/selinux.h>
 #endif  #endif
 #include <ctype.h>  #include <ctype.h>
 #include <setjmp.h>  
 #ifndef HAVE_GETADDRINFO  #ifndef HAVE_GETADDRINFO
 # include "compat/getaddrinfo.h"  # include "compat/getaddrinfo.h"
 #endif  #endif
   
 #include "sudoers.h"  #include "sudoers.h"
 #include "interfaces.h"  
 #include "sudoers_version.h"  
 #include "auth/sudo_auth.h"  #include "auth/sudo_auth.h"
 #include "secure_path.h"  #include "secure_path.h"
   
 /*  /*
  * Prototypes   * Prototypes
  */   */
static void init_vars(char * const *);static char *find_editor(int nfiles, char **files, char ***argv_out);
 static int cb_runas_default(const char *);
 static int cb_sudoers_locale(const char *);
 static int set_cmnd(void);  static int set_cmnd(void);
   static void create_admin_success_flag(void);
   static void init_vars(char * const *);
   static void set_fqdn(void);
 static void set_loginclass(struct passwd *);  static void set_loginclass(struct passwd *);
 static void set_runaspw(const char *);  
 static void set_runasgr(const char *);  static void set_runasgr(const char *);
static int cb_runas_default(const char *);static void set_runaspw(const char *);
static int sudoers_policy_version(int verbose);static bool tty_present(void);
static int deserialize_info(char * const args[], char * const settings[], 
    char * const user_info[]); 
static char *find_editor(int nfiles, char **files, char ***argv_out); 
static void create_admin_success_flag(void); 
   
 /*  /*
  * Globals   * Globals
  */   */
 struct sudo_user sudo_user;  struct sudo_user sudo_user;
 struct passwd *list_pw;  struct passwd *list_pw;
 struct interface *interfaces;  
 int long_list;  int long_list;
 uid_t timestamp_uid;  uid_t timestamp_uid;
 extern int errorlineno;  extern int errorlineno;
Line 118  extern char *errorfile; Line 106  extern char *errorfile;
 #ifdef HAVE_BSD_AUTH_H  #ifdef HAVE_BSD_AUTH_H
 char *login_style;  char *login_style;
 #endif /* HAVE_BSD_AUTH_H */  #endif /* HAVE_BSD_AUTH_H */
 sudo_conv_t sudo_conv;  
 sudo_printf_t sudo_printf;  
 int sudo_mode;  int sudo_mode;
   
 static int sudo_version;  
 static char *prev_user;  static char *prev_user;
 static char *runas_user;  static char *runas_user;
 static char *runas_group;  static char *runas_group;
 static struct sudo_nss_list *snl;  static struct sudo_nss_list *snl;
 static const char *interfaces_string;  
 static sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp;  
   
 /* XXX - must be extern for audit bits of sudo_auth.c */  /* XXX - must be extern for audit bits of sudo_auth.c */
 int NewArgc;  int NewArgc;
 char **NewArgv;  char **NewArgv;
   
/* Declared here instead of plugin_error.c for static sudo builds. */int
sigjmp_buf error_jmp;sudoers_policy_init(void *info, char * const envp[])
 
static int 
sudoers_policy_open(unsigned int version, sudo_conv_t conversation, 
    sudo_printf_t plugin_printf, char * const settings[], 
    char * const user_info[], char * const envp[], char * const args[]) 
 {  {
     volatile int sources = 0;      volatile int sources = 0;
    sigaction_t sa;    struct sudo_nss *nss, *nss_next;
    struct sudo_nss *nss;    debug_decl(sudoers_policy_init, SUDO_DEBUG_PLUGIN)
    debug_decl(sudoers_policy_open, SUDO_DEBUG_PLUGIN) 
   
     sudo_version = version;  
     if (!sudo_conv)  
         sudo_conv = conversation;  
     if (!sudo_printf)  
         sudo_printf = plugin_printf;  
   
     /* Plugin args are only specified for API version 1.2 and higher. */  
     if (sudo_version < SUDO_API_MKVERSION(1, 2))  
         args = NULL;  
   
     if (sigsetjmp(error_jmp, 1)) {  
         /* called via error(), errorx() or log_fatal() */  
         rewind_perms();  
         debug_return_bool(-1);  
     }  
   
     bindtextdomain("sudoers", LOCALEDIR);      bindtextdomain("sudoers", LOCALEDIR);
   
     /*  
      * Signal setup:  
      *  Ignore keyboard-generated signals so the user cannot interrupt  
      *  us at some point and avoid the logging.  
      *  Install handler to wait for children when they exit.  
      */  
     zero_bytes(&sa, sizeof(sa));  
     sigemptyset(&sa.sa_mask);  
     sa.sa_flags = SA_RESTART;  
     sa.sa_handler = SIG_IGN;  
     (void) sigaction(SIGINT, &sa, &saved_sa_int);  
     (void) sigaction(SIGQUIT, &sa, &saved_sa_quit);  
     (void) sigaction(SIGTSTP, &sa, &saved_sa_tstp);  
   
     sudo_setpwent();      sudo_setpwent();
     sudo_setgrent();      sudo_setgrent();
   
       /* Register fatal/fatalx callback. */
       fatal_callback_register(sudoers_cleanup);
   
     /* Initialize environment functions (including replacements). */      /* Initialize environment functions (including replacements). */
     env_init(envp);      env_init(envp);
   
     /* Setup defaults data structures. */      /* Setup defaults data structures. */
     init_defaults();      init_defaults();
   
    /* Parse args, settings and user_info */    /* Parse info from front-end. */
    sudo_mode = deserialize_info(args, settings, user_info);    sudo_mode = sudoers_policy_deserialize_info(info, &runas_user, &runas_group);
   
     init_vars(envp);            /* XXX - move this later? */      init_vars(envp);            /* XXX - move this later? */
   
Line 201  sudoers_policy_open(unsigned int version, sudo_conv_t  Line 151  sudoers_policy_open(unsigned int version, sudo_conv_t 
     set_perms(PERM_ROOT);      set_perms(PERM_ROOT);
   
     /* Open and parse sudoers, set global defaults */      /* Open and parse sudoers, set global defaults */
    tq_foreach_fwd(snl, nss) {    for (nss = snl->first; nss != NULL; nss = nss_next) {
        if (nss->open(nss) == 0 && nss->parse(nss) == 0) {        nss_next = nss->next;
            sources++;        if (nss->open(nss) == 0 && nss->parse(nss) == 0) {
            if (nss->setdefs(nss) != 0)            sources++;
                log_error(NO_STDERR, _("problem with defaults entries"));            if (nss->setdefs(nss) != 0)
        }                log_warning(NO_STDERR, N_("problem with defaults entries"));
         } else {
             tq_remove(snl, nss);
         }
     }      }
     if (sources == 0) {      if (sources == 0) {
         warningx(_("no valid sudoers sources found, quitting"));          warningx(_("no valid sudoers sources found, quitting"));
Line 228  sudoers_policy_open(unsigned int version, sudo_conv_t  Line 181  sudoers_policy_open(unsigned int version, sudo_conv_t 
      * Note that if runas_group was specified without runas_user we       * Note that if runas_group was specified without runas_user we
      * defer setting runas_pw so the match routines know to ignore it.       * defer setting runas_pw so the match routines know to ignore it.
      */       */
       /* XXX - qpm4u does more here as it may have already set runas_pw */
     if (runas_group != NULL) {      if (runas_group != NULL) {
         set_runasgr(runas_group);          set_runasgr(runas_group);
         if (runas_user != NULL)          if (runas_user != NULL)
Line 236  sudoers_policy_open(unsigned int version, sudo_conv_t  Line 190  sudoers_policy_open(unsigned int version, sudo_conv_t 
         set_runaspw(runas_user ? runas_user : def_runas_default);          set_runaspw(runas_user ? runas_user : def_runas_default);
   
     if (!update_defaults(SETDEF_RUNAS))      if (!update_defaults(SETDEF_RUNAS))
        log_error(NO_STDERR, _("problem with defaults entries"));        log_warning(NO_STDERR, N_("problem with defaults entries"));
   
     if (def_fqdn)      if (def_fqdn)
         set_fqdn();     /* deferred until after sudoers is parsed */          set_fqdn();     /* deferred until after sudoers is parsed */
Line 249  sudoers_policy_open(unsigned int version, sudo_conv_t  Line 203  sudoers_policy_open(unsigned int version, sudo_conv_t 
     debug_return_bool(true);      debug_return_bool(true);
 }  }
   
static voidint
sudoers_policy_close(int exit_status, int error_code) 
{ 
    debug_decl(sudoers_policy_close, SUDO_DEBUG_PLUGIN) 
 
    if (sigsetjmp(error_jmp, 1)) { 
        /* called via error(), errorx() or log_fatal() */ 
        debug_return; 
    } 
 
    /* We do not currently log the exit status. */ 
    if (error_code) 
        warningx(_("unable to execute %s: %s"), safe_cmnd, strerror(error_code)); 
 
    /* Close the session we opened in sudoers_policy_init_session(). */ 
    if (ISSET(sudo_mode, MODE_RUN|MODE_EDIT)) 
        (void)sudo_auth_end_session(runas_pw); 
 
    /* Free remaining references to password and group entries. */ 
    pw_delref(sudo_user.pw); 
    pw_delref(runas_pw); 
    if (runas_gr != NULL) 
        gr_delref(runas_gr); 
    if (user_group_list != NULL) 
        grlist_delref(user_group_list); 
 
    debug_return; 
} 
 
/* 
 * The init_session function is called before executing the command 
 * and before uid/gid changes occur. 
 */ 
static int 
sudoers_policy_init_session(struct passwd *pwd, char **user_env[]) 
{ 
    debug_decl(sudoers_policy_init, SUDO_DEBUG_PLUGIN) 
 
    /* user_env is only specified for API version 1.2 and higher. */ 
    if (sudo_version < SUDO_API_MKVERSION(1, 2)) 
        user_env = NULL; 
 
    if (sigsetjmp(error_jmp, 1)) { 
        /* called via error(), errorx() or log_fatal() */ 
        return -1; 
    } 
 
    debug_return_bool(sudo_auth_begin_session(pwd, user_env)); 
} 
 
static int 
 sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],  sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
    char **command_infop[], char **argv_out[], char **user_env_out[])    void *closure)
 {  {
     static char *command_info[32]; /* XXX */  
     char **edit_argv = NULL;      char **edit_argv = NULL;
       char *iolog_path = NULL;
       mode_t cmnd_umask = 0777;
     struct sudo_nss *nss;      struct sudo_nss *nss;
    int cmnd_status = -1, validated;    int cmnd_status = -1, oldlocale, validated;
    volatile int info_len = 0; 
     volatile int rval = true;      volatile int rval = true;
     debug_decl(sudoers_policy_main, SUDO_DEBUG_PLUGIN)      debug_decl(sudoers_policy_main, SUDO_DEBUG_PLUGIN)
   
    if (sigsetjmp(error_jmp, 1)) {    /* XXX - would like to move this to policy.c but need the cleanup. */
        /* error recovery via error(), errorx() or log_fatal() */    if (fatal_setjmp() != 0) {
         /* error recovery via fatal(), fatalx() or log_fatal() */
         rval = -1;          rval = -1;
         goto done;          goto done;
     }      }
Line 363  sudoers_policy_main(int argc, char * const argv[], int Line 268  sudoers_policy_main(int argc, char * const argv[], int
   
     /* Find command in path */      /* Find command in path */
     cmnd_status = set_cmnd();      cmnd_status = set_cmnd();
     if (cmnd_status == -1) {  
         rval = -1;  
         goto done;  
     }  
   
 #ifdef HAVE_SETLOCALE  
     if (!setlocale(LC_ALL, def_sudoers_locale)) {  
         warningx(_("unable to set locale to \"%s\", using \"C\""),  
             def_sudoers_locale);  
         setlocale(LC_ALL, "C");  
     }  
 #endif  
   
     /*      /*
     * Check sudoers sources.     * Check sudoers sources, using the locale specified in sudoers.
      */       */
       sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale);
     validated = FLAG_NO_USER | FLAG_NO_HOST;      validated = FLAG_NO_USER | FLAG_NO_HOST;
     tq_foreach_fwd(snl, nss) {      tq_foreach_fwd(snl, nss) {
         validated = nss->lookup(nss, validated, pwflag);          validated = nss->lookup(nss, validated, pwflag);
   
         if (ISSET(validated, VALIDATE_OK)) {          if (ISSET(validated, VALIDATE_OK)) {
            /* Handle "= auth" in netsvc.conf */            /* Handle [SUCCESS=return] */
             if (nss->ret_if_found)              if (nss->ret_if_found)
                 break;                  break;
         } else {          } else {
Line 394  sudoers_policy_main(int argc, char * const argv[], int Line 288  sudoers_policy_main(int argc, char * const argv[], int
         }          }
     }      }
   
       /* Restore user's locale. */
       sudoers_setlocale(oldlocale, NULL);
   
     if (safe_cmnd == NULL)      if (safe_cmnd == NULL)
         safe_cmnd = estrdup(user_cmnd);          safe_cmnd = estrdup(user_cmnd);
   
 #ifdef HAVE_SETLOCALE  
     setlocale(LC_ALL, "");  
 #endif  
   
     /* If only a group was specified, set runas_pw based on invoking user. */      /* If only a group was specified, set runas_pw based on invoking user. */
     if (runas_pw == NULL)      if (runas_pw == NULL)
         set_runaspw(user_name);          set_runaspw(user_name);
Line 417  sudoers_policy_main(int argc, char * const argv[], int Line 310  sudoers_policy_main(int argc, char * const argv[], int
             pw = sudo_getpwnam(def_timestampowner);              pw = sudo_getpwnam(def_timestampowner);
         if (pw != NULL) {          if (pw != NULL) {
             timestamp_uid = pw->pw_uid;              timestamp_uid = pw->pw_uid;
            pw_delref(pw);            sudo_pw_delref(pw);
         } else {          } else {
            log_error(0, _("timestamp owner (%s): No such user"),            log_warning(0, N_("timestamp owner (%s): No such user"),
                 def_timestampowner);                  def_timestampowner);
             timestamp_uid = ROOT_UID;              timestamp_uid = ROOT_UID;
         }          }
Line 432  sudoers_policy_main(int argc, char * const argv[], int Line 325  sudoers_policy_main(int argc, char * const argv[], int
     }      }
   
     /* Bail if a tty is required and we don't have one.  */      /* Bail if a tty is required and we don't have one.  */
    if (def_requiretty) {    if (def_requiretty && !tty_present()) {
        int fd = open(_PATH_TTY, O_RDWR|O_NOCTTY);        audit_failure(NewArgv, N_("no tty"));
        if (fd == -1) {        warningx(_("sorry, you must have a tty to run sudo"));
            audit_failure(NewArgv, _("no tty"));        goto bad;
            warningx(_("sorry, you must have a tty to run sudo")); 
            goto bad; 
        } else 
            (void) close(fd); 
     }      }
   
     /*      /*
Line 455  sudoers_policy_main(int argc, char * const argv[], int Line 344  sudoers_policy_main(int argc, char * const argv[], int
   
     /* Require a password if sudoers says so.  */      /* Require a password if sudoers says so.  */
     rval = check_user(validated, sudo_mode);      rval = check_user(validated, sudo_mode);
    if (rval != true)    if (rval != true) {
         if (!ISSET(validated, VALIDATE_OK))
             log_denial(validated, false);
         goto done;          goto done;
       }
   
     /* If run as root with SUDO_USER set, set sudo_user.pw to that user. */      /* If run as root with SUDO_USER set, set sudo_user.pw to that user. */
     /* XXX - causes confusion when root is not listed in sudoers */      /* XXX - causes confusion when root is not listed in sudoers */
Line 466  sudoers_policy_main(int argc, char * const argv[], int Line 358  sudoers_policy_main(int argc, char * const argv[], int
   
             if ((pw = sudo_getpwnam(prev_user)) != NULL) {              if ((pw = sudo_getpwnam(prev_user)) != NULL) {
                     if (sudo_user.pw != NULL)                      if (sudo_user.pw != NULL)
                        pw_delref(sudo_user.pw);                        sudo_pw_delref(sudo_user.pw);
                     sudo_user.pw = pw;                      sudo_user.pw = pw;
             }              }
         }          }
Line 474  sudoers_policy_main(int argc, char * const argv[], int Line 366  sudoers_policy_main(int argc, char * const argv[], int
   
     /* If the user was not allowed to run the command we are done. */      /* If the user was not allowed to run the command we are done. */
     if (!ISSET(validated, VALIDATE_OK)) {      if (!ISSET(validated, VALIDATE_OK)) {
        if (ISSET(validated, FLAG_NO_USER | FLAG_NO_HOST)) {        log_failure(validated, cmnd_status);
            audit_failure(NewArgv, _("No user or host")); 
            log_denial(validated, 1); 
        } else { 
            if (def_path_info) { 
                /* 
                 * We'd like to not leak path info at all here, but that can 
                 * *really* confuse the users.  To really close the leak we'd 
                 * have to say "not allowed to run foo" even when the problem 
                 * is just "no foo in path" since the user can trivially set 
                 * their path to just contain a single dir. 
                 */ 
                log_denial(validated, 
                    !(cmnd_status == NOT_FOUND_DOT || cmnd_status == NOT_FOUND)); 
                if (cmnd_status == NOT_FOUND) 
                    warningx(_("%s: command not found"), user_cmnd); 
                else if (cmnd_status == NOT_FOUND_DOT) 
                    warningx(_("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run."), user_cmnd, user_cmnd, user_cmnd); 
            } else { 
                /* Just tell the user they are not allowed to run foo. */ 
                log_denial(validated, 1); 
            } 
            audit_failure(NewArgv, _("validation failure")); 
        } 
         goto bad;          goto bad;
     }      }
   
Line 506  sudoers_policy_main(int argc, char * const argv[], int Line 375  sudoers_policy_main(int argc, char * const argv[], int
   
     /* Finally tell the user if the command did not exist. */      /* Finally tell the user if the command did not exist. */
     if (cmnd_status == NOT_FOUND_DOT) {      if (cmnd_status == NOT_FOUND_DOT) {
        audit_failure(NewArgv, _("command in current directory"));        audit_failure(NewArgv, N_("command in current directory"));
         warningx(_("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run."), user_cmnd, user_cmnd, user_cmnd);          warningx(_("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run."), user_cmnd, user_cmnd, user_cmnd);
         goto bad;          goto bad;
     } else if (cmnd_status == NOT_FOUND) {      } else if (cmnd_status == NOT_FOUND) {
        audit_failure(NewArgv, _("%s: command not found"), user_cmnd);        if (ISSET(sudo_mode, MODE_CHECK)) {
        warningx(_("%s: command not found"), user_cmnd);            audit_failure(NewArgv, N_("%s: command not found"), NewArgv[0]);
             warningx(_("%s: command not found"), NewArgv[0]);
         } else {
             audit_failure(NewArgv, N_("%s: command not found"), user_cmnd);
             warningx(_("%s: command not found"), user_cmnd);
         }
         goto bad;          goto bad;
     }      }
   
Line 524  sudoers_policy_main(int argc, char * const argv[], int Line 398  sudoers_policy_main(int argc, char * const argv[], int
             validate_env_vars(sudo_user.env_vars);              validate_env_vars(sudo_user.env_vars);
     }      }
   
    if (ISSET(sudo_mode, (MODE_RUN | MODE_EDIT)) && (def_log_input || def_log_output)) {    if (ISSET(sudo_mode, (MODE_RUN | MODE_EDIT))) {
        if (def_iolog_file && def_iolog_dir) {        if ((def_log_input || def_log_output) && def_iolog_file && def_iolog_dir) {
            command_info[info_len++] = expand_iolog_path("iolog_path=",            const char prefix[] = "iolog_path=";
                def_iolog_dir, def_iolog_file, &sudo_user.iolog_file);            iolog_path = expand_iolog_path(prefix, def_iolog_dir,
                 def_iolog_file, &sudo_user.iolog_file);
             sudo_user.iolog_file++;              sudo_user.iolog_file++;
         }          }
         if (def_log_input) {  
             command_info[info_len++] = estrdup("iolog_stdin=true");  
             command_info[info_len++] = estrdup("iolog_ttyin=true");  
         }  
         if (def_log_output) {  
             command_info[info_len++] = estrdup("iolog_stdout=true");  
             command_info[info_len++] = estrdup("iolog_stderr=true");  
             command_info[info_len++] = estrdup("iolog_ttyout=true");  
         }  
         if (def_compress_io)  
             command_info[info_len++] = estrdup("iolog_compress=true");  
     }      }
   
     log_allowed(validated);      log_allowed(validated);
Line 567  sudoers_policy_main(int argc, char * const argv[], int Line 431  sudoers_policy_main(int argc, char * const argv[], int
      * unless umask_override is set.       * unless umask_override is set.
      */       */
     if (def_umask != 0777) {      if (def_umask != 0777) {
        mode_t mask = def_umask;        cmnd_umask = def_umask;
        if (!def_umask_override) {        if (!def_umask_override)
            mode_t omask = umask(mask);            cmnd_umask |= user_umask;
            mask |= omask; 
            umask(omask); 
        } 
        easprintf(&command_info[info_len++], "umask=0%o", (unsigned int)mask); 
     }      }
   
     if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {      if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
Line 585  sudoers_policy_main(int argc, char * const argv[], int Line 445  sudoers_policy_main(int argc, char * const argv[], int
         *p = '-';          *p = '-';
         NewArgv[0] = p;          NewArgv[0] = p;
   
         /* Set cwd to run user's homedir. */  
         command_info[info_len++] = fmt_string("cwd", runas_pw->pw_dir);  
   
         /*          /*
          * Newer versions of bash require the --login option to be used           * Newer versions of bash require the --login option to be used
          * in conjunction with the -c option even if the shell name starts           * in conjunction with the -c option even if the shell name starts
Line 626  sudoers_policy_main(int argc, char * const argv[], int Line 483  sudoers_policy_main(int argc, char * const argv[], int
     /* Insert user-specified environment variables. */      /* Insert user-specified environment variables. */
     insert_env_vars(sudo_user.env_vars);      insert_env_vars(sudo_user.env_vars);
   
     /* Restore signal handlers before we exec. */  
     (void) sigaction(SIGINT, &saved_sa_int, NULL);  
     (void) sigaction(SIGQUIT, &saved_sa_quit, NULL);  
     (void) sigaction(SIGTSTP, &saved_sa_tstp, NULL);  
   
     if (ISSET(sudo_mode, MODE_EDIT)) {      if (ISSET(sudo_mode, MODE_EDIT)) {
        char *editor = find_editor(NewArgc - 1, NewArgv + 1, &edit_argv);        efree(safe_cmnd);
        if (editor == NULL)        safe_cmnd = find_editor(NewArgc - 1, NewArgv + 1, &edit_argv);
         if (safe_cmnd == NULL)
             goto bad;              goto bad;
         command_info[info_len++] = fmt_string("command", editor);  
         command_info[info_len++] = estrdup("sudoedit=true");  
     } else {  
         command_info[info_len++] = fmt_string("command", safe_cmnd);  
     }      }
     if (def_stay_setuid) {  
         easprintf(&command_info[info_len++], "runas_uid=%u",  
             (unsigned int)user_uid);  
         easprintf(&command_info[info_len++], "runas_gid=%u",  
             (unsigned int)user_gid);  
         easprintf(&command_info[info_len++], "runas_euid=%u",  
             (unsigned int)runas_pw->pw_uid);  
         easprintf(&command_info[info_len++], "runas_egid=%u",  
             runas_gr ? (unsigned int)runas_gr->gr_gid :  
             (unsigned int)runas_pw->pw_gid);  
     } else {  
         easprintf(&command_info[info_len++], "runas_uid=%u",  
             (unsigned int)runas_pw->pw_uid);  
         easprintf(&command_info[info_len++], "runas_gid=%u",  
             runas_gr ? (unsigned int)runas_gr->gr_gid :  
             (unsigned int)runas_pw->pw_gid);  
     }  
     if (def_preserve_groups) {  
         command_info[info_len++] = "preserve_groups=true";  
     } else {  
         int i, len;  
         gid_t egid;  
         size_t glsize;  
         char *cp, *gid_list;  
         struct group_list *grlist = get_group_list(runas_pw);  
   
         /* We reserve an extra spot in the list for the effective gid. */  
         glsize = sizeof("runas_groups=") - 1 +  
             ((grlist->ngids + 1) * (MAX_UID_T_LEN + 1));  
         gid_list = emalloc(glsize);  
         memcpy(gid_list, "runas_groups=", sizeof("runas_groups=") - 1);  
         cp = gid_list + sizeof("runas_groups=") - 1;  
   
         /* On BSD systems the effective gid is the first group in the list. */  
         egid = runas_gr ? (unsigned int)runas_gr->gr_gid :  
             (unsigned int)runas_pw->pw_gid;  
         len = snprintf(cp, glsize - (cp - gid_list), "%u", egid);  
         if (len < 0 || len >= glsize - (cp - gid_list))  
             errorx(1, _("internal error, runas_groups overflow"));  
         cp += len;  
         for (i = 0; i < grlist->ngids; i++) {  
             if (grlist->gids[i] != egid) {  
                 len = snprintf(cp, glsize - (cp - gid_list), ",%u",  
                      (unsigned int) grlist->gids[i]);  
                 if (len < 0 || len >= glsize - (cp - gid_list))  
                     errorx(1, _("internal error, runas_groups overflow"));  
                 cp += len;  
             }  
         }  
         command_info[info_len++] = gid_list;  
         grlist_delref(grlist);  
     }  
     if (def_closefrom >= 0)  
         easprintf(&command_info[info_len++], "closefrom=%d", def_closefrom);  
     if (def_noexec)  
         command_info[info_len++] = estrdup("noexec=true");  
     if (def_set_utmp)  
         command_info[info_len++] = estrdup("set_utmp=true");  
     if (def_use_pty)  
         command_info[info_len++] = estrdup("use_pty=true");  
     if (def_utmp_runas)  
         command_info[info_len++] = fmt_string("utmp_user", runas_pw->pw_name);  
 #ifdef HAVE_LOGIN_CAP_H  
     if (def_use_loginclass)  
         command_info[info_len++] = fmt_string("login_class", login_class);  
 #endif /* HAVE_LOGIN_CAP_H */  
 #ifdef HAVE_SELINUX  
     if (user_role != NULL)  
         command_info[info_len++] = fmt_string("selinux_role", user_role);  
     if (user_type != NULL)  
         command_info[info_len++] = fmt_string("selinux_type", user_type);  
 #endif /* HAVE_SELINUX */  
   
     /* Must audit before uid change. */      /* Must audit before uid change. */
     audit_success(NewArgv);      audit_success(NewArgv);
   
    *command_infop = command_info;    /* Setup execution environment to pass back to front-end. */
     rval = sudoers_policy_exec_setup(edit_argv ? edit_argv : NewArgv,
         env_get(), cmnd_umask, iolog_path, closure);
   
    *argv_out = edit_argv ? edit_argv : NewArgv;    /* Zero out stashed copy of environment, it is owned by the front-end. */
 
    /* Get private version of the environment and zero out stashed copy. */ 
    *user_env_out = env_get(); 
     env_init(NULL);      env_init(NULL);
   
     goto done;      goto done;
Line 730  bad: Line 506  bad:
     rval = false;      rval = false;
   
 done:  done:
       fatal_disable_setjmp();
     rewind_perms();      rewind_perms();
   
     /* Close the password and group files and free up memory. */      /* Close the password and group files and free up memory. */
Line 739  done: Line 516  done:
     debug_return_bool(rval);      debug_return_bool(rval);
 }  }
   
 static int  
 sudoers_policy_check(int argc, char * const argv[], char *env_add[],  
     char **command_infop[], char **argv_out[], char **user_env_out[])  
 {  
     debug_decl(sudoers_policy_check, SUDO_DEBUG_PLUGIN)  
   
     if (!ISSET(sudo_mode, MODE_EDIT))  
         SET(sudo_mode, MODE_RUN);  
   
     debug_return_bool(sudoers_policy_main(argc, argv, 0, env_add, command_infop,  
         argv_out, user_env_out));  
 }  
   
 static int  
 sudoers_policy_validate(void)  
 {  
     debug_decl(sudoers_policy_validate, SUDO_DEBUG_PLUGIN)  
   
     user_cmnd = "validate";  
     SET(sudo_mode, MODE_VALIDATE);  
   
     debug_return_bool(sudoers_policy_main(0, NULL, I_VERIFYPW, NULL, NULL, NULL, NULL));  
 }  
   
 static void  
 sudoers_policy_invalidate(int remove)  
 {  
     debug_decl(sudoers_policy_invalidate, SUDO_DEBUG_PLUGIN)  
   
     user_cmnd = "kill";  
     if (sigsetjmp(error_jmp, 1) == 0) {  
         remove_timestamp(remove);  
         plugin_cleanup(0);  
     }  
   
     debug_return;  
 }  
   
 static int  
 sudoers_policy_list(int argc, char * const argv[], int verbose,  
     const char *list_user)  
 {  
     int rval;  
     debug_decl(sudoers_policy_list, SUDO_DEBUG_PLUGIN)  
   
     user_cmnd = "list";  
     if (argc)  
         SET(sudo_mode, MODE_CHECK);  
     else  
         SET(sudo_mode, MODE_LIST);  
     if (verbose)  
         long_list = 1;  
     if (list_user) {  
         list_pw = sudo_getpwnam(list_user);  
         if (list_pw == NULL) {  
             warningx(_("unknown user: %s"), list_user);  
             debug_return_bool(-1);  
         }  
     }  
     rval = sudoers_policy_main(argc, argv, I_LISTPW, NULL, NULL, NULL, NULL);  
     if (list_user) {  
         pw_delref(list_pw);  
         list_pw = NULL;  
     }  
   
     debug_return_bool(rval);  
 }  
   
 /*  /*
 * Initialize timezone, set umask, fill in ``sudo_user'' struct and * Initialize timezone and fill in ``sudo_user'' struct.
 * load the ``interfaces'' array. 
  */   */
 static void  static void
 init_vars(char * const envp[])  init_vars(char * const envp[])
Line 817  init_vars(char * const envp[]) Line 525  init_vars(char * const envp[])
     char * const * ep;      char * const * ep;
     debug_decl(init_vars, SUDO_DEBUG_PLUGIN)      debug_decl(init_vars, SUDO_DEBUG_PLUGIN)
   
#ifdef HAVE_TZSET    sudoers_initlocale(setlocale(LC_ALL, NULL), def_sudoers_locale);
    (void) tzset();             /* set the timezone if applicable */ 
#endif /* HAVE_TZSET */ 
   
     for (ep = envp; *ep; ep++) {      for (ep = envp; *ep; ep++) {
         /* XXX - don't fill in if empty string */          /* XXX - don't fill in if empty string */
Line 842  init_vars(char * const envp[]) Line 548  init_vars(char * const envp[])
     }      }
   
     /*      /*
     * Get a local copy of the user's struct passwd with the shadow password     * Get a local copy of the user's struct passwd if we don't already
     * if necessary.  It is assumed that euid is 0 at this point so we     * have one.
     * can read the shadow passwd file if necessary. 
      */       */
    if ((sudo_user.pw = sudo_getpwuid(user_uid)) == NULL) {    if (sudo_user.pw == NULL) {
        /*        if ((sudo_user.pw = sudo_getpwnam(user_name)) == NULL) {
         * It is not unusual for users to place "sudo -k" in a .logout            /*
         * file which can cause sudo to be run during reboot after the             * It is not unusual for users to place "sudo -k" in a .logout
         * YP/NIS/NIS+/LDAP/etc daemon has died.             * file which can cause sudo to be run during reboot after the
         */             * YP/NIS/NIS+/LDAP/etc daemon has died.
        if (sudo_mode == MODE_KILL || sudo_mode == MODE_INVALIDATE)             */
            errorx(1, _("unknown uid: %u"), (unsigned int) user_uid);            if (sudo_mode == MODE_KILL || sudo_mode == MODE_INVALIDATE)
                 fatalx(_("unknown uid: %u"), (unsigned int) user_uid);
   
        /* Need to make a fake struct passwd for the call to log_fatal(). */            /* Need to make a fake struct passwd for the call to log_fatal(). */
        sudo_user.pw = sudo_fakepwnamid(user_name, user_uid, user_gid);            sudo_user.pw = sudo_mkpwent(user_name, user_uid, user_gid, NULL, NULL);
        log_fatal(0, _("unknown uid: %u"), (unsigned int) user_uid);            log_fatal(0, N_("unknown uid: %u"), (unsigned int) user_uid);
        /* NOTREACHED */            /* NOTREACHED */
         }
     }      }
   
     /*      /*
      * Get group list.       * Get group list.
      */       */
     if (user_group_list == NULL)      if (user_group_list == NULL)
        user_group_list = get_group_list(sudo_user.pw);        user_group_list = sudo_get_grlist(sudo_user.pw);
   
     /* Set runas callback. */      /* Set runas callback. */
     sudo_defs_table[I_RUNAS_DEFAULT].callback = cb_runas_default;      sudo_defs_table[I_RUNAS_DEFAULT].callback = cb_runas_default;
   
       /* Set locale callback. */
       sudo_defs_table[I_SUDOERS_LOCALE].callback = cb_sudoers_locale;
   
       /* Set maxseq callback. */
       sudo_defs_table[I_MAXSEQ].callback = io_set_max_sessid;
   
     /* It is now safe to use log_fatal() and set_perms() */      /* It is now safe to use log_fatal() and set_perms() */
     debug_return;      debug_return;
 }  }
Line 938  set_cmnd(void) Line 651  set_cmnd(void)
                 for (to = user_args, av = NewArgv + 1; *av; av++) {                  for (to = user_args, av = NewArgv + 1; *av; av++) {
                     n = strlcpy(to, *av, size - (to - user_args));                      n = strlcpy(to, *av, size - (to - user_args));
                     if (n >= size - (to - user_args))                      if (n >= size - (to - user_args))
                        errorx(1, _("internal error, set_cmnd() overflow"));                        fatalx(_("internal error, %s overflow"), "set_cmnd()");
                     to += n;                      to += n;
                     *to++ = ' ';                      *to++ = ' ';
                 }                  }
Line 946  set_cmnd(void) Line 659  set_cmnd(void)
             }              }
         }          }
     }      }
    if (strlen(user_cmnd) >= PATH_MAX)    if (strlen(user_cmnd) >= PATH_MAX) {
        errorx(1, _("%s: %s"), user_cmnd, strerror(ENAMETOOLONG));        errno = ENAMETOOLONG;
         fatal("%s", user_cmnd);
     }
   
     if ((user_base = strrchr(user_cmnd, '/')) != NULL)      if ((user_base = strrchr(user_cmnd, '/')) != NULL)
         user_base++;          user_base++;
Line 955  set_cmnd(void) Line 670  set_cmnd(void)
         user_base = user_cmnd;          user_base = user_cmnd;
   
     if (!update_defaults(SETDEF_CMND))      if (!update_defaults(SETDEF_CMND))
        log_error(NO_STDERR, _("problem with defaults entries"));        log_warning(NO_STDERR, N_("problem with defaults entries"));
   
     debug_return_int(rval);      debug_return_int(rval);
 }  }
Line 975  open_sudoers(const char *sudoers, bool doedit, bool *k Line 690  open_sudoers(const char *sudoers, bool doedit, bool *k
   
     switch (sudo_secure_file(sudoers, sudoers_uid, sudoers_gid, &sb)) {      switch (sudo_secure_file(sudoers, sudoers_uid, sudoers_gid, &sb)) {
         case SUDO_PATH_SECURE:          case SUDO_PATH_SECURE:
               /*
                * If we are expecting sudoers to be group readable but
                * it is not, we must open the file as root, not uid 1.
                */
               if (sudoers_uid == ROOT_UID && (sudoers_mode & S_IRGRP)) {
                   if ((sb.st_mode & S_IRGRP) == 0) {
                       restore_perms();
                       set_perms(PERM_ROOT);
                   }
               }
               /*
                * Open sudoers and make sure we can read it so we can present
                * the user with a reasonable error message (unlike the lexer).
                */
             if ((fp = fopen(sudoers, "r")) == NULL) {              if ((fp = fopen(sudoers, "r")) == NULL) {
                log_error(USE_ERRNO, _("unable to open %s"), sudoers);                log_warning(USE_ERRNO, N_("unable to open %s"), sudoers);
             } else {              } else {
                 /*  
                  * Make sure we can actually read sudoers so we can present the  
                  * user with a reasonable error message (unlike the lexer).  
                  */  
                 if (sb.st_size != 0 && fgetc(fp) == EOF) {                  if (sb.st_size != 0 && fgetc(fp) == EOF) {
                    log_error(USE_ERRNO, _("unable to read %s"),                    log_warning(USE_ERRNO, N_("unable to read %s"),
                         sudoers);                          sudoers);
                     fclose(fp);                      fclose(fp);
                     fp = NULL;                      fp = NULL;
Line 995  open_sudoers(const char *sudoers, bool doedit, bool *k Line 720  open_sudoers(const char *sudoers, bool doedit, bool *k
             }              }
             break;              break;
         case SUDO_PATH_MISSING:          case SUDO_PATH_MISSING:
            log_error(USE_ERRNO, _("unable to stat %s"), sudoers);            log_warning(USE_ERRNO, N_("unable to stat %s"), sudoers);
             break;              break;
         case SUDO_PATH_BAD_TYPE:          case SUDO_PATH_BAD_TYPE:
            log_error(0, _("%s is not a regular file"), sudoers);            log_warning(0, N_("%s is not a regular file"), sudoers);
             break;              break;
         case SUDO_PATH_WRONG_OWNER:          case SUDO_PATH_WRONG_OWNER:
            log_error(0, _("%s is owned by uid %u, should be %u"),            log_warning(0, N_("%s is owned by uid %u, should be %u"),
                 sudoers, (unsigned int) sb.st_uid, (unsigned int) sudoers_uid);                  sudoers, (unsigned int) sb.st_uid, (unsigned int) sudoers_uid);
             break;              break;
         case SUDO_PATH_WORLD_WRITABLE:          case SUDO_PATH_WORLD_WRITABLE:
            log_error(0, _("%s is world writable"), sudoers);            log_warning(0, N_("%s is world writable"), sudoers);
             break;              break;
         case SUDO_PATH_GROUP_WRITABLE:          case SUDO_PATH_GROUP_WRITABLE:
            log_error(0, _("%s is owned by gid %u, should be %u"),            log_warning(0, N_("%s is owned by gid %u, should be %u"),
                 sudoers, (unsigned int) sb.st_gid, (unsigned int) sudoers_gid);                  sudoers, (unsigned int) sb.st_gid, (unsigned int) sudoers_gid);
             break;              break;
         default:          default:
Line 1035  set_loginclass(struct passwd *pw) Line 760  set_loginclass(struct passwd *pw)
     if (login_class && strcmp(login_class, "-") != 0) {      if (login_class && strcmp(login_class, "-") != 0) {
         if (user_uid != 0 &&          if (user_uid != 0 &&
             strcmp(runas_user ? runas_user : def_runas_default, "root") != 0)              strcmp(runas_user ? runas_user : def_runas_default, "root") != 0)
            errorx(1, _("only root can use `-c %s'"), login_class);            fatalx(_("only root can use `-c %s'"), login_class);
     } else {      } else {
         login_class = pw->pw_class;          login_class = pw->pw_class;
         if (!login_class || !*login_class)          if (!login_class || !*login_class)
Line 1052  set_loginclass(struct passwd *pw) Line 777  set_loginclass(struct passwd *pw)
          * corrupted we want the admin to be able to use sudo to fix it.           * corrupted we want the admin to be able to use sudo to fix it.
          */           */
         if (login_class)          if (login_class)
            log_fatal(errflags, _("unknown login class: %s"), login_class);            log_fatal(errflags, N_("unknown login class: %s"), login_class);
         else          else
            log_error(errflags, _("unknown login class: %s"), login_class);            log_warning(errflags, N_("unknown login class: %s"), login_class);
         def_use_loginclass = false;          def_use_loginclass = false;
     }      }
     login_close(lc);      login_close(lc);
Line 1067  set_loginclass(struct passwd *pw) Line 792  set_loginclass(struct passwd *pw)
 }  }
 #endif /* HAVE_LOGIN_CAP_H */  #endif /* HAVE_LOGIN_CAP_H */
   
   #ifndef AI_FQDN
   # define AI_FQDN AI_CANONNAME
   #endif
   
 /*  /*
  * Look up the fully qualified domain name and set user_host and user_shost.   * Look up the fully qualified domain name and set user_host and user_shost.
    * Use AI_FQDN if available since "canonical" is not always the same as fqdn.
  */   */
voidstatic void
 set_fqdn(void)  set_fqdn(void)
 {  {
     struct addrinfo *res0, hint;      struct addrinfo *res0, hint;
Line 1079  set_fqdn(void) Line 809  set_fqdn(void)
   
     zero_bytes(&hint, sizeof(hint));      zero_bytes(&hint, sizeof(hint));
     hint.ai_family = PF_UNSPEC;      hint.ai_family = PF_UNSPEC;
    hint.ai_flags = AI_CANONNAME;    hint.ai_flags = AI_FQDN;
     if (getaddrinfo(user_host, NULL, &hint, &res0) != 0) {      if (getaddrinfo(user_host, NULL, &hint, &res0) != 0) {
        log_error(MSG_ONLY, _("unable to resolve host %s"), user_host);        log_warning(MSG_ONLY, N_("unable to resolve host %s"), user_host);
     } else {      } else {
         if (user_shost != user_host)          if (user_shost != user_host)
             efree(user_shost);              efree(user_shost);
         efree(user_host);          efree(user_host);
         user_host = estrdup(res0->ai_canonname);          user_host = estrdup(res0->ai_canonname);
         freeaddrinfo(res0);          freeaddrinfo(res0);
           if ((p = strchr(user_host, '.')) != NULL)
               user_shost = estrndup(user_host, (size_t)(p - user_host));
           else
               user_shost = user_host;
     }      }
     if ((p = strchr(user_host, '.')) != NULL)  
         user_shost = estrndup(user_host, (size_t)(p - user_host));  
     else  
         user_shost = user_host;  
     debug_return;      debug_return;
 }  }
   
Line 1106  set_runaspw(const char *user) Line 836  set_runaspw(const char *user)
     debug_decl(set_runaspw, SUDO_DEBUG_PLUGIN)      debug_decl(set_runaspw, SUDO_DEBUG_PLUGIN)
   
     if (runas_pw != NULL)      if (runas_pw != NULL)
        pw_delref(runas_pw);        sudo_pw_delref(runas_pw);
     if (*user == '#') {      if (*user == '#') {
         if ((runas_pw = sudo_getpwuid(atoi(user + 1))) == NULL)          if ((runas_pw = sudo_getpwuid(atoi(user + 1))) == NULL)
             runas_pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0);              runas_pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0);
     } else {      } else {
         if ((runas_pw = sudo_getpwnam(user)) == NULL)          if ((runas_pw = sudo_getpwnam(user)) == NULL)
            log_fatal(NO_MAIL|MSG_ONLY, _("unknown user: %s"), user);            log_fatal(NO_MAIL|MSG_ONLY, N_("unknown user: %s"), user);
     }      }
     debug_return;      debug_return;
 }  }
Line 1127  set_runasgr(const char *group) Line 857  set_runasgr(const char *group)
     debug_decl(set_runasgr, SUDO_DEBUG_PLUGIN)      debug_decl(set_runasgr, SUDO_DEBUG_PLUGIN)
   
     if (runas_gr != NULL)      if (runas_gr != NULL)
        gr_delref(runas_gr);        sudo_gr_delref(runas_gr);
     if (*group == '#') {      if (*group == '#') {
         if ((runas_gr = sudo_getgrgid(atoi(group + 1))) == NULL)          if ((runas_gr = sudo_getgrgid(atoi(group + 1))) == NULL)
             runas_gr = sudo_fakegrnam(group);              runas_gr = sudo_fakegrnam(group);
     } else {      } else {
         if ((runas_gr = sudo_getgrnam(group)) == NULL)          if ((runas_gr = sudo_getgrnam(group)) == NULL)
            log_fatal(NO_MAIL|MSG_ONLY, _("unknown group: %s"), group);            log_fatal(NO_MAIL|MSG_ONLY, N_("unknown group: %s"), group);
     }      }
     debug_return;      debug_return;
 }  }
Line 1151  cb_runas_default(const char *user) Line 881  cb_runas_default(const char *user)
 }  }
   
 /*  /*
 * Cleanup hook for error()/errorx() * Callback for sudoers_locale sudoers setting.
  */   */
 void  
 plugin_cleanup(int gotsignal)  
 {  
     struct sudo_nss *nss;  
   
     if (!gotsignal) {  
         debug_decl(plugin_cleanup, SUDO_DEBUG_PLUGIN)  
         if (snl != NULL) {  
             tq_foreach_fwd(snl, nss)  
                 nss->close(nss);  
         }  
         if (def_group_plugin)  
             group_plugin_unload();  
         sudo_endpwent();  
         sudo_endgrent();  
         debug_return;  
     }  
 }  
   
 static int  static int
sudoers_policy_version(int verbose)cb_sudoers_locale(const char *locale)
 {  {
    debug_decl(sudoers_policy_version, SUDO_DEBUG_PLUGIN)    sudoers_initlocale(NULL, locale);
    return true;
    if (sigsetjmp(error_jmp, 1)) { 
        /* error recovery via error(), errorx() or log_fatal() */ 
        debug_return_bool(-1); 
    } 
 
    sudo_printf(SUDO_CONV_INFO_MSG, _("Sudoers policy plugin version %s\n"), 
        PACKAGE_VERSION); 
    sudo_printf(SUDO_CONV_INFO_MSG, _("Sudoers file grammar version %d\n"), 
        SUDOERS_GRAMMAR_VERSION); 
 
    if (verbose) { 
        sudo_printf(SUDO_CONV_INFO_MSG, _("\nSudoers path: %s\n"), sudoers_file); 
#ifdef HAVE_LDAP 
# ifdef _PATH_NSSWITCH_CONF 
        sudo_printf(SUDO_CONV_INFO_MSG, _("nsswitch path: %s\n"), _PATH_NSSWITCH_CONF); 
# endif 
        sudo_printf(SUDO_CONV_INFO_MSG, _("ldap.conf path: %s\n"), _PATH_LDAP_CONF); 
        sudo_printf(SUDO_CONV_INFO_MSG, _("ldap.secret path: %s\n"), _PATH_LDAP_SECRET); 
#endif 
        dump_auth_methods(); 
        dump_defaults(); 
        sudo_printf(SUDO_CONV_INFO_MSG, "\n"); 
        if (interfaces_string != NULL) { 
            dump_interfaces(interfaces_string); 
            sudo_printf(SUDO_CONV_INFO_MSG, "\n"); 
        } 
    } 
    debug_return_bool(true); 
 }  }
   
static int/*
deserialize_info(char * const args[], char * const settings[], char * const user_info[]) * Cleanup hook for fatal()/fatalx()
  */
 void
 sudoers_cleanup(void)
 {  {
    char * const *cur;    struct sudo_nss *nss;
    const char *p, *groups = NULL;    debug_decl(sudoers_cleanup, SUDO_DEBUG_PLUGIN)
    const char *debug_flags = NULL; 
    int flags = 0; 
    debug_decl(deserialize_info, SUDO_DEBUG_PLUGIN) 
   
#define MATCHES(s, v) (strncmp(s, v, sizeof(v) - 1) == 0)    if (snl != NULL) {
        tq_foreach_fwd(snl, nss)
    /* Parse sudo.conf plugin args. */            nss->close(nss);
    if (args != NULL) { 
        for (cur = args; *cur != NULL; cur++) { 
            if (MATCHES(*cur, "sudoers_file=")) { 
                sudoers_file = *cur + sizeof("sudoers_file=") - 1; 
                continue; 
            } 
            if (MATCHES(*cur, "sudoers_uid=")) { 
                sudoers_uid = (uid_t) atoi(*cur + sizeof("sudoers_uid=") - 1); 
                continue; 
            } 
            if (MATCHES(*cur, "sudoers_gid=")) { 
                sudoers_gid = (gid_t) atoi(*cur + sizeof("sudoers_gid=") - 1); 
                continue; 
            } 
            if (MATCHES(*cur, "sudoers_mode=")) { 
                sudoers_mode = (mode_t) strtol(*cur + sizeof("sudoers_mode=") - 1, 
                    NULL, 8); 
                continue; 
            } 
        } 
     }      }
       if (def_group_plugin)
           group_plugin_unload();
       sudo_endpwent();
       sudo_endgrent();
   
    /* Parse command line settings. */    debug_return;
    user_closefrom = -1; 
    for (cur = settings; *cur != NULL; cur++) { 
        if (MATCHES(*cur, "closefrom=")) { 
            user_closefrom = atoi(*cur + sizeof("closefrom=") - 1); 
            continue; 
        } 
        if (MATCHES(*cur, "debug_flags=")) { 
            debug_flags = *cur + sizeof("debug_flags=") - 1; 
            continue; 
        } 
        if (MATCHES(*cur, "runas_user=")) { 
            runas_user = *cur + sizeof("runas_user=") - 1; 
            continue; 
        } 
        if (MATCHES(*cur, "runas_group=")) { 
            runas_group = *cur + sizeof("runas_group=") - 1; 
            continue; 
        } 
        if (MATCHES(*cur, "prompt=")) { 
            user_prompt = *cur + sizeof("prompt=") - 1; 
            def_passprompt_override = true; 
            continue; 
        } 
        if (MATCHES(*cur, "set_home=")) { 
            if (atobool(*cur + sizeof("set_home=") - 1) == true) 
                SET(flags, MODE_RESET_HOME); 
            continue; 
        } 
        if (MATCHES(*cur, "preserve_environment=")) { 
            if (atobool(*cur + sizeof("preserve_environment=") - 1) == true) 
                SET(flags, MODE_PRESERVE_ENV); 
            continue; 
        } 
        if (MATCHES(*cur, "run_shell=")) { 
            if (atobool(*cur + sizeof("run_shell=") - 1) == true) 
                SET(flags, MODE_SHELL); 
            continue; 
        } 
        if (MATCHES(*cur, "login_shell=")) { 
            if (atobool(*cur + sizeof("login_shell=") - 1) == true) { 
                SET(flags, MODE_LOGIN_SHELL); 
                def_env_reset = true; 
            } 
            continue; 
        } 
        if (MATCHES(*cur, "implied_shell=")) { 
            if (atobool(*cur + sizeof("implied_shell=") - 1) == true) 
                SET(flags, MODE_IMPLIED_SHELL); 
            continue; 
        } 
        if (MATCHES(*cur, "preserve_groups=")) { 
            if (atobool(*cur + sizeof("preserve_groups=") - 1) == true) 
                SET(flags, MODE_PRESERVE_GROUPS); 
            continue; 
        } 
        if (MATCHES(*cur, "ignore_ticket=")) { 
            if (atobool(*cur + sizeof("ignore_ticket=") - 1) == true) 
                SET(flags, MODE_IGNORE_TICKET); 
            continue; 
        } 
        if (MATCHES(*cur, "noninteractive=")) { 
            if (atobool(*cur + sizeof("noninteractive=") - 1) == true) 
                SET(flags, MODE_NONINTERACTIVE); 
            continue; 
        } 
        if (MATCHES(*cur, "sudoedit=")) { 
            if (atobool(*cur + sizeof("sudoedit=") - 1) == true) 
                SET(flags, MODE_EDIT); 
            continue; 
        } 
        if (MATCHES(*cur, "login_class=")) { 
            login_class = *cur + sizeof("login_class=") - 1; 
            def_use_loginclass = true; 
            continue; 
        } 
#ifdef HAVE_SELINUX 
        if (MATCHES(*cur, "selinux_role=")) { 
            user_role = *cur + sizeof("selinux_role=") - 1; 
            continue; 
        } 
        if (MATCHES(*cur, "selinux_type=")) { 
            user_type = *cur + sizeof("selinux_type=") - 1; 
            continue; 
        } 
#endif /* HAVE_SELINUX */ 
#ifdef HAVE_BSD_AUTH_H 
        if (MATCHES(*cur, "bsdauth_type=")) { 
            login_style = *cur + sizeof("bsdauth_type=") - 1; 
            continue; 
        } 
#endif /* HAVE_BSD_AUTH_H */ 
#if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME) 
        if (MATCHES(*cur, "progname=")) { 
            setprogname(*cur + sizeof("progname=") - 1); 
            continue; 
        } 
#endif 
        if (MATCHES(*cur, "network_addrs=")) { 
            interfaces_string = *cur + sizeof("network_addrs=") - 1; 
            set_interfaces(interfaces_string); 
            continue; 
        } 
    } 
 
    for (cur = user_info; *cur != NULL; cur++) { 
        if (MATCHES(*cur, "user=")) { 
            user_name = estrdup(*cur + sizeof("user=") - 1); 
            continue; 
        } 
        if (MATCHES(*cur, "uid=")) { 
            user_uid = (uid_t) atoi(*cur + sizeof("uid=") - 1); 
            continue; 
        } 
        if (MATCHES(*cur, "gid=")) { 
            p = *cur + sizeof("gid=") - 1; 
            user_gid = (gid_t) atoi(p); 
            continue; 
        } 
        if (MATCHES(*cur, "groups=")) { 
            groups = *cur + sizeof("groups=") - 1; 
            continue; 
        } 
        if (MATCHES(*cur, "cwd=")) { 
            user_cwd = estrdup(*cur + sizeof("cwd=") - 1); 
            continue; 
        } 
        if (MATCHES(*cur, "tty=")) { 
            user_tty = user_ttypath = estrdup(*cur + sizeof("tty=") - 1); 
            if (strncmp(user_tty, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 
                user_tty += sizeof(_PATH_DEV) - 1; 
            continue; 
        } 
        if (MATCHES(*cur, "host=")) { 
            user_host = user_shost = estrdup(*cur + sizeof("host=") - 1); 
            if ((p = strchr(user_host, '.'))) 
                user_shost = estrndup(user_host, (size_t)(p - user_host)); 
            continue; 
        } 
        if (MATCHES(*cur, "lines=")) { 
            sudo_user.lines = atoi(*cur + sizeof("lines=") - 1); 
            continue; 
        } 
        if (MATCHES(*cur, "cols=")) { 
            sudo_user.cols = atoi(*cur + sizeof("cols=") - 1); 
            continue; 
        } 
    } 
    if (user_cwd == NULL) 
        user_cwd = "unknown"; 
    if (user_tty == NULL) 
        user_tty = "unknown"; /* user_ttypath remains NULL */ 
 
    if (groups != NULL && groups[0] != '\0') { 
        const char *cp; 
        GETGROUPS_T *gids; 
        int ngids; 
 
        /* Count number of groups, including passwd gid. */ 
        ngids = 2; 
        for (cp = groups; *cp != '\0'; cp++) { 
            if (*cp == ',') 
                ngids++; 
        } 
 
        /* The first gid in the list is the passwd group gid. */ 
        gids = emalloc2(ngids, sizeof(GETGROUPS_T)); 
        gids[0] = user_gid; 
        ngids = 1; 
        cp = groups; 
        for (;;) { 
            gids[ngids] = atoi(cp); 
            if (gids[0] != gids[ngids]) 
                ngids++; 
            cp = strchr(cp, ','); 
            if (cp == NULL) 
                break; 
            cp++; /* skip over comma */ 
        } 
        set_group_list(user_name, gids, ngids); 
        efree(gids); 
    } 
 
    /* Setup debugging if indicated. */ 
    if (debug_flags != NULL) { 
        sudo_debug_init(NULL, debug_flags); 
        for (cur = settings; *cur != NULL; cur++) 
            sudo_debug_printf(SUDO_DEBUG_INFO, "settings: %s", *cur); 
        for (cur = user_info; *cur != NULL; cur++) 
            sudo_debug_printf(SUDO_DEBUG_INFO, "user_info: %s", *cur); 
    } 
 
#undef MATCHES 
    debug_return_int(flags); 
 }  }
   
 static char *  static char *
resolve_editor(char *editor, int nfiles, char **files, char ***argv_out)resolve_editor(const char *ed, size_t edlen, int nfiles, char **files, char ***argv_out)
 {  {
    char *cp, **nargv, *editor_path = NULL;    char *cp, **nargv, *editor, *editor_path = NULL;
     int ac, i, nargc;      int ac, i, nargc;
     bool wasblank;      bool wasblank;
     debug_decl(resolve_editor, SUDO_DEBUG_PLUGIN)      debug_decl(resolve_editor, SUDO_DEBUG_PLUGIN)
   
    editor = estrdup(editor); /* becomes part of argv_out */    /* Note: editor becomes part of argv_out and is not freed. */
     editor = emalloc(edlen + 1);
     memcpy(editor, ed, edlen);
     editor[edlen] = '\0';
   
     /*      /*
      * Split editor into an argument vector; editor is reused (do not free).       * Split editor into an argument vector; editor is reused (do not free).
Line 1490  resolve_editor(char *editor, int nfiles, char **files, Line 967  resolve_editor(char *editor, int nfiles, char **files,
 static char *  static char *
 find_editor(int nfiles, char **files, char ***argv_out)  find_editor(int nfiles, char **files, char ***argv_out)
 {  {
    char *cp, *editor, *editor_path = NULL, **ev, *ev0[4];    const char *cp, *ep, *editor;
     char *editor_path = NULL, **ev, *ev0[4];
     size_t len;
     debug_decl(find_editor, SUDO_DEBUG_PLUGIN)      debug_decl(find_editor, SUDO_DEBUG_PLUGIN)
   
     /*      /*
Line 1500  find_editor(int nfiles, char **files, char ***argv_out Line 979  find_editor(int nfiles, char **files, char ***argv_out
     ev0[1] = "VISUAL";      ev0[1] = "VISUAL";
     ev0[2] = "EDITOR";      ev0[2] = "EDITOR";
     ev0[3] = NULL;      ev0[3] = NULL;
    for (ev = ev0; *ev != NULL; ev++) {    for (ev = ev0; editor_path == NULL && *ev != NULL; ev++) {
         if ((editor = getenv(*ev)) != NULL && *editor != '\0') {          if ((editor = getenv(*ev)) != NULL && *editor != '\0') {
            editor_path = resolve_editor(editor, nfiles, files, argv_out);            editor_path = resolve_editor(editor, strlen(editor), nfiles,
            if (editor_path != NULL)                files, argv_out);
                break; 
         }          }
     }      }
     if (editor_path == NULL) {      if (editor_path == NULL) {
        /* def_editor could be a path, split it up */        /* def_editor could be a path, split it up, avoiding strtok() */
        editor = estrdup(def_editor);        cp = editor = def_editor;
        cp = strtok(editor, ":");        do {
        while (cp != NULL && editor_path == NULL) {            if ((ep = strchr(cp, ':')) != NULL)
            editor_path = resolve_editor(cp, nfiles, files, argv_out);                len = ep - cp;
            cp = strtok(NULL, ":");            else
        }                len = strlen(cp);
        if (editor_path)            editor_path = resolve_editor(cp, len, nfiles, files, argv_out);
            efree(editor);            cp = ep + 1;
         } while (ep != NULL && editor_path == NULL);
     }      }
     if (!editor_path) {      if (!editor_path) {
        audit_failure(NewArgv, _("%s: command not found"), editor);        audit_failure(NewArgv, N_("%s: command not found"), editor);
         warningx(_("%s: command not found"), editor);          warningx(_("%s: command not found"), editor);
     }      }
     debug_return_str(editor_path);      debug_return_str(editor_path);
Line 1561  create_admin_success_flag(void) Line 1040  create_admin_success_flag(void)
 }  }
 #endif /* USE_ADMIN_FLAG */  #endif /* USE_ADMIN_FLAG */
   
static voidstatic bool
sudoers_policy_register_hooks(int version, int (*register_hook)(struct sudo_hook *hook))tty_present(void)
 {  {
    struct sudo_hook hook;#if defined(HAVE_STRUCT_KINFO_PROC2_P_TDEV) || defined(HAVE_STRUCT_KINFO_PROC_P_TDEV) || defined(HAVE_STRUCT_KINFO_PROC_KI_TDEV) || defined(HAVE_STRUCT_KINFO_PROC_KP_EPROC_E_TDEV) || defined(HAVE_STRUCT_PSINFO_PR_TTYDEV) || defined(HAVE_PSTAT_GETPROC) || defined(__linux__)
    return user_ttypath != NULL;
    memset(&hook, 0, sizeof(hook));#else
    hook.hook_version = SUDO_HOOK_VERSION;    int fd = open(_PATH_TTY, O_RDWR|O_NOCTTY);
    if (fd != -1)
    hook.hook_type = SUDO_HOOK_SETENV;        close(fd);
    hook.hook_fn = sudoers_hook_setenv;    return fd != -1;
    register_hook(&hook);#endif
 
    hook.hook_type = SUDO_HOOK_UNSETENV; 
    hook.hook_fn = sudoers_hook_unsetenv; 
    register_hook(&hook); 
 
    hook.hook_type = SUDO_HOOK_GETENV; 
    hook.hook_fn = sudoers_hook_getenv; 
    register_hook(&hook); 
 
    hook.hook_type = SUDO_HOOK_PUTENV; 
    hook.hook_fn = sudoers_hook_putenv; 
    register_hook(&hook); 
 }  }
   
 struct policy_plugin sudoers_policy = {  
     SUDO_POLICY_PLUGIN,  
     SUDO_API_VERSION,  
     sudoers_policy_open,  
     sudoers_policy_close,  
     sudoers_policy_version,  
     sudoers_policy_check,  
     sudoers_policy_list,  
     sudoers_policy_validate,  
     sudoers_policy_invalidate,  
     sudoers_policy_init_session,  
     sudoers_policy_register_hooks  
 };  

Removed from v.1.1.1.2  
changed lines
  Added in v.1.1.1.4


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>