123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379 |
- /*++
- Copyright (c) 2015 Minoca Corp. All Rights Reserved
- Module Name:
- userdel.c
- Abstract:
- This module implements the userdel command, which deletes a user account
- from the system.
- Author:
- Evan Green 11-Mar-2015
- Environment:
- POSIX
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/lib/types.h>
- #include <assert.h>
- #include <errno.h>
- #include <getopt.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include "../swlib.h"
- #include "lutil.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define USERDEL_VERSION_MAJOR 1
- #define USERDEL_VERSION_MINOR 0
- #define USERDEL_USAGE \
- "usage: userdel [options] username\n" \
- "The userdel utility deletes a user from the system. Options are:\n" \
- " -f, --force -- Force the removal of the account, even if the user \n" \
- " is still logged in, or another user uses the same home directory.\n"\
- " -r, --remove -- Delete the home directory and its files.\n" \
- " -R, --root=dir -- Chroot into the given directory before operation.\n" \
- " --help -- Displays this help text and exits.\n" \
- " --version -- Displays the application version and exits.\n"
- #define USERDEL_OPTIONS_STRING "frR:HV"
- //
- // Define application options.
- //
- //
- // Set this option to force the removal.
- //
- #define USERDEL_OPTION_FORCE 0x00000001
- //
- // Set this option to remove the home directory and mail spool.
- //
- #define USERDEL_OPTION_REMOVE 0x00000002
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- //
- // -------------------------------------------------------------------- Globals
- //
- struct option UserdelLongOptions[] = {
- {"force", no_argument, 0, 'f'},
- {"remove", no_argument, 0, 'r'},
- {"root", required_argument, 0, 'R'},
- {"help", no_argument, 0, 'H'},
- {"version", no_argument, 0, 'V'},
- {NULL, 0, 0, 0},
- };
- //
- // ------------------------------------------------------------------ Functions
- //
- INT
- UserdelMain (
- INT ArgumentCount,
- CHAR **Arguments
- )
- /*++
- Routine Description:
- This routine is the main entry point for the userdel utility.
- Arguments:
- ArgumentCount - Supplies the number of command line arguments the program
- was invoked with.
- Arguments - Supplies a tokenized array of command line arguments.
- Return Value:
- Returns an integer exit code. 0 for success, nonzero otherwise.
- --*/
- {
- ULONG ArgumentIndex;
- struct group *Group;
- int GroupCount;
- UINTN GroupIndex;
- gid_t *Groups;
- PSTR Home;
- INT Option;
- ULONG Options;
- PSTR RootDirectory;
- struct spwd Shadow;
- int Status;
- int TotalStatus;
- struct passwd *User;
- struct passwd UserCopy;
- PSTR UserName;
- memset(&Shadow, 0, sizeof(Shadow));
- Groups = NULL;
- GroupCount = 0;
- Home = NULL;
- Options = 0;
- RootDirectory = NULL;
- TotalStatus = 0;
- UserName = NULL;
- //
- // Process the control arguments.
- //
- while (TRUE) {
- Option = getopt_long(ArgumentCount,
- Arguments,
- USERDEL_OPTIONS_STRING,
- UserdelLongOptions,
- NULL);
- if (Option == -1) {
- break;
- }
- if ((Option == '?') || (Option == ':')) {
- Status = 1;
- goto MainEnd;
- }
- switch (Option) {
- case 'f':
- Options |= USERDEL_OPTION_FORCE;
- break;
- case 'r':
- Options |= USERDEL_OPTION_REMOVE;
- break;
- case 'R':
- RootDirectory = optarg;
- break;
- case 'V':
- SwPrintVersion(USERDEL_VERSION_MAJOR, USERDEL_VERSION_MINOR);
- return 1;
- case 'H':
- printf(USERDEL_USAGE);
- return 1;
- default:
- assert(FALSE);
- Status = 1;
- goto MainEnd;
- }
- }
- ArgumentIndex = optind;
- if (ArgumentIndex > ArgumentCount) {
- ArgumentIndex = ArgumentCount;
- }
- if (ArgumentIndex >= ArgumentCount) {
- SwPrintError(0, NULL, "Argument expected. Try --help for usage");
- return 1;
- }
- //
- // Chroot if requested.
- //
- if (RootDirectory != NULL) {
- Status = chroot(RootDirectory);
- if (Status != 0) {
- Status = errno;
- SwPrintError(Status, RootDirectory, "Failed to chroot");
- goto MainEnd;
- }
- Status = chdir("/");
- if (Status != 0) {
- Status = errno;
- SwPrintError(Status, RootDirectory, "Failed to chdir");
- goto MainEnd;
- }
- }
- while (ArgumentIndex < ArgumentCount) {
- UserName = Arguments[ArgumentIndex];
- ArgumentIndex += 1;
- User = getpwnam(UserName);
- if (User == NULL) {
- SwPrintError(0, UserName, "No such user");
- TotalStatus = ENOENT;
- continue;
- }
- memcpy(&UserCopy, User, sizeof(struct passwd));
- UserCopy.pw_name = UserName;
- Home = strdup(User->pw_dir);
- //
- // Get all the groups this user belongs to.
- //
- Status = getgrouplist(UserName, UserCopy.pw_gid, Groups, &GroupCount);
- if (Status < 0) {
- //
- // Allocate or reallocate the buffer. Add some extras in case
- // things shift a bit in the meantime.
- //
- Groups = realloc(Groups, (GroupCount + 5) * sizeof(gid_t));
- if (Groups == NULL) {
- Status = ENOMEM;
- goto MainEnd;
- }
- Status = getgrouplist(UserName,
- UserCopy.pw_gid,
- Groups,
- &GroupCount);
- if (Status < 0) {
- SwPrintError(0, UserName, "Failed to get groups");
- Status = errno;
- goto MainEnd;
- }
- }
- if (Status > 0) {
- //
- // Remove the user from all supplementary groups.
- //
- for (GroupIndex = 0; GroupIndex < GroupCount; GroupIndex += 1) {
- Group = getgrgid(Groups[GroupIndex]);
- if ((Group != NULL) && (Group->gr_gid != UserCopy.pw_gid)) {
- Status = SwUpdatePasswordFile(
- GROUP_FILE_PATH,
- Group->gr_name,
- NULL,
- UserName,
- UpdatePasswordDeleteGroupMember);
- if (Status != 0) {
- SwPrintError(Status,
- NULL,
- "Failed to remove user %s from group %s",
- UserName,
- Group->gr_name);
- TotalStatus = Status;
- }
- }
- }
- }
- //
- // If there is a group with the same name as the user, delete that
- // group.
- //
- Group = getgrnam(UserName);
- if (Group != NULL) {
- Status = SwUpdatePasswordFile(GROUP_FILE_PATH,
- UserName,
- NULL,
- NULL,
- UpdatePasswordDeleteLine);
- if (Status != 0) {
- TotalStatus = Status;
- }
- }
- //
- // Remove the user itself.
- //
- UserCopy.pw_name = UserName;
- Shadow.sp_namp = UserName;
- Status = SwUpdatePasswordLine(&UserCopy,
- &Shadow,
- UpdatePasswordDeleteLine);
- if (Status != 0) {
- SwPrintError(Status, UserName, "Failed to remove user");
- goto MainEnd;
- }
- //
- // Remove the home directory.
- //
- if (((Options & USERDEL_OPTION_REMOVE) != 0) && (Home != NULL)) {
- Status = SwDelete(DELETE_OPTION_RECURSIVE | DELETE_OPTION_FORCE,
- Home);
- if (Status != 0) {
- SwPrintError(Status, Home, "Failed to delete home directory");
- TotalStatus = Status;
- }
- }
- if (Home != NULL) {
- free(Home);
- Home = NULL;
- }
- }
- Status = 0;
- MainEnd:
- if (Home != NULL) {
- free(Home);
- }
- if (Groups != NULL) {
- free(Groups);
- }
- if ((TotalStatus == 0) && (Status != 0)) {
- TotalStatus = Status;
- }
- return TotalStatus;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
|