X-Git-Url: https://git.cameronkatri.com/pw-darwin.git/blobdiff_plain/5b291029a9ed6f6ac19b03b29501179559dc07c3..0318aba2a76b3131e3b36d0171ae00f776765bd9:/pw/pw_user.c diff --git a/pw/pw_user.c b/pw/pw_user.c index c3b2751..d6dad3f 100644 --- a/pw/pw_user.c +++ b/pw/pw_user.c @@ -51,8 +51,7 @@ static const char rcsid[] = static char locked_str[] = "*LOCKED*"; -static int delete_user(struct userconf *cnf, struct passwd *pwd, - char *name, int delete, int mode); +static int pw_userdel(char *name, long id); static int print_user(struct passwd * pwd); static uid_t pw_uidpolicy(struct userconf * cnf, long id); static uid_t pw_gidpolicy(struct cargs * args, char *nam, gid_t prefer); @@ -60,32 +59,210 @@ static time_t pw_pwdpolicy(struct userconf * cnf, struct cargs * args); static time_t pw_exppolicy(struct userconf * cnf, struct cargs * args); static char *pw_homepolicy(struct userconf * cnf, struct cargs * args, char const * user); static char *pw_shellpolicy(struct userconf * cnf, struct cargs * args, char *newshell); -static char *pw_password(struct userconf * cnf, struct cargs * args, char const * user); +static char *pw_password(struct userconf * cnf, char const * user); static char *shell_path(char const * path, char *shells[], char *sh); static void rmat(uid_t uid); static void rmopie(char const * name); static void -create_and_populate_homedir(int mode, struct passwd *pwd) +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); - pw_log(cnf, mode, W_USER, "%s(%u) home %s made", pwd->pw_name, + 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); } +static int +set_passwd(struct passwd *pwd, bool update) +{ + int b, istty; + struct termios t, n; + login_cap_t *lc; + char line[_PASSWORD_LEN+1]; + char *p; + + if (conf.fd == '-') { + if (!pwd->pw_passwd || *pwd->pw_passwd != '*') { + pwd->pw_passwd = "*"; /* No access */ + return (1); + } + return (0); + } + + if ((istty = isatty(conf.fd))) { + if (tcgetattr(conf.fd, &t) == -1) + istty = 0; + else { + n = t; + n.c_lflag &= ~(ECHO); + tcsetattr(conf.fd, TCSANOW, &n); + printf("%s%spassword for user %s:", + update ? "new " : "", + conf.precrypted ? "encrypted " : "", + pwd->pw_name); + fflush(stdout); + } + } + b = read(conf.fd, line, sizeof(line) - 1); + if (istty) { /* Restore state */ + tcsetattr(conf.fd, TCSANOW, &t); + fputc('\n', stdout); + fflush(stdout); + } + + if (b < 0) + err(EX_IOERR, "-%c file descriptor", + conf.precrypted ? 'H' : 'h'); + line[b] = '\0'; + if ((p = strpbrk(line, "\r\n")) != NULL) + *p = '\0'; + if (!*line) + errx(EX_DATAERR, "empty password read on file descriptor %d", + conf.fd); + if (conf.precrypted) { + if (strchr(line, ':') != NULL) + errx(EX_DATAERR, "bad encrypted password"); + pwd->pw_passwd = line; + } else { + lc = login_getpwclass(pwd); + if (lc == NULL || + login_setcryptfmt(lc, "sha512", NULL) == NULL) + warn("setting crypt(3) format"); + login_close(lc); + pwd->pw_passwd = pw_pwcrypt(line); + } + return (1); +} + +int +pw_usernext(struct userconf *cnf, bool quiet) +{ + uid_t next = pw_uidpolicy(cnf, -1); + + if (quiet) + return (next); + + printf("%u:", next); + pw_groupnext(cnf, quiet); + + return (EXIT_SUCCESS); +} + +static int +pw_usershow(char *name, long id, struct passwd *fakeuser) +{ + struct passwd *pwd = NULL; + + if (id < 0 && name == NULL && !conf.all) + errx(EX_DATAERR, "username or id or '-a' required"); + + if (conf.all) { + SETPWENT(); + while ((pwd = GETPWENT()) != NULL) + print_user(pwd); + ENDPWENT(); + return (EXIT_SUCCESS); + } + + pwd = (name != NULL) ? GETPWNAM(pw_checkname(name, 0)) : GETPWUID(id); + if (pwd == NULL) { + if (conf.force) { + pwd = fakeuser; + } else { + if (name == NULL) + errx(EX_NOUSER, "no such uid `%ld'", id); + errx(EX_NOUSER, "no such user `%s'", name); + } + } + + return (print_user(pwd)); +} + +static void +perform_chgpwent(const char *name, struct passwd *pwd) +{ + int rc; + + rc = chgpwent(name, pwd); + if (rc == -1) + errx(EX_IOERR, "user '%s' does not exist (NIS?)", pwd->pw_name); + else if (rc != 0) + err(EX_IOERR, "passwd file update"); + + if (conf.userconf->nispasswd && *conf.userconf->nispasswd == '/') { + rc = chgnispwent(conf.userconf->nispasswd, name, pwd); + if (rc == -1) + warn("User '%s' not found in NIS passwd", pwd->pw_name); + else + warn("NIS passwd update"); + /* NOTE: NIS-only update errors are not fatal */ + } +} + +/* + * The M_LOCK and M_UNLOCK functions simply add or remove + * a "*LOCKED*" prefix from in front of the password to + * prevent it decoding correctly, and therefore prevents + * access. Of course, this only prevents access via + * password authentication (not ssh, kerberos or any + * other method that does not use the UNIX password) but + * that is a known limitation. + */ +static int +pw_userlock(char *name, long id, int mode) +{ + struct passwd *pwd = NULL; + char *passtmp = NULL; + bool locked = false; + + if (id < 0 && name == NULL) + errx(EX_DATAERR, "username or id required"); + + pwd = (name != NULL) ? GETPWNAM(pw_checkname(name, 0)) : GETPWUID(id); + if (pwd == NULL) { + if (name == NULL) + errx(EX_NOUSER, "no such uid `%ld'", id); + errx(EX_NOUSER, "no such user `%s'", name); + } + + if (name == NULL) + name = pwd->pw_name; + + if (strncmp(pwd->pw_passwd, locked_str, sizeof(locked_str) -1) == 0) + locked = true; + if (mode == M_LOCK && locked) + errx(EX_DATAERR, "user '%s' is already locked", pwd->pw_name); + if (mode == M_UNLOCK && !locked) + errx(EX_DATAERR, "user '%s' is not locked", pwd->pw_name); + + if (mode == M_LOCK) { + asprintf(&passtmp, "%s%s", locked_str, pwd->pw_passwd); + if (passtmp == NULL) /* disaster */ + errx(EX_UNAVAILABLE, "out of memory"); + pwd->pw_passwd = passtmp; + } else { + pwd->pw_passwd += sizeof(locked_str)-1; + } + + perform_chgpwent(name, pwd); + free(passtmp); + + return (EXIT_SUCCESS); +} + /*- * -C config configuration file * -q quiet operation @@ -123,7 +300,6 @@ pw_user(int mode, char *name, long id, struct cargs * args) { int rc, edited = 0; char *p = NULL; - char *passtmp; struct carg *arg; struct passwd *pwd = NULL; struct group *grp; @@ -137,7 +313,7 @@ pw_user(int mode, char *name, long id, struct cargs * args) static struct passwd fakeuser = { - NULL, + "nouser", "*", -1, -1, @@ -154,19 +330,17 @@ pw_user(int mode, char *name, long id, struct cargs * args) cnf = conf.userconf; - /* - * With M_NEXT, we only need to return the - * next uid to stdout - */ if (mode == M_NEXT) - { - uid_t next = pw_uidpolicy(cnf, id); - if (getarg(args, 'q')) - return next; - printf("%u:", next); - pw_group(mode, name, -1, args); - return EXIT_SUCCESS; - } + return (pw_usernext(cnf, conf.quiet)); + + if (mode == M_PRINT) + return (pw_usershow(name, id, &fakeuser)); + + if (mode == M_DELETE) + return (pw_userdel(name, id)); + + if (mode == M_LOCK || mode == M_UNLOCK) + return (pw_userlock(name, id, mode)); /* * We can do all of the common legwork here @@ -226,7 +400,7 @@ pw_user(int mode, char *name, long id, struct cargs * args) *p = '\0'; if (stat(dbuf, &st) == -1) { if (mkdir(dbuf, _DEF_DIRMODE) == -1) - goto direrr; + err(EX_OSFILE, "mkdir '%s'", dbuf); chown(dbuf, 0, 0); } else if (!S_ISDIR(st.st_mode)) errx(EX_OSFILE, "'%s' (root home parent) is not a directory", dbuf); @@ -234,9 +408,8 @@ pw_user(int mode, char *name, long id, struct cargs * args) } } if (stat(dbuf, &st) == -1) { - if (mkdir(dbuf, _DEF_DIRMODE) == -1) { - direrr: err(EX_OSFILE, "mkdir '%s'", dbuf); - } + if (mkdir(dbuf, _DEF_DIRMODE) == -1) + err(EX_OSFILE, "mkdir '%s'", dbuf); chown(dbuf, 0, 0); } } else if (!S_ISDIR(st.st_mode)) @@ -267,23 +440,23 @@ pw_user(int mode, char *name, long id, struct cargs * args) cnf->default_class = pw_checkname(arg->val, 0); if ((arg = getarg(args, 'G')) != NULL && arg->val) { - int i = 0; - for (p = strtok(arg->val, ", \t"); p != NULL; p = strtok(NULL, ", \t")) { if ((grp = GETGRNAM(p)) == NULL) { if (!isdigit((unsigned char)*p) || (grp = GETGRGID((gid_t) atoi(p))) == NULL) errx(EX_NOUSER, "group `%s' does not exist", p); } - if (extendarray(&cnf->groups, &cnf->numgroups, i + 2) != -1) - cnf->groups[i++] = newstr(grp->gr_name); + sl_add(cnf->groups, newstr(grp->gr_name)); } - while (i < cnf->numgroups) - cnf->groups[i++] = NULL; } 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) @@ -312,14 +485,6 @@ pw_user(int mode, char *name, long id, struct cargs * args) err(EX_IOERR, "config udpate"); } - if (mode == M_PRINT && getarg(args, 'a')) { - SETPWENT(); - while ((pwd = GETPWENT()) != NULL) - print_user(pwd); - ENDPWENT(); - return EXIT_SUCCESS; - } - if (name != NULL) pwd = GETPWNAM(pw_checkname(name, 0)); @@ -327,20 +492,14 @@ pw_user(int mode, char *name, long id, struct cargs * args) errx(EX_DATAERR, "user name or id required"); /* - * Update, delete & print require that the user exists + * Update require that the user exists */ - if (mode == M_UPDATE || mode == M_DELETE || - mode == M_PRINT || mode == M_LOCK || mode == M_UNLOCK) { + if (mode == M_UPDATE) { if (name == NULL && pwd == NULL) /* Try harder */ pwd = GETPWUID(id); if (pwd == NULL) { - if (mode == M_PRINT && getarg(args, 'F')) { - fakeuser.pw_name = name ? name : "nouser"; - fakeuser.pw_uid = (uid_t) id; - return print_user(&fakeuser); - } if (name == NULL) errx(EX_NOUSER, "no such uid `%ld'", id); errx(EX_NOUSER, "no such user `%s'", name); @@ -349,35 +508,6 @@ pw_user(int mode, char *name, long id, struct cargs * args) if (name == NULL) name = pwd->pw_name; - /* - * The M_LOCK and M_UNLOCK functions simply add or remove - * a "*LOCKED*" prefix from in front of the password to - * prevent it decoding correctly, and therefore prevents - * access. Of course, this only prevents access via - * password authentication (not ssh, kerberos or any - * other method that does not use the UNIX password) but - * that is a known limitation. - */ - - if (mode == M_LOCK) { - if (strncmp(pwd->pw_passwd, locked_str, sizeof(locked_str)-1) == 0) - errx(EX_DATAERR, "user '%s' is already locked", pwd->pw_name); - asprintf(&passtmp, "%s%s", locked_str, pwd->pw_passwd); - if (passtmp == NULL) /* disaster */ - errx(EX_UNAVAILABLE, "out of memory"); - pwd->pw_passwd = passtmp; - edited = 1; - } else if (mode == M_UNLOCK) { - if (strncmp(pwd->pw_passwd, locked_str, sizeof(locked_str)-1) != 0) - errx(EX_DATAERR, "user '%s' is not locked", pwd->pw_name); - pwd->pw_passwd += sizeof(locked_str)-1; - edited = 1; - } else if (mode == M_DELETE) - return (delete_user(cnf, pwd, name, - getarg(args, 'r') != NULL, mode)); - else if (mode == M_PRINT) - return print_user(pwd); - /* * The rest is edit code */ @@ -470,8 +600,7 @@ pw_user(int mode, char *name, long id, struct cargs * args) warnx("WARNING: home `%s' is not a directory", pwd->pw_dir); } - if ((arg = getarg(args, 'w')) != NULL && - getarg(args, 'h') == NULL && getarg(args, 'H') == NULL) { + if ((arg = getarg(args, 'w')) != NULL && conf.fd == -1) { login_cap_t *lc; lc = login_getpwclass(pwd); @@ -479,7 +608,7 @@ pw_user(int mode, char *name, long id, struct cargs * args) login_setcryptfmt(lc, "sha512", NULL) == NULL) warn("setting crypt(3) format"); login_close(lc); - pwd->pw_passwd = pw_password(cnf, args, pwd->pw_name); + pwd->pw_passwd = pw_password(cnf, pwd->pw_name); edited = 1; } @@ -511,7 +640,7 @@ pw_user(int mode, char *name, long id, struct cargs * args) if (lc == NULL || login_setcryptfmt(lc, "sha512", NULL) == NULL) warn("setting crypt(3) format"); login_close(lc); - pwd->pw_passwd = pw_password(cnf, args, pwd->pw_name); + pwd->pw_passwd = pw_password(cnf, pwd->pw_name); edited = 1; if (pwd->pw_uid == 0 && strcmp(pwd->pw_name, "root") != 0) @@ -521,74 +650,15 @@ pw_user(int mode, char *name, long id, struct cargs * args) /* * Shared add/edit code */ - if ((arg = getarg(args, 'c')) != NULL) { - char *gecos = pw_checkname(arg->val, 1); - if (strcmp(pwd->pw_gecos, gecos) != 0) { - pwd->pw_gecos = gecos; + if (conf.gecos != NULL) { + if (strcmp(pwd->pw_gecos, conf.gecos) != 0) { + pwd->pw_gecos = conf.gecos; edited = 1; } } - if ((arg = getarg(args, 'h')) != NULL || - (arg = getarg(args, 'H')) != NULL) { - if (strcmp(arg->val, "-") == 0) { - if (!pwd->pw_passwd || *pwd->pw_passwd != '*') { - pwd->pw_passwd = "*"; /* No access */ - edited = 1; - } - } else { - int fd = atoi(arg->val); - int precrypt = (arg->ch == 'H'); - int b; - int istty = isatty(fd); - struct termios t; - login_cap_t *lc; - - if (istty) { - if (tcgetattr(fd, &t) == -1) - istty = 0; - else { - struct termios n = t; - - /* Disable echo */ - n.c_lflag &= ~(ECHO); - tcsetattr(fd, TCSANOW, &n); - printf("%s%spassword for user %s:", - (mode == M_UPDATE) ? "new " : "", - precrypt ? "encrypted " : "", - pwd->pw_name); - fflush(stdout); - } - } - b = read(fd, line, sizeof(line) - 1); - if (istty) { /* Restore state */ - tcsetattr(fd, TCSANOW, &t); - fputc('\n', stdout); - fflush(stdout); - } - if (b < 0) - err(EX_IOERR, "-%c file descriptor", - precrypt ? 'H' : 'h'); - line[b] = '\0'; - if ((p = strpbrk(line, "\r\n")) != NULL) - *p = '\0'; - if (!*line) - errx(EX_DATAERR, "empty password read on file descriptor %d", fd); - if (precrypt) { - if (strchr(line, ':') != NULL) - return EX_DATAERR; - pwd->pw_passwd = line; - } else { - lc = login_getpwclass(pwd); - if (lc == NULL || - login_setcryptfmt(lc, "sha512", NULL) == NULL) - warn("setting crypt(3) format"); - login_close(lc); - pwd->pw_passwd = pw_pwcrypt(line); - } - edited = 1; - } - } + if (conf.fd != -1) + edited = set_passwd(pwd, mode == M_UPDATE); /* * Special case: -N only displays & exits @@ -612,30 +682,16 @@ pw_user(int mode, char *name, long id, struct cargs * args) warn("NIS passwd update"); /* NOTE: we treat NIS-only update errors as non-fatal */ } - } else if (mode == M_UPDATE || mode == M_LOCK || mode == M_UNLOCK) { - if (edited) { /* Only updated this if required */ - rc = chgpwent(name, pwd); - if (rc == -1) - errx(EX_IOERR, "user '%s' does not exist (NIS?)", pwd->pw_name); - else if (rc != 0) - err(EX_IOERR, "passwd file update"); - if ( cnf->nispasswd && *cnf->nispasswd=='/') { - rc = chgnispwent(cnf->nispasswd, name, pwd); - if (rc == -1) - warn("User '%s' not found in NIS passwd", pwd->pw_name); - else - warn("NIS passwd update"); - /* NOTE: NIS-only update errors are not fatal */ - } - } - } + } else if (mode == M_UPDATE && edited) /* Only updated this if required */ + perform_chgpwent(name, pwd); /* * Ok, user is created or changed - now edit group file */ if (mode == M_ADD || getarg(args, 'G') != NULL) { - int i, j; + int j; + size_t i; /* First remove the user from all group */ SETGRENT(); while ((grp = GETGRENT()) != NULL) { @@ -654,8 +710,8 @@ pw_user(int mode, char *name, long id, struct cargs * args) ENDGRENT(); /* now add to group where needed */ - for (i = 0; cnf->groups[i] != NULL; i++) { - grp = GETGRNAM(cnf->groups[i]); + for (i = 0; i < cnf->groups->sl_cur; i++) { + grp = GETGRNAM(cnf->groups->sl_str[i]); grp = gr_add(grp, pwd->pw_name); /* * grp can only be NULL in 2 cases: @@ -665,7 +721,7 @@ pw_user(int mode, char *name, long id, struct cargs * args) */ if (grp == NULL) continue; - chggrent(cnf->groups[i], grp); + chggrent(grp->gr_name, grp); free(grp); } } @@ -696,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); } } @@ -712,7 +768,7 @@ pw_user(int mode, char *name, long id, struct cargs * args) */ if (PWALTDIR() != PWF_ALT && getarg(args, 'm') != NULL && pwd->pw_dir && *pwd->pw_dir == '/' && pwd->pw_dir[1]) - create_and_populate_homedir(mode, pwd); + create_and_populate_homedir(pwd); /* * Finally, send mail to the new user as well, if we are asked to @@ -748,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) @@ -823,10 +879,7 @@ 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; - char tmp[32]; - - LIST_INIT(&grpargs); + gid_t grid = -1; /* * We need to auto-create a group with the user's name. We @@ -837,26 +890,15 @@ pw_gidpolicy(struct cargs * args, char *nam, gid_t prefer) * user's name dups an existing group, then the group add * function will happily handle that case for us and exit. */ - if (GETGRGID(prefer) == NULL) { - snprintf(tmp, sizeof(tmp), "%u", prefer); - addarg(&grpargs, 'g', tmp); - } + if (GETGRGID(prefer) == NULL) + grid = prefer; if (conf.dryrun) { - addarg(&grpargs, 'q', NULL); - gid = pw_group(M_NEXT, nam, -1, &grpargs); - } - else - { - pw_group(M_ADD, nam, -1, &grpargs); + gid = pw_groupnext(cnf, true); + } else { + pw_group(M_ADD, nam, grid, NULL); if ((grp = GETGRNAM(nam)) != NULL) gid = grp->gr_gid; } - a_gid = LIST_FIRST(&grpargs); - while (a_gid != NULL) { - struct carg *t = LIST_NEXT(a_gid, list); - LIST_REMOVE(a_gid, list); - a_gid = t; - } } ENDGRENT(); return gid; @@ -986,7 +1028,7 @@ pw_pwcrypt(char *password) static char * -pw_password(struct userconf * cnf, struct cargs * args, char const * user) +pw_password(struct userconf * cnf, char const * user) { int i, l; char pwbuf[32]; @@ -1001,8 +1043,7 @@ pw_password(struct userconf * cnf, struct cargs * args, char const * user) /* * We give this information back to the user */ - if (getarg(args, 'h') == NULL && getarg(args, 'H') == NULL && - !conf.dryrun) { + if (conf.fd == -1 && !conf.dryrun) { if (isatty(STDOUT_FILENO)) printf("Password for '%s' is: ", user); printf("%s\n", pwbuf); @@ -1025,30 +1066,40 @@ pw_password(struct userconf * cnf, struct cargs * args, char const * user) } static int -delete_user(struct userconf *cnf, struct passwd *pwd, char *name, - int delete, int mode) +pw_userdel(char *name, long id) { + struct passwd *pwd = NULL; char file[MAXPATHLEN]; char home[MAXPATHLEN]; - uid_t uid = pwd->pw_uid; + uid_t uid; struct group *gr, *grp; char grname[LOGNAMESIZE]; int rc; struct stat st; + if (id < 0 && name == NULL) + errx(EX_DATAERR, "username or id required"); + + pwd = (name != NULL) ? GETPWNAM(pw_checkname(name, 0)) : GETPWUID(id); + if (pwd == NULL) { + if (name == NULL) + errx(EX_NOUSER, "no such uid `%ld'", id); + errx(EX_NOUSER, "no such user `%s'", name); + } + uid = pwd->pw_uid; + if (name == NULL) + name = pwd->pw_name; + 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); @@ -1073,10 +1124,11 @@ delete_user(struct userconf *cnf, struct passwd *pwd, char *name, else if (rc != 0) err(EX_IOERR, "passwd update"); - if (cnf->nispasswd && *cnf->nispasswd=='/') { - rc = delnispwent(cnf->nispasswd, name); + if (conf.userconf->nispasswd && *conf.userconf->nispasswd=='/') { + rc = delnispwent(conf.userconf->nispasswd, name); if (rc == -1) - warnx("WARNING: user '%s' does not exist in NIS passwd", pwd->pw_name); + warnx("WARNING: user '%s' does not exist in NIS passwd", + pwd->pw_name); else if (rc != 0) warn("WARNING: NIS passwd update"); /* non-fatal */ @@ -1106,30 +1158,26 @@ delete_user(struct userconf *cnf, struct passwd *pwd, char *name, } ENDGRENT(); - pw_log(cnf, mode, 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 (delete && *home == '/' && getpwuid(uid) == NULL && - stat(home, &st) != -1) { - rm_r(home, uid); - pw_log(cnf, mode, W_USER, "%s(%u) home '%s' %sremoved", - name, uid, home, - stat(home, &st) == -1 ? "" : "not completely "); - } + pw_log(conf.userconf, M_DELETE, W_USER, "%s(%u) account removed", name, + uid); + + /* 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); @@ -1303,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); } -