Serenity Operating System
1/*
2 * Copyright (c) 2020, Fei Wu <f.eiwu@yahoo.com>
3 * Copyright (c) 2021, Brandon Pruitt <brapru@pm.me>
4 * Copyright (c) 2021, Maxime Friess <M4x1me@pm.me>
5 * Copyright (c) 2022, Umut İnan Erdoğan <umutinanerdogan62@gmail.com>
6 *
7 * SPDX-License-Identifier: BSD-2-Clause
8 */
9
10#include <LibCore/ArgsParser.h>
11#include <LibCore/System.h>
12#include <LibMain/Main.h>
13#include <grp.h>
14#include <pwd.h>
15#include <unistd.h>
16
17ErrorOr<int> serenity_main(Main::Arguments arguments)
18{
19 TRY(Core::System::pledge("stdio wpath rpath cpath fattr proc exec"));
20 TRY(Core::System::unveil("/etc/", "rwc"));
21 TRY(Core::System::unveil("/bin/rm", "x"));
22
23 DeprecatedString groupname;
24
25 Core::ArgsParser args_parser;
26 args_parser.add_positional_argument(groupname, "Group name", "group");
27 args_parser.parse(arguments);
28
29 setgrent();
30 auto* g = getgrnam(groupname.characters());
31
32 // Check if the group exists
33 if (!g) {
34 warnln("group {} does not exist", groupname);
35 return 6;
36 }
37 auto gid = g->gr_gid;
38 endgrent();
39
40 // Search if the group is the primary group of an user
41 setpwent();
42 struct passwd* pw;
43 for (pw = getpwent(); pw; pw = getpwent()) {
44 if (pw->pw_gid == gid)
45 break;
46 }
47
48 // If pw is not NULL it means we ended prematurely, aka. the group was found as primary group of an user
49 if (pw) {
50 warnln("cannot remove the primary group of user '{}'", pw->pw_name);
51 endpwent();
52 return 8;
53 }
54
55 endpwent();
56 // We can now safely delete the group
57
58 // Create a temporary group file
59 char temp_group[] = "/etc/group.XXXXXX";
60 StringView temp_group_view { temp_group, strlen(temp_group) };
61
62 auto unlink_temp_files = [&] {
63 if (Core::System::unlink(temp_group_view).is_error())
64 perror("unlink");
65 };
66
67 ArmedScopeGuard unlink_temp_files_guard = [&] {
68 unlink_temp_files();
69 };
70
71 int temp_group_fd = TRY(Core::System::mkstemp(temp_group));
72
73 FILE* temp_group_file = fdopen(temp_group_fd, "w");
74 if (!temp_group_file) {
75 perror("fdopen");
76 return 1;
77 }
78
79 setgrent();
80 for (auto* gr = getgrent(); gr; gr = getgrent()) {
81 if (gr->gr_gid != gid) {
82 if (putgrent(gr, temp_group_file) != 0) {
83 perror("failed to put an entry in the temporary group file");
84 return 1;
85 }
86 }
87 }
88 endgrent();
89
90 if (fclose(temp_group_file)) {
91 perror("fclose");
92 return 1;
93 }
94
95 TRY(Core::System::chmod(temp_group_view, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
96 TRY(Core::System::rename(temp_group_view, "/etc/group"sv));
97
98 unlink_temp_files_guard.disarm();
99
100 return 0;
101}