]> git.cameronkatri.com Git - pw-darwin.git/blobdiff - pw/pw_user.c
Regression fix: allow to create users with uid0
[pw-darwin.git] / pw / pw_user.c
index 315af39ed47e0181ce29dd4cfc3d07742e8bc819..d6dad3f3c52b7ea121826a2c704633362301c882 100644 (file)
@@ -67,20 +67,20 @@ static void     rmopie(char const * name);
 static void
 create_and_populate_homedir(struct passwd *pwd)
 {
-       char *homedir, *dotdir;
        struct userconf *cnf = conf.userconf;
+       const char *skeldir;
+       int skelfd = -1;
 
-       homedir = dotdir = NULL;
+       skeldir = cnf->dotdir;
 
-       if (conf.rootdir[0] != '\0') {
-               asprintf(&homedir, "%s/%s", conf.rootdir, pwd->pw_dir);
-               if (homedir == NULL)
-                       errx(EX_OSERR, "out of memory");
-               asprintf(&dotdir, "%s/%s", conf.rootdir, cnf->dotdir);
+       if (skeldir != NULL && *skeldir != '\0') {
+               if (*skeldir == '/')
+                       skeldir++;
+               skelfd = openat(conf.rootfd, skeldir, O_DIRECTORY|O_CLOEXEC);
        }
 
-       copymkdir(homedir ? homedir : pwd->pw_dir, dotdir ? dotdir: cnf->dotdir,
-           cnf->homemode, pwd->pw_uid, pwd->pw_gid);
+       copymkdir(conf.rootfd, pwd->pw_dir, skelfd, cnf->homemode, pwd->pw_uid,
+           pwd->pw_gid, 0);
        pw_log(cnf, M_ADD, W_USER, "%s(%u) home %s made", pwd->pw_name,
            pwd->pw_uid, pwd->pw_dir);
 }
@@ -450,8 +450,13 @@ pw_user(int mode, char *name, long id, struct cargs * args)
        }
 
        if ((arg = getarg(args, 'k')) != NULL) {
-               if (stat(cnf->dotdir = arg->val, &st) == -1 || !S_ISDIR(st.st_mode))
-                       errx(EX_OSFILE, "skeleton `%s' is not a directory or does not exist", cnf->dotdir);
+               char *tmp = cnf->dotdir = arg->val;
+               if (*tmp == '/')
+                       tmp++;
+               if ((fstatat(conf.rootfd, tmp, &st, 0) == -1) ||
+                   !S_ISDIR(st.st_mode))
+                       errx(EX_OSFILE, "skeleton `%s' is not a directory or "
+                           "does not exist", cnf->dotdir);
        }
 
        if ((arg = getarg(args, 's')) != NULL)
@@ -747,12 +752,12 @@ pw_user(int mode, char *name, long id, struct cargs * args)
         */
        if (mode == M_ADD) {
                if (PWALTDIR() != PWF_ALT) {
-                       arg = getarg(args, 'R');
-                       snprintf(path, sizeof(path), "%s%s/%s",
-                           arg ? arg->val : "", _PATH_MAILDIR, pwd->pw_name);
-                       close(open(path, O_RDWR | O_CREAT, 0600));      /* Preserve contents &
-                                                                        * mtime */
-                       chown(path, pwd->pw_uid, pwd->pw_gid);
+                       snprintf(path, sizeof(path), "%s/%s", _PATH_MAILDIR,
+                           pwd->pw_name);
+                       close(openat(conf.rootfd, path +1, O_RDWR | O_CREAT,
+                           0600));     /* Preserve contents & mtime */
+                       fchownat(conf.rootfd, path + 1, pwd->pw_uid,
+                           pwd->pw_gid, AT_SYMLINK_NOFOLLOW);
                }
        }
 
@@ -799,7 +804,7 @@ pw_uidpolicy(struct userconf * cnf, long id)
        /*
         * Check the given uid, if any
         */
