| /* 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 |
| |
| Options: |
| -r remove home directory |
| Delete USER from the SYSTEM |
| */ |
| |
| #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); |
| } |
| } |