10f66f451Sopenharmony_ci/* userdel.c - delete a user
20f66f451Sopenharmony_ci *
30f66f451Sopenharmony_ci * Copyright 2014 Ashwini Kumar <ak.ashwini1981@gmail.com>
40f66f451Sopenharmony_ci *
50f66f451Sopenharmony_ci * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/userdel.html
60f66f451Sopenharmony_ci
70f66f451Sopenharmony_ciUSE_USERDEL(NEWTOY(userdel, "<1>1r", TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
80f66f451Sopenharmony_ciUSE_USERDEL(OLDTOY(deluser, userdel, TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
90f66f451Sopenharmony_ci
100f66f451Sopenharmony_ciconfig USERDEL
110f66f451Sopenharmony_ci  bool "userdel"
120f66f451Sopenharmony_ci  default n
130f66f451Sopenharmony_ci  help
140f66f451Sopenharmony_ci    usage: userdel [-r] USER
150f66f451Sopenharmony_ci    usage: deluser [-r] USER
160f66f451Sopenharmony_ci
170f66f451Sopenharmony_ci    Delete USER from the SYSTEM
180f66f451Sopenharmony_ci
190f66f451Sopenharmony_ci    -r	remove home directory
200f66f451Sopenharmony_ci*/
210f66f451Sopenharmony_ci
220f66f451Sopenharmony_ci#define FOR_userdel
230f66f451Sopenharmony_ci#include "toys.h"
240f66f451Sopenharmony_ci
250f66f451Sopenharmony_cistatic void update_groupfiles(char *filename, char* username)
260f66f451Sopenharmony_ci{
270f66f451Sopenharmony_ci  char *filenamesfx = NULL, *sfx = NULL, *line = NULL;
280f66f451Sopenharmony_ci  FILE *exfp, *newfp;
290f66f451Sopenharmony_ci  int ulen = strlen(username);
300f66f451Sopenharmony_ci  size_t allocated_length = 0;
310f66f451Sopenharmony_ci  struct flock lock;
320f66f451Sopenharmony_ci
330f66f451Sopenharmony_ci  filenamesfx = xmprintf("%s+", filename);
340f66f451Sopenharmony_ci  sfx = strchr(filenamesfx, '+');
350f66f451Sopenharmony_ci  exfp = xfopen(filename, "r+");
360f66f451Sopenharmony_ci
370f66f451Sopenharmony_ci  *sfx = '-';
380f66f451Sopenharmony_ci  unlink(filenamesfx);
390f66f451Sopenharmony_ci  if (link(filename, filenamesfx)) error_msg("Can't create backup file");
400f66f451Sopenharmony_ci
410f66f451Sopenharmony_ci  *sfx = '+';
420f66f451Sopenharmony_ci  lock.l_type = F_WRLCK;
430f66f451Sopenharmony_ci  lock.l_whence = SEEK_SET;
440f66f451Sopenharmony_ci  lock.l_start = lock.l_len = 0;
450f66f451Sopenharmony_ci
460f66f451Sopenharmony_ci  if (fcntl(fileno(exfp), F_SETLK, &lock) < 0)
470f66f451Sopenharmony_ci    perror_msg("Couldn't lock file %s",filename);
480f66f451Sopenharmony_ci
490f66f451Sopenharmony_ci  lock.l_type = F_UNLCK; //unlocking at a later stage
500f66f451Sopenharmony_ci
510f66f451Sopenharmony_ci  newfp = xfopen(filenamesfx, "w+");
520f66f451Sopenharmony_ci
530f66f451Sopenharmony_ci  while (getline(&line, &allocated_length, exfp) > 0) {
540f66f451Sopenharmony_ci    sprintf(toybuf, "%s:",username);
550f66f451Sopenharmony_ci    if (strncmp(line, toybuf, ulen+1)) {
560f66f451Sopenharmony_ci      char *n, *p = strrchr(line, ':');
570f66f451Sopenharmony_ci
580f66f451Sopenharmony_ci      if (p && *++p && (n = strstr(p, username))) {
590f66f451Sopenharmony_ci        do {
600f66f451Sopenharmony_ci          if (n[ulen] == ',') {
610f66f451Sopenharmony_ci            *n = '\0';
620f66f451Sopenharmony_ci            n += ulen + 1;
630f66f451Sopenharmony_ci            fprintf(newfp, "%s%s\n", line, n);
640f66f451Sopenharmony_ci            break;
650f66f451Sopenharmony_ci          } else if (!n[ulen]) {
660f66f451Sopenharmony_ci            if (n[-1] == ',') n[-1] = *n = '\0';
670f66f451Sopenharmony_ci            if (n[-1] == ':') *n = '\0';
680f66f451Sopenharmony_ci            fprintf(newfp, "%s%s\n", line, n);
690f66f451Sopenharmony_ci            break;
700f66f451Sopenharmony_ci          } else n += ulen;
710f66f451Sopenharmony_ci        } while (*n && (n=strstr(n, username)));
720f66f451Sopenharmony_ci        if (!n) fprintf(newfp, "%s\n", line);
730f66f451Sopenharmony_ci      } else fprintf(newfp, "%s\n", line);
740f66f451Sopenharmony_ci    }
750f66f451Sopenharmony_ci  }
760f66f451Sopenharmony_ci  free(line);
770f66f451Sopenharmony_ci  fcntl(fileno(exfp), F_SETLK, &lock);
780f66f451Sopenharmony_ci  fclose(exfp);
790f66f451Sopenharmony_ci  errno = 0;
800f66f451Sopenharmony_ci  fflush(newfp);
810f66f451Sopenharmony_ci  fsync(fileno(newfp));
820f66f451Sopenharmony_ci  fclose(newfp);
830f66f451Sopenharmony_ci  rename(filenamesfx, filename);
840f66f451Sopenharmony_ci  if (errno){
850f66f451Sopenharmony_ci    perror_msg("File Writing/Saving failed: ");
860f66f451Sopenharmony_ci    unlink(filenamesfx);
870f66f451Sopenharmony_ci  }
880f66f451Sopenharmony_ci  free(filenamesfx);
890f66f451Sopenharmony_ci}
900f66f451Sopenharmony_ci
910f66f451Sopenharmony_civoid userdel_main(void)
920f66f451Sopenharmony_ci{
930f66f451Sopenharmony_ci  struct passwd *pwd = xgetpwnam(*toys.optargs);
940f66f451Sopenharmony_ci
950f66f451Sopenharmony_ci  update_password("/etc/passwd", pwd->pw_name, NULL);
960f66f451Sopenharmony_ci  update_password("/etc/shadow", pwd->pw_name, NULL);
970f66f451Sopenharmony_ci
980f66f451Sopenharmony_ci  // delete the group named USER, and remove user from group.
990f66f451Sopenharmony_ci  // could update_password() be used for this?
1000f66f451Sopenharmony_ci  // not a good idea, as update_passwd() updates one entry at a time
1010f66f451Sopenharmony_ci  // in this case it will be modifying the files as many times the
1020f66f451Sopenharmony_ci  // USER appears in group database files. So the customized version
1030f66f451Sopenharmony_ci  // of update_passwd() is here.
1040f66f451Sopenharmony_ci  update_groupfiles("/etc/group", *toys.optargs);
1050f66f451Sopenharmony_ci  update_groupfiles("/etc/gshadow", *toys.optargs);
1060f66f451Sopenharmony_ci
1070f66f451Sopenharmony_ci  if (FLAG(r)) {
1080f66f451Sopenharmony_ci    char *arg[] = {"rm", "-fr", pwd->pw_dir, NULL, NULL};
1090f66f451Sopenharmony_ci
1100f66f451Sopenharmony_ci    sprintf(toybuf, "/var/spool/mail/%s",pwd->pw_name);
1110f66f451Sopenharmony_ci    arg[3] = toybuf;
1120f66f451Sopenharmony_ci    xexec(arg);
1130f66f451Sopenharmony_ci  }
1140f66f451Sopenharmony_ci}
115