1 /*
2 * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6 #include <errno.h>
7 #include <getopt.h>
8 #include <grp.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13
14 #include <set>
15 #include <string>
16
17 #include <OS.h>
18
19 #include <RegistrarDefs.h>
20 #include <user_group.h>
21 #include <util/KMessage.h>
22
23 #include "multiuser_utils.h"
24
25
26 extern const char *__progname;
27
28
29 static const char* kUsage =
30 "Usage: %s [ <options> ] <group name>\n"
31 "Creates a new group <group name>.\n"
32 "\n"
33 "Options:\n"
34 " -A, --add-user <user>\n"
35 " Add the user <user> to the group.\n"
36 " -h, --help\n"
37 " Print usage info.\n"
38 " -R, --remove-user <user>\n"
39 " Remove the user <user> from the group.\n"
40 ;
41
42 static void
print_usage_and_exit(bool error)43 print_usage_and_exit(bool error)
44 {
45 fprintf(error ? stderr : stdout, kUsage, __progname);
46 exit(error ? 1 : 0);
47 }
48
49
50 int
main(int argc,const char * const * argv)51 main(int argc, const char* const* argv)
52 {
53 typedef std::set<std::string> StringSet;
54
55 StringSet usersToAdd;
56 StringSet usersToRemove;
57
58 while (true) {
59 static struct option sLongOptions[] = {
60 { "add-user", required_argument, 0, 'A' },
61 { "help", no_argument, 0, 'h' },
62 { "remove-user", required_argument, 0, 'A' },
63 { 0, 0, 0, 0 }
64 };
65
66 opterr = 0; // don't print errors
67 int c = getopt_long(argc, (char**)argv, "A:hR:", sLongOptions, NULL);
68 if (c == -1)
69 break;
70
71
72 switch (c) {
73 case 'A':
74 usersToAdd.insert(optarg);
75 break;
76
77 case 'h':
78 print_usage_and_exit(false);
79 break;
80
81 case 'R':
82 usersToRemove.insert(optarg);
83 break;
84
85 default:
86 print_usage_and_exit(true);
87 break;
88 }
89 }
90
91 if (optind != argc - 1)
92 print_usage_and_exit(true);
93
94 const char* group = argv[optind];
95
96 if (geteuid() != 0) {
97 fprintf(stderr, "Error: Only root may modify groups.\n");
98 exit(1);
99 }
100
101 // get the group
102 struct group* groupInfo = getgrnam(group);
103 if (groupInfo == NULL) {
104 fprintf(stderr, "Error: Group \"%s\" doesn't exist.\n", group);
105 exit(1);
106 }
107
108 // check, if anything needs to be done
109 if (usersToAdd.empty() && usersToRemove.empty()) {
110 fprintf(stderr, "Error: No modification specified.\n");
111 exit(1);
112 }
113
114 // prepare request for the registrar
115 KMessage message(BPrivate::B_REG_UPDATE_GROUP);
116 if (message.AddInt32("gid", groupInfo->gr_gid) != B_OK
117 || message.AddString("name", group) != B_OK
118 || message.AddString("password", groupInfo->gr_passwd) != B_OK
119 || message.AddBool("add group", false) != B_OK) {
120 fprintf(stderr, "Error: Out of memory!\n");
121 exit(1);
122 }
123
124 for (int32 i = 0; const char* user = groupInfo->gr_mem[i]; i++) {
125 if (usersToRemove.erase(user) > 0)
126 continue;
127
128 usersToAdd.insert(user);
129 }
130
131 if (!usersToRemove.empty()) {
132 fprintf(stderr, "Error: \"%s\" is not a member of group \"%s\"\n",
133 usersToRemove.begin()->c_str(), group);
134 exit(1);
135 }
136
137 // If the group doesn't have any more members, insert an empty string as an
138 // indicator for the registrar to remove all members.
139 if (usersToAdd.empty())
140 usersToAdd.insert("");
141
142 for (StringSet::const_iterator it = usersToAdd.begin();
143 it != usersToAdd.end(); ++it) {
144 if (message.AddString("members", it->c_str()) != B_OK) {
145 fprintf(stderr, "Error: Out of memory!\n");
146 exit(1);
147 }
148 }
149
150 // send the request
151 KMessage reply;
152 status_t error = send_authentication_request_to_registrar(message, reply);
153 if (error != B_OK) {
154 fprintf(stderr, "Error: Failed to create group: %s\n", strerror(error));
155 exit(1);
156 }
157
158 return 0;
159 }
160