/* userdel.c - delete a user
*
* Copyright 2014 Ashwini Kumar <ak.ashwini1981@gmail.com>
*
* See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/userdel.html
USE_USERDEL(NEWTOY(userdel, "<1>1r", TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
USE_USERDEL(OLDTOY(deluser, userdel, TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
config USERDEL
bool "userdel"
default n
help
usage: userdel [-r] USER
usage: deluser [-r] USER
Delete USER from the SYSTEM
-r remove home directory
*/
#define FOR_userdel
#include "toys.h"
static void update_groupfiles(char *filename, char* username)
{
char *filenamesfx = NULL, *sfx = NULL, *line = NULL;
FILE *exfp, *newfp;
int ulen = strlen(username);
struct flock lock;
filenamesfx = xmprintf("%s+", filename);
sfx = strchr(filenamesfx, '+');
exfp = xfopen(filename, "r+");
*sfx = '-';
unlink(filenamesfx);
if (link(filename, filenamesfx)) error_msg("Can't create backup file");
*sfx = '+';
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = lock.l_len = 0;
if (fcntl(fileno(exfp), F_SETLK, &lock) < 0)
perror_msg("Couldn't lock file %s",filename);
lock.l_type = F_UNLCK; //unlocking at a later stage
newfp = xfopen(filenamesfx, "w+");
while ((line = get_line(fileno(exfp))) != NULL){
sprintf(toybuf, "%s:",username);
if (!strncmp(line, toybuf, ulen+1)) goto LOOP;
else {
char *n, *p = strrchr(line, ':');
if (p && *++p && (n = strstr(p, username))) {
do {
if (n[ulen] == ',') {
*n = '\0';
n += ulen + 1;
fprintf(newfp, "%s%s\n", line, n);
break;
} else if (!n[ulen]) {
if (n[-1] == ',') n[-1] = *n = '\0';
if (n[-1] == ':') *n = '\0';
fprintf(newfp, "%s%s\n", line, n);
break;
} else n += ulen;
} while (*n && (n=strstr(n, username)));
if (!n) fprintf(newfp, "%s\n", line);
} else fprintf(newfp, "%s\n", line);
}
LOOP:
free(line);
}
fcntl(fileno(exfp), F_SETLK, &lock);
fclose(exfp);
errno = 0;
fflush(newfp);
fsync(fileno(newfp));
fclose(newfp);
rename(filenamesfx, filename);
if (errno){
perror_msg("File Writing/Saving failed: ");
unlink(filenamesfx);
}
free(filenamesfx);
}
void userdel_main(void)
{
struct passwd *pwd = NULL;
pwd = xgetpwnam(*toys.optargs);
update_password("/etc/passwd", pwd->pw_name, NULL);
update_password("/etc/shadow", pwd->pw_name, NULL);
// delete the group named USER, and remove user from group.
// could update_password() be used for this?
// not a good idea, as update_passwd() updates one entry at a time
// in this case it will be modifying the files as many times the
// USER appears in group database files. So the customized version
// of update_passwd() is here.
update_groupfiles("/etc/group", *toys.optargs);
update_groupfiles("/etc/gshadow", *toys.optargs);
if (toys.optflags & FLAG_r) {
char *arg[] = {"rm", "-fr", pwd->pw_dir, NULL, NULL};
sprintf(toybuf, "/var/spool/mail/%s",pwd->pw_name);
arg[3] = toybuf;
xexec(arg);
}
}