-       if (id > 0) {
+       if (id >= 0) {
                uid = (uid_t) id;
 
                if ((pwd = GETPWUID(uid)) != NULL && conf.checkduplicate)
@@ -874,11 +879,8 @@ pw_gidpolicy(struct cargs * args, char *nam, gid_t prefer)
            (grp->gr_mem == NULL || grp->gr_mem[0] == NULL)) {
                gid = grp->gr_gid;  /* Already created? Use it anyway... */
        } else {
-               struct cargs    grpargs;
                gid_t           grid = -1;
 
-               LIST_INIT(&grpargs);
-
                /*
                 * We need to auto-create a group with the user's name. We
                 * can send all the appropriate output to our sister routine
@@ -893,7 +895,7 @@ pw_gidpolicy(struct cargs * args, char *nam, gid_t prefer)
                if (conf.dryrun) {
                        gid = pw_groupnext(cnf, true);
                } else {
-                       pw_group(M_ADD, nam, grid, &grpargs);
+                       pw_group(M_ADD, nam, grid, NULL);
                        if ((grp = GETGRNAM(nam)) != NULL)
                                gid = grp->gr_gid;
                }
@@ -1091,16 +1093,13 @@ pw_userdel(char *name, long id)
        if (strcmp(pwd->pw_name, "root") == 0)
                errx(EX_DATAERR, "cannot remove user 'root'");
 
-       if (!PWALTDIR()) {
-               /*
-                * Remove opie record from /etc/opiekeys
-               */
+               /* Remove opie record from /etc/opiekeys */
 
+       if (PWALTDIR() != PWF_ALT)
                rmopie(pwd->pw_name);
 
-               /*
-                * Remove crontabs
-                */
+       if (!PWALTDIR()) {
+               /* Remove crontabs */
                snprintf(file, sizeof(file), "/var/cron/tabs/%s", pwd->pw_name);
                if (access(file, F_OK) == 0) {
                        snprintf(file, sizeof(file), "crontab -u %s -r", pwd->pw_name);
@@ -1162,28 +1161,23 @@ pw_userdel(char *name, long id)
        pw_log(conf.userconf, M_DELETE, W_USER, "%s(%u) account removed", name,
            uid);
 
-       if (!PWALTDIR()) {
-               /*
-                * Remove mail file
-                */
-               remove(file);
-
-               /*
-                * Remove at jobs
-                */
-               if (getpwuid(uid) == NULL)
-                       rmat(uid);
-
-               /*
-                * Remove home directory and contents
-                */
-               if (conf.deletehome && *home == '/' && getpwuid(uid) == NULL &&
-                   stat(home, &st) != -1) {
-                       rm_r(home, uid);
-                       pw_log(conf.userconf, M_DELETE, W_USER, "%s(%u) home '%s' %sremoved",
-                              name, uid, home,
-                              stat(home, &st) == -1 ? "" : "not completely ");
-               }
+       /* Remove mail file */
+       if (PWALTDIR() != PWF_ALT)
+               unlinkat(conf.rootfd, file + 1, 0);
+
+               /* Remove at jobs */
+       if (!PWALTDIR() && getpwuid(uid) == NULL)
+               rmat(uid);
+
+       /* Remove home directory and contents */
+       if (PWALTDIR() != PWF_ALT && conf.deletehome && *home == '/' &&
+           getpwuid(uid) == NULL &&
+           fstatat(conf.rootfd, home + 1, &st, 0) != -1) {
+               rm_r(conf.rootfd, home, uid);
+               pw_log(conf.userconf, M_DELETE, W_USER, "%s(%u) home '%s' %s"
+                   "removed", name, uid, home,
+                    fstatat(conf.rootfd, home + 1, &st, 0) == -1 ? "" : "not "
+                    "completely ");
        }
 
        return (EXIT_SUCCESS);
@@ -1357,27 +1351,29 @@ rmat(uid_t uid)
 static void
 rmopie(char const * name)
 {
-       static const char etcopie[] = "/etc/opiekeys";
-       FILE   *fp = fopen(etcopie, "r+");
-
-       if (fp != NULL) {
-               char    tmp[1024];
-               off_t   atofs = 0;
-               int     length = strlen(name);
-
-               while (fgets(tmp, sizeof tmp, fp) != NULL) {
-                       if (strncmp(name, tmp, length) == 0 && tmp[length]==' ') {
-                               if (fseek(fp, atofs, SEEK_SET) == 0) {
-                                       fwrite("#", 1, 1, fp);  /* Comment username out */
-                               }
-                               break;
-                       }
-                       atofs = ftell(fp);
+       char tmp[1014];
+       FILE *fp;
+       int fd;
+       size_t len;
+       off_t   atofs = 0;
+       
+       if ((fd = openat(conf.rootfd, "etc/opiekeys", O_RDWR)) == -1)
+               return;
+
+       fp = fdopen(fd, "r+");
+       len = strlen(name);
+
+       while (fgets(tmp, sizeof(tmp), fp) != NULL) {
+               if (strncmp(name, tmp, len) == 0 && tmp[len]==' ') {
+                       /* Comment username out */
+                       if (fseek(fp, atofs, SEEK_SET) == 0)
+                               fwrite("#", 1, 1, fp);
+                       break;
                }
-               /*
-                * If we got an error of any sort, don't update!
-                */
-               fclose(fp);
+               atofs = ftell(fp);
        }
+       /*
+        * If we got an error of any sort, don't update!
+        */
+       fclose(fp);
 }
-