Serenity Operating System
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Userland: Add userdel program (#1217)

authored by

howar6hill and committed by
GitHub
940de40f 6eae2ef9

+194
+43
Base/usr/share/man/man8/userdel.md
··· 1 + ## Name 2 + 3 + userdel - delete a user account 4 + 5 + ## Synopsis 6 + 7 + ```**sh 8 + # userdel [-r] <login> 9 + ``` 10 + 11 + ## Description 12 + 13 + This program deletes a user account in the system. 14 + 15 + This program must be run as root. 16 + 17 + ## Options 18 + 19 + * `-r`, `--remove`: Remove the home directory for this user if the directory exists. 20 + 21 + ## Exit Values 22 + 23 + * 0 - Success 24 + * 1 - Couldn't update the password file 25 + * 6 - Specified user doesn't exist 26 + * 12 - Couldn't remove home directory 27 + 28 + ## Files 29 + 30 + * `/etc/passwd` - user information (such as UID and GID) in this file is deleted. 31 + * `/home/` - user home directroy is deleted if the `-r` flag is specified. 32 + 33 + ## Examples 34 + 35 + ```sh 36 + # userdel alice 37 + # userdel -r alice 38 + # userdel --remove alice 39 + ``` 40 + 41 + ## See Also 42 + 43 + * [`useradd`(8)](useradd.md)
+151
Userland/userdel.cpp
··· 1 + /* 2 + * Copyright (c) 2019-2020, Fei Wu <f.eiwu@yahoo.com> 3 + * All rights reserved. 4 + * 5 + * Redistribution and use in source and binary forms, with or without 6 + * modification, are permitted provided that the following conditions are met: 7 + * 8 + * 1. Redistributions of source code must retain the above copyright notice, this 9 + * list of conditions and the following disclaimer. 10 + * 11 + * 2. Redistributions in binary form must reproduce the above copyright notice, 12 + * this list of conditions and the following disclaimer in the documentation 13 + * and/or other materials provided with the distribution. 14 + * 15 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 + */ 26 + 27 + #include <AK/String.h> 28 + #include <AK/StringBuilder.h> 29 + #include <LibCore/ArgsParser.h> 30 + #include <ctype.h> 31 + #include <dirent.h> 32 + #include <errno.h> 33 + #include <pwd.h> 34 + #include <stdio.h> 35 + #include <stdlib.h> 36 + #include <string.h> 37 + #include <sys/stat.h> 38 + #include <sys/types.h> 39 + #include <sys/wait.h> 40 + #include <unistd.h> 41 + 42 + int main(int argc, char** argv) 43 + { 44 + const char* username = nullptr; 45 + bool remove_home = false; 46 + 47 + Core::ArgsParser args_parser; 48 + args_parser.add_option(remove_home, "Remove home directory", "remove", 'r'); 49 + args_parser.add_positional_argument(username, "Login user identity (username)", "login"); 50 + args_parser.parse(argc, argv); 51 + 52 + char temp_filename[] = "/etc/passwd.XXXXXX"; 53 + auto fd = mkstemp(temp_filename); 54 + if (fd == -1) { 55 + perror("failed to create temporary file"); 56 + return 1; 57 + } 58 + 59 + FILE* temp_file = fdopen(fd, "w"); 60 + if (!temp_file) { 61 + perror("fdopen"); 62 + if (unlink(temp_filename) < 0) { 63 + perror("unlink"); 64 + } 65 + 66 + return 1; 67 + } 68 + 69 + bool user_exists = false; 70 + String home_directory; 71 + 72 + int rc = 0; 73 + setpwent(); 74 + for (auto* pw = getpwent(); pw; pw = getpwent()) { 75 + if (strcmp(pw->pw_name, username)) { 76 + if (putpwent(pw, temp_file) != 0) { 77 + perror("failed to put an entry in the temporary passwd file"); 78 + rc = 1; 79 + break; 80 + } 81 + } else { 82 + user_exists = true; 83 + if (remove_home) 84 + home_directory = pw->pw_dir; 85 + } 86 + } 87 + endpwent(); 88 + 89 + if (fclose(temp_file)) { 90 + perror("fclose"); 91 + if (!rc) 92 + rc = 1; 93 + } 94 + 95 + if (rc == 0 && !user_exists) { 96 + fprintf(stderr, "specified user doesn't exist\n"); 97 + rc = 6; 98 + } 99 + 100 + if (rc == 0 && chmod(temp_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) { 101 + perror("chmod"); 102 + rc = 1; 103 + } 104 + 105 + if (rc == 0 && rename(temp_filename, "/etc/passwd") < 0) { 106 + perror("failed to rename the temporary passwd file"); 107 + rc = 1; 108 + } 109 + 110 + if (rc) { 111 + if (unlink(temp_filename) < 0) { 112 + perror("unlink"); 113 + } 114 + return rc; 115 + } 116 + 117 + if (remove_home) { 118 + if (home_directory == "/") { 119 + fprintf(stderr, "home directory is /, not deleted!\n"); 120 + return 12; 121 + } 122 + 123 + if (access(home_directory.characters(), F_OK) != -1) { 124 + auto child = fork(); 125 + 126 + if (child < 0) { 127 + perror("fork"); 128 + return 12; 129 + } 130 + 131 + if (!child) { 132 + int rc = execl("/bin/rm", "rm", "-r", home_directory.characters(), nullptr); 133 + ASSERT(rc < 0); 134 + perror("execl"); 135 + exit(127); 136 + } 137 + 138 + int wstatus; 139 + if (waitpid(child, &wstatus, 0) < 0) { 140 + perror("waitpid"); 141 + return 12; 142 + } 143 + if (WEXITSTATUS(wstatus)) { 144 + fprintf(stderr, "failed to remove the home directory\n"); 145 + return 12; 146 + } 147 + } 148 + } 149 + 150 + return 0; 151 + }