Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 12 Jul 2015 21:43:58 +0000 (UTC)
From:      Baptiste Daroussin <bapt@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r285433 - in head/usr.sbin/pw: . tests
Message-ID:  <201507122143.t6CLhwx4050957@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: bapt
Date: Sun Jul 12 21:43:57 2015
New Revision: 285433
URL: https://svnweb.freebsd.org/changeset/base/285433

Log:
  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

Modified:
  head/usr.sbin/pw/pw_user.c
  head/usr.sbin/pw/pwupd.h
  head/usr.sbin/pw/rm_r.c
  head/usr.sbin/pw/tests/pw_userdel.sh

Modified: head/usr.sbin/pw/pw_user.c
==============================================================================
--- head/usr.sbin/pw/pw_user.c	Sun Jul 12 21:43:31 2015	(r285432)
+++ head/usr.sbin/pw/pw_user.c	Sun Jul 12 21:43:57 2015	(r285433)
@@ -746,12 +746,12 @@ pw_user(int mode, char *name, long id, s
 	 */
 	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);
 }
-

Modified: head/usr.sbin/pw/pwupd.h
==============================================================================
--- head/usr.sbin/pw/pwupd.h	Sun Jul 12 21:43:31 2015	(r285432)
+++ head/usr.sbin/pw/pwupd.h	Sun Jul 12 21:43:57 2015	(r285433)
@@ -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 */

Modified: head/usr.sbin/pw/rm_r.c
==============================================================================
--- head/usr.sbin/pw/rm_r.c	Sun Jul 12 21:43:31 2015	(r285432)
+++ head/usr.sbin/pw/rm_r.c	Sun Jul 12 21:43:57 2015	(r285433)
@@ -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];
-
-		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);
-		}
+	if (*path == '/')
+		path++;
+
+	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);
 }

Modified: head/usr.sbin/pw/tests/pw_userdel.sh
==============================================================================
--- head/usr.sbin/pw/tests/pw_userdel.sh	Sun Jul 12 21:43:31 2015	(r285432)
+++ head/usr.sbin/pw/tests/pw_userdel.sh	Sun Jul 12 21:43:57 2015	(r285433)
@@ -31,7 +31,27 @@ user_do_not_try_to_delete_root_if_user_u
 		${PW} userdel -u plop
 }
 
+atf_test_case delete_files
+delete_files_body() {
+	populate_root_etc_skel
+
+	mkdir -p ${HOME}/skel
+	touch ${HOME}/skel/a
+	mkdir -p ${HOME}/home
+	mkdir -p ${HOME}/var/mail
+	echo "foo wedontcare" > ${HOME}/etc/opiekeys
+	atf_check -s exit:0 ${RPW} useradd foo -k skel -m
+	test -d ${HOME}/home || atf_fail "Fail to create home directory"
+	test -f ${HOME}/var/mail/foo || atf_fail "Mail file not created"
+	atf_check -s exit:0 ${RPW} userdel foo -r
+	atf_check -s exit:0 -o inline:"#oo wedontcare\n" cat ${HOME}/etc/opiekeys
+	if test -f ${HOME}/var/mail/foo; then
+		atf_fail "Mail file not removed"
+	fi
+}
+
 atf_init_test_cases() {
 	atf_add_test_case rmuser_seperate_group
 	atf_add_test_case user_do_not_try_to_delete_root_if_user_unknown
+	atf_add_test_case delete_files
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201507122143.t6CLhwx4050957>