1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 14:57:35 +00:00

Utilities: Add groupdel

This commit is contained in:
M4x1m3 2021-07-09 17:31:23 +02:00 committed by Gunnar Beutner
parent 21cb531be1
commit 39e622c400
2 changed files with 167 additions and 0 deletions

View file

@ -0,0 +1,45 @@
## Name
groupdel - delete a group
## Synopsis
```**sh
# groupdel <group>
```
## Description
This program deletes a group in the system.
This program must be run as root.
## Caveats
You may not remove the primary group of any existing user. You must remove the user before you remove the group.
You should manually check all file systems to ensure that no files remain owned by this group.
You should manually check all users to ensure that no user remain in this group.
## Exit Values
* 0 - Success
* 1 - Couldn't update the group file
* 6 - Specified group doesn't exist
* 8 - Can't remove user's primary group
## Files
* `/etc/group` - group information (such as GID) in this file is deleted.
## Examples
```sh
# groupdel alice
```
## See Also
* [`useradd`(8)](groupadd.md)

View file

@ -0,0 +1,122 @@
/*
* Copyright (c) 2020, Fei Wu <f.eiwu@yahoo.com>
* Copyright (c) 2021, Brandon Pruitt <brapru@pm.me>
* Copyright (c) 2021, Maxime Friess <M4x1me@pm.me>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibCore/ArgsParser.h>
#include <LibCore/File.h>
#include <ctype.h>
#include <grp.h>
#include <pwd.h>
#include <unistd.h>
int main(int argc, char** argv)
{
if (pledge("stdio wpath rpath cpath fattr proc exec", nullptr) < 0) {
perror("pledge");
return 1;
}
if (unveil("/etc/", "rwc") < 0) {
perror("unveil");
return 1;
}
if (unveil("/bin/rm", "x") < 0) {
perror("unveil");
return 1;
}
char const* groupname = nullptr;
gid_t gid = 0;
Core::ArgsParser args_parser;
args_parser.add_positional_argument(groupname, "Group name", "group");
args_parser.parse(argc, argv);
setgrent();
auto* g = getgrnam(groupname);
gid = g->gr_gid;
endgrent();
// Check if the group exists
if (!g) {
warnln("group {} does not exist", groupname);
return 6;
}
// Search if the group is the primary group of an user
setpwent();
struct passwd* pw;
for (pw = getpwent(); pw; pw = getpwent()) {
if (pw->pw_gid == gid)
break;
}
// If pw is not NULL it means we ended prematuraly, aka. the group was found as primary group of an user
if (pw) {
warnln("cannot remove the primary group of user '{}'", pw->pw_name);
endpwent();
return 8;
}
endpwent();
// We can now safely delete the group
// Create a temporary group file
char temp_group[] = "/etc/group.XXXXXX";
auto unlink_temp_files = [&] {
if (unlink(temp_group) < 0)
perror("unlink");
};
ArmedScopeGuard unlink_temp_files_guard = [&] {
unlink_temp_files();
};
auto temp_group_fd = mkstemp(temp_group);
if (temp_group_fd == -1) {
perror("failed to create temporary group file");
return 1;
}
FILE* temp_group_file = fdopen(temp_group_fd, "w");
if (!temp_group_file) {
perror("fdopen");
return 1;
}
setgrent();
for (auto* gr = getgrent(); gr; gr = getgrent()) {
if (gr->gr_gid != gid) {
if (putgrent(gr, temp_group_file) != 0) {
perror("failed to put an entry in the temporary group file");
return 1;
}
}
}
endgrent();
if (fclose(temp_group_file)) {
perror("fclose");
return 1;
}
if (chmod(temp_group, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) {
perror("chmod");
return 1;
}
if (rename(temp_group, "/etc/group") < 0) {
perror("failed to rename the temporary group file");
return 1;
}
unlink_temp_files_guard.disarm();
return 0;
}