summaryrefslogtreecommitdiffstats
path: root/pw
diff options
context:
space:
mode:
authorBaptiste Daroussin <bapt@FreeBSD.org>2015-07-12 21:43:57 +0000
committerBaptiste Daroussin <bapt@FreeBSD.org>2015-07-12 21:43:57 +0000
commitd6d7189c26aa1c3f1bb8ac622e5daf43b8485c30 (patch)
tree8101f7e9a7f13130354eaf49a9e19547be91be7b /pw
parentf6975773c5ebf939f9e3f22b2b600d2c821604bc (diff)
downloadpw-darwin-d6d7189c26aa1c3f1bb8ac622e5daf43b8485c30.tar.gz
pw-darwin-d6d7189c26aa1c3f1bb8ac622e5daf43b8485c30.tar.zst
pw-darwin-d6d7189c26aa1c3f1bb8ac622e5daf43b8485c30.zip
pw -R <rootdir> userdel can now cleanup installation
Rewrite rm_r to use *at function, allowing to remove home directories along with users. only crontabs and at(1) installation are not removed Relnotes: yes
Diffstat (limited to 'pw')
-rw-r--r--pw/pw_user.c106
-rw-r--r--pw/pwupd.h2
-rw-r--r--pw/rm_r.c52
3 files changed, 76 insertions, 84 deletions
diff --git a/pw/pw_user.c b/pw/pw_user.c
index afc163f..fd2c80a 100644
--- a/pw/pw_user.c
+++ b/pw/pw_user.c
@@ -746,12 +746,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);
}
}
@@ -1087,16 +1087,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);
@@ -1158,28 +1155,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);
@@ -1353,27 +1345,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);
}
-
diff --git a/pw/pwupd.h b/pw/pwupd.h
index f08d2c7..054c5a5 100644
--- a/pw/pwupd.h
+++ b/pw/pwupd.h
@@ -159,7 +159,7 @@ void vendgrent(void);
void copymkdir(int rootfd, char const * dir, int skelfd, mode_t mode, uid_t uid,
gid_t gid, int flags);
-void rm_r(char const * dir, uid_t uid);
+void rm_r(int rootfd, char const * dir, uid_t uid);
__END_DECLS
#endif /* !_PWUPD_H */
diff --git a/pw/rm_r.c b/pw/rm_r.c
index 797ca9d..65a63e6 100644
--- a/pw/rm_r.c
+++ b/pw/rm_r.c
@@ -37,39 +37,37 @@ static const char rcsid[] =
#include <sys/param.h>
#include <unistd.h>
#include <dirent.h>
+#include <fcntl.h>
#include "pwupd.h"
void
-rm_r(char const * dir, uid_t uid)
+rm_r(int rootfd, const char *path, uid_t uid)
{
- DIR *d = opendir(dir);
+ int dirfd;
+ DIR *d;
+ struct dirent *e;
+ struct stat st;
- if (d != NULL) {
- struct dirent *e;
- struct stat st;
- char file[MAXPATHLEN];
+ if (*path == '/')
+ path++;
- while ((e = readdir(d)) != NULL) {
- if (strcmp(e->d_name, ".") != 0 && strcmp(e->d_name, "..") != 0) {
- snprintf(file, sizeof(file), "%s/%s", dir, e->d_name);
- if (lstat(file, &st) == 0) { /* Need symlinks, not
- * linked file */
- if (S_ISDIR(st.st_mode)) /* Directory - recurse */
- rm_r(file, uid);
- else {
- if (S_ISLNK(st.st_mode) || st.st_uid == uid)
- remove(file);
- }
- }
- }
- }
- closedir(d);
- if (lstat(dir, &st) == 0) {
- if (S_ISLNK(st.st_mode))
- remove(dir);
- else if (st.st_uid == uid)
- rmdir(dir);
- }
+ dirfd = openat(rootfd, path, O_DIRECTORY);
+
+ d = fdopendir(dirfd);
+ while ((e = readdir(d)) != NULL) {
+ if (strcmp(e->d_name, ".") == 0 || strcmp(e->d_name, "..") == 0)
+ continue;
+
+ if (fstatat(dirfd, e->d_name, &st, AT_SYMLINK_NOFOLLOW) != 0)
+ continue;
+ if (S_ISDIR(st.st_mode))
+ rm_r(dirfd, e->d_name, uid);
+ else if (S_ISLNK(st.st_mode) || st.st_uid == uid)
+ unlinkat(dirfd, e->d_name, 0);
}
+ closedir(d);
+ if (fstatat(rootfd, path, &st, AT_SYMLINK_NOFOLLOW) != 0)
+ return;
+ unlinkat(rootfd, path, S_ISDIR(st.st_mode) ? AT_REMOVEDIR : 0);
}