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
This commit is contained in:
parent
65730d9349
commit
ee8c5d1451
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=285433
@ -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 mail file */
|
||||
if (PWALTDIR() != PWF_ALT)
|
||||
unlinkat(conf.rootfd, file + 1, 0);
|
||||
|
||||
/*
|
||||
* Remove at jobs
|
||||
*/
|
||||
if (getpwuid(uid) == NULL)
|
||||
rmat(uid);
|
||||
/* Remove at jobs */
|
||||
if (!PWALTDIR() && 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 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+");
|
||||
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;
|
||||
|
||||
if (fp != NULL) {
|
||||
char tmp[1024];
|
||||
off_t atofs = 0;
|
||||
int length = strlen(name);
|
||||
fp = fdopen(fd, "r+");
|
||||
len = 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);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -31,7 +31,27 @@ user_do_not_try_to_delete_root_if_user_unknown_body() {
|
||||
${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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user