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