Text   |  XML   |  ReML   |   Visible Warnings:

File System Race Condition  at eacces-error.c:34

No properties have been set. | edit properties
Jump to warning location ↓ warning details...
Show Events | Options

create_mail_process

(/home/sate/Testcases/c/cve/dovecot-1.2.0/src/master/mail-process.c)expand/collapse
Show more  
 551  create_mail_process(enum process_type process_type, struct settings *set,
 552                      const struct  *request,
 553                      const char *user, const char *const *args,
 554                      const unsigned char *data, bool dump_capability,
 555                      pid_t *pid_r)
 556  {
 557          const struct var_expand_table *var_expand_table;
 558          const char *p, *addr, *mail, *chroot_dir, *home_dir, *full_home_dir;
 559          const char *system_groups_user, *master_user;
 560          struct mail_process_group *process_group;
 561          char title[1024];
 562          struct log_io *log;
 563          string_t *str;
 564          pid_t pid;
 565          uid_t uid;
 566          gid_t gid;
 567          ARRAY_DEFINE(extra_args, const char *);
 568          unsigned int i, len, count, left, process_count, throttle;
 569          int ret, log_fd, nice_value, chdir_errno;
 570          bool home_given, nfs_check;
 571   
 572          i_assert(process_type == PROCESS_TYPE_IMAP ||
 573                   process_type == PROCESS_TYPE_POP3);
 574   
 575          if (mail_process_count == set->max_mail_processes) {
 576                  i_error("Maximum number of mail processes exceeded "
 577                          "(see max_mail_processes setting)");
 578                  return ;
 579          }
 580   
 581          t_array_init(&extra_args, 16);
 582          mail = home_dir = chroot_dir = system_groups_user = "";
 583          master_user = NULL;
 584          uid = (uid_t)-1; gid = (gid_t)-1; nice_value = 0;
 585          home_given = FALSE;
 586          for (; *args != NULL; args++) {
 587                  if (strncmp(*args, "home=", 5) == 0) {
 588                          home_dir = *args + 5;
 589                          home_given = TRUE;
 590                  } else if (strncmp(*args, "mail=", 5) == 0)
 591                          mail = *args + 5;
 592                  else if (strncmp(*args, "chroot=", 7) == 0)
 593                          chroot_dir = *args + 7;
 594                  else if (strncmp(*args, "nice=", 5) == 0)
 595                          nice_value = atoi(*args + 5);
 596                  else if (strncmp(*args, "system_groups_user=", 19) == 0)
 597                          system_groups_user = *args + 19;
 598                  else if (strncmp(*args, "uid=", 4) == 0) {
 599                          if (uid != (uid_t)-1) {
 600                                  i_error("uid specified multiple times for %s",
 601                                          user);
 602                                  return ;
 603                          }
 604                          uid = (uid_t)strtoul(*args + 4, NULL, 10);
 605                  } else if (strncmp(*args, "gid=", 4) == 0) {
 606                          gid = (gid_t)strtoul(*args + 4, NULL, 10);
 607                  } else if (strncmp(*args, "master_user=", 12) == 0) {
 608                          const char *arg = *args;
 609   
 610                          master_user = arg + 12;
 611                          array_append(&extra_args, &arg, 1);
 612                  } else {
 613                          const char *arg = *args;
 614                          array_append(&extra_args, &arg, 1);
 615                  }
 616          }
 617   
 618          /* check process limit for this user, but not if this is a master 
 619             user . */
 620          process_group = dump_capability ? NULL :
 621                  mail_process_group_lookup(process_type, user,
 622                                            &request->remote_ip);
 623          process_count = process_group == NULL ? 0 :
 624                  array_count(&process_group->processes);
 625          if (process_count >= set->mail_max_userip_connections &&
 626              set->mail_max_userip_connections != 0 &&
 627              master_user == NULL)
 628                  return ;
 629   
 630          /* if uid/gid wasn't returned, use the defaults */
 631          if (uid == (uid_t)-1) {
 632                  uid = set->mail_uid_t;
 633                  if (uid == (uid_t)-1) {
 634                          i_error("User %s is missing UID (see mail_uid setting)",
 635                                  user);
 636                          return ;
 637                  }
 638          }
 639          if (gid == (gid_t)-1) {
 640                  gid = set->mail_gid_t;
 641                  if (gid == (gid_t)-1) {
 642                          i_error("User %s is missing GID (see mail_gid setting)",
 643                                  user);
 644                          return ;
 645                  }
 646          }
 647   
 648          if (*chroot_dir == '\0' && *set->valid_chroot_dirs != '\0' &&
 649              (p = strstr(home_dir, "/./")) != NULL) {
 650                  /* wu-ftpd like <chroot>/./<home> - check only if there's even 
 651                     a possibility of using them (non-empty valid_chroot_dirs)*/
 652                  chroot_dir = t_strdup_until(home_dir, p);
 653                  home_dir = p + 2;
 654          } else if (*chroot_dir != '\0' && *home_dir != '/') {
 655                  /* home directories should never be relative, but force this 
 656                     with chroots. */
 657                  home_dir = t_strconcat("/", home_dir, NULL);
 658          }
 659   
 660          if (!dump_capability) {
 661[+]                 if (!validate_uid_gid(set, uid, gid, user))
 662                          return ;
 663          }
 664   
 665          if (*chroot_dir != '\0') {
 666                  if (!validate_chroot(set, chroot_dir)) {
 667                          i_error("Invalid chroot directory '%s' (user %s) "
 668                                  "(see valid_chroot_dirs setting)",
 669                                  chroot_dir, user);
 670                          return ;
 671                  }
 672          } else if (*set->mail_chroot != '\0') {
 673                  /* mail_chroot setting's value doesn't need to be in
 674                     valid_chroot_dirs. */
 675                  chroot_dir = set->mail_chroot;
 676          }
 677          if (*chroot_dir != '\0' && set->mail_drop_priv_before_exec) {
 678                  i_error("Can't chroot to directory '%s' (user %s) "
 679                          "with mail_drop_priv_before_exec=yes",
 680                          chroot_dir, user);
 681                  return ;
 682          }
 683          len = strlen(chroot_dir);
 684          if (len > 2 && strcmp(chroot_dir + len - 2, "/.") == 0 &&
 685              strncmp(home_dir, chroot_dir, len - 2) == 0) {
 686                  /* strip chroot dir from home dir */
 687                  home_dir += len - 2;
 688          }
 689   
 690          if (!dump_capability) {
 691                  throttle = set->mail_debug ? 0 :
 692                          set->mail_log_max_lines_per_sec;
 693[+]                 log_fd = log_create_pipe(&log, throttle);
 694                  if (log_fd == -1)
 695                          return ;
 696          } else {
 697                  log = NULL;
 698                  log_fd = dup(STDERR_FILENO);
 699                  if (log_fd == -1) {
 700                          i_error("dup() failed: %m");
 701                          return ;
 702                  }
 703                  fd_close_on_exec(log_fd, TRUE);
 704          }
 705   
 706          /* See if we need to do the initial NFS check. We want to do this only
 707             once, so the check code needs to be before fork(). */
 708          if (set->nfs_check && !set->mail_nfs_index && !dump_capability) {
 709                  set->nfs_check = FALSE;
 710                  nfs_check = TRUE;
 711          } else {
 712                  nfs_check = FALSE;
 713          }
 714   
 715          pid = fork();
 716          if (pid < 0) {
 717                  i_error("fork() failed: %m");
 718                  (void)close(log_fd);
 719                  return ;
 720          }
 721   
 722          var_expand_table =
 723                  get_var_expand_table(process_names[process_type],
 724                                       user, home_given ? home_dir : NULL,
 725                                       net_ip2addr(&request->local_ip),
 726                                       net_ip2addr(&request->remote_ip),
 727                                       pid != 0 ? pid : getpid(), uid);
 728          str = t_str_new(128);
 729   
 730          if (pid != 0) {
 731                  /* master */
 732                  var_expand(str, set->mail_log_prefix, var_expand_table);
 733   
 734                  if (!dump_capability) {
 735                          log_set_prefix(log, str_c(str));
 736                          log_set_pid(log, pid);
 737                          if (process_group == NULL) {
 738                                  process_group = mail_process_group_create(
 739                                                          process_type, user,
 740                                                          &request->remote_ip);
 741                          }
 742                          mail_process_group_add(process_group, pid);
 743                  }
 744                  (void)close(log_fd);
 745                  *pid_r = pid;
 746                  return ;
 747          }
 748   
 749  #ifdef HAVE_SETPRIORITY 
 750          if (nice_value != 0) {
 751                  if (setpriority(PRIO_PROCESS, 0, nice_value) < 0)
 752                          i_error("setpriority(%d) failed: %m", nice_value);
 753          }
 754  #endif
 755   
 756          if (!dump_capability) {
 757                  str_append(str, "master-");
 758                  var_expand(str, set->mail_log_prefix, var_expand_table);
 759                  log_set_prefix(log, str_c(str));
 760          }
 761   
 762          child_process_init_env();
 763   
 764          /* setup environment - set the most important environment first
 765             (paranoia about filling up environment without noticing) */
 766          restrict_access_set_env(system_groups_user, uid, gid,
 767                                  set->mail_priv_gid_t,
 768                                  dump_capability ? "" : chroot_dir,
 769                                  set->first_valid_gid, set->last_valid_gid,
 770                                  set->mail_access_groups);
 771   
 772          restrict_process_size(set->mail_process_size, (unsigned int)-1);
 773   
 774          if (dump_capability)
 775                  env_put("DUMP_CAPABILITY=1");
 776   
 777          if ((*home_dir == '\0' && *chroot_dir == '\0') || dump_capability) {
 778                  full_home_dir = "";
 779                  ret = -1;
 780          } else {
 781                  full_home_dir = *chroot_dir == '\0' ? home_dir :
 782[+]                         t_strconcat(chroot_dir, home_dir, NULL);
 783                  /* NOTE: if home directory is NFS-mounted, we might not 
 784                     have access to it as root. Change the effective UID and GID
 785                     temporarily to make it work. */
 786                  if (uid != master_uid) {
 787                          if (setegid(gid) < 0)
 788                                  i_fatal("setegid(%s) failed: %m", dec2str(gid));
 789                          if (seteuid(uid) < 0)
 790                                  i_fatal("seteuid(%s) failed: %m", dec2str(uid));
 791                  }
 792   
 793                  alarm(CHDIR_TIMEOUT);
 794                  ret = chdir(full_home_dir);
 795                  chdir_errno = errno;
 796                  if ((left = alarm(0)) < CHDIR_TIMEOUT - CHDIR_WARN_SECS) {
 797                          i_warning("chdir(%s) blocked for %u secs",
 798                                    full_home_dir, CHDIR_TIMEOUT - left);
 799                  }
 800   
 801                  /* Change UID back. No need to change GID back, it doesn't
 802                     really matter. */
 803                  if (uid != master_uid && seteuid(master_uid) < 0)
 804                          i_fatal("seteuid(%s) failed: %m", dec2str(master_uid));
 805   
 806                  /* If user's home directory doesn't exist and we're not 
 807                     trying to chroot anywhere, fallback to /tmp as the mails 
 808                     could be stored elsewhere. The ENOTDIR check is mostly for
 809                     /dev/null home directory. */
 810                  if (ret < 0 && (*chroot_dir != '\0' ||
 811                                  !(ENOTFOUND(chdir_errno) ||
 812                                    chdir_errno == EINTR))) {
 813                          errno = chdir_errno;
 814                          if (errno != EACCES) {
 815                                  i_fatal("chdir(%s) failed with uid %s: %m",
 816                                          full_home_dir, dec2str(uid));
 817                          } else {
 818                                  i_fatal("%s", eacces_error_get("chdir",
 819[+]                                                                full_home_dir));
expand/collapse

eacces_error_get

(/home/sate/Testcases/c/cve/dovecot-1.2.0/src/lib/eacces-error.c)expand/collapse
Show more  
 153  const char *eacces_error_get(const char *func, const char *path)
 154  {
 155[+]         return eacces_error_get_full(func, path, FALSE);
expand/collapse

eacces_error_get_full

(/home/sate/Testcases/c/cve/dovecot-1.2.0/src/lib/eacces-error.c)expand/collapse
Show more  
 83  static const char *
 84  eacces_error_get_full(const char *func, const char *path, bool creating)
 85  {
 86          const char *prev_path = path, *dir = "/", *p;
 87          const struct passwd *pw;
 88          const struct group *group;
 89          string_t *errmsg;
 90          struct stat st, dir_st;
 91          int orig_errno, ret = -1;
 92   
 93          orig_errno = errno;
 94          errmsg = t_str_new(256);
 95          str_printfa(errmsg, "%s(%s) failed: Permission denied (euid=%s",
 96                      func, path, dec2str(geteuid()));
 97   
 98          pw = getpwuid(geteuid());
 99          if (pw != NULL)
 100                  str_printfa(errmsg, "(%s)", pw->pw_name);
 101   
 102          str_printfa(errmsg, " egid=%s", dec2str(getegid()));
 103          group = getgrgid(getegid());
 104          if (group != NULL)
 105                  str_printfa(errmsg, "(%s)", group->gr_name);
 106   
 107          while ((p = strrchr(prev_path, '/')) != NULL) {
 108                  dir = t_strdup_until(prev_path, p);
 109                  ret = stat(dir, &st);
 110                  if (ret == 0)
 111                          break;
 112                  if (errno == EACCES) {
 113                          /* see if we have access to parent directory */
 114                  } else if (errno == ENOENT && creating) {
 115                          /* probably mkdir_parents() failed here, find the first 
 116                             parent directory we couldn't create */
 117                  } else {
 118                          /* some other error, can't handle it */
 119                          str_printfa(errmsg, " stat(%s) failed: %m", dir);
 120                          break;
 121                  }
 122                  prev_path = dir;
 123                  dir = "/";
 124                  dir_st = st;
 125          }
 126   
 127          if (ret == 0) {
 128                  /* dir is the first parent directory we can stat() */
 129[+]                 if (test_access(dir, X_OK, errmsg) < 0) {
 130                          if (errno == EACCES)
 131                                  str_printfa(errmsg, " missing +x perm: %s", dir);
 132                  } else if (creating && test_access(dir, W_OK, errmsg) < 0) {
 133                          if (errno == EACCES)
 134                                  str_printfa(errmsg, " missing +w perm: %s", dir);
 135                  } else if (prev_path == path &&
 136[+]                            test_access(path, R_OK, errmsg) < 0) {
expand/collapse

test_access

(/home/sate/Testcases/c/cve/dovecot-1.2.0/src/lib/eacces-error.c)expand/collapse
Show more  
 29  static int test_access(const char *path, int mode, string_t *errmsg)
 30  {
 31          struct stat st;
 32   
 33          if (getuid() == geteuid()) {
 34                  if (access(path, mode) == 0)
Show more  
Show more  
Show more  
Show more  




Change Warning 7752.25031 : File System Race Condition

Priority:
State:
Finding:
Owner:
Note: