xref: /haiku/src/bin/multiuser/groupmod.cpp (revision e81a954787e50e56a7f06f72705b7859b6ab06d1)
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
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
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