added 12 changesets to branch 'refs/remotes/HaikuPM-github/package-management' old head: 7d09a8dc6788de70bc30da84e6feb9b006c46bfb new head: 519bb60aef35f6e7371dc0ccf0a9c989036ae9b4 overview: https://github.com/haiku/HaikuPM/compare/7d09a8d...519bb60 ---------------------------------------------------------------------------- 9a85313: X86PagingStructuresPAE: Zero fPageDirPointerTable in constructor ... and use it as a guard in the destructor. Fixes crash when running out of memory and Init() is not called. c13744f: useradd: Improve usage text 222fb7a: getgrgid_r()/getgrname_r(): Fix group not found return value fb8a9c4: getpw{nam,uid}[_r]: Fix return value behavior ... when the user is not found. de15b85: getgr{nam,gid}[_r](): Fix retrieving group members 0e9e586: useradd: Support specifying group by name e9d9ac7: Add userdel 82a064b: useradd: small style fix 032ea9a: useradd: Create the new user with a locked password 6c346b8: passwd: Add option -d to delete a user's password dc3be29: Enable -Werror in src/bin/multiuser 519bb60: Add group{add,del,mod} [ Ingo Weinhold <ingo_weinhold@xxxxxx> ] ---------------------------------------------------------------------------- 16 files changed, 959 insertions(+), 115 deletions(-) build/jam/ArchitectureRules | 1 + build/jam/images/HaikuImage | 4 +- build/jam/images/HaikuImageBootstrap | 4 +- headers/private/app/RegistrarDefs.h | 2 + src/bin/multiuser/Jamfile | 10 +- src/bin/multiuser/groupadd.cpp | 109 ++++++ src/bin/multiuser/groupdel.cpp | 98 ++++++ src/bin/multiuser/groupmod.cpp | 159 +++++++++ src/bin/multiuser/passwd.cpp | 116 +++++-- src/bin/multiuser/useradd.cpp | 118 ++++--- src/bin/multiuser/userdel.cpp | 98 ++++++ src/servers/registrar/AuthenticationManager.cpp | 332 +++++++++++++++++-- src/servers/registrar/AuthenticationManager.h | 4 + .../x86/paging/pae/X86PagingStructuresPAE.cpp | 8 +- src/system/libroot/posix/grp.cpp | 9 +- src/system/libroot/posix/pwd.cpp | 2 +- ############################################################################ Commit: 9a85313bc68fde2a79e17e51726bab55eb3d85ac Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Wed Sep 18 14:12:51 2013 UTC X86PagingStructuresPAE: Zero fPageDirPointerTable in constructor ... and use it as a guard in the destructor. Fixes crash when running out of memory and Init() is not called. ---------------------------------------------------------------------------- diff --git a/src/system/kernel/arch/x86/paging/pae/X86PagingStructuresPAE.cpp b/src/system/kernel/arch/x86/paging/pae/X86PagingStructuresPAE.cpp index efffa60..99e3f1d 100644 --- a/src/system/kernel/arch/x86/paging/pae/X86PagingStructuresPAE.cpp +++ b/src/system/kernel/arch/x86/paging/pae/X86PagingStructuresPAE.cpp @@ -20,6 +20,8 @@ X86PagingStructuresPAE::X86PagingStructuresPAE() + : + fPageDirPointerTable(NULL) { memset(fVirtualPageDirs, 0, sizeof(fVirtualPageDirs)); } @@ -32,8 +34,10 @@ X86PagingStructuresPAE::~X86PagingStructuresPAE() // There's one contiguous allocation for 0 and 1. // free the PDPT page - X86PagingMethodPAE::Method()->Free32BitPage(fPageDirPointerTable, - pgdir_phys, fPageDirPointerTableHandle); + if (fPageDirPointerTable != NULL) { + X86PagingMethodPAE::Method()->Free32BitPage(fPageDirPointerTable, + pgdir_phys, fPageDirPointerTableHandle); + } } ############################################################################ Commit: c13744f4c0fc1f8b597c7a349af9218473525be2 Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Mon Sep 16 09:23:22 2013 UTC useradd: Improve usage text ---------------------------------------------------------------------------- diff --git a/src/bin/multiuser/useradd.cpp b/src/bin/multiuser/useradd.cpp index 4522084..febe75a 100644 --- a/src/bin/multiuser/useradd.cpp +++ b/src/bin/multiuser/useradd.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2008, Ingo Weinhold, ingo_weinhold@xxxxxx. All Rights Reserved. + * Copyright 2008-2013, Ingo Weinhold, ingo_weinhold@xxxxxx. * Distributed under the terms of the MIT License. */ @@ -30,9 +30,27 @@ extern const char *__progname; static const char* kUsage = -"Usage: %s [ -d <home> ] [ -e <expiration> ] [ -f <inactive> ] [ -g <gid> ]\n" -" [ -s <shell> ] [ -n <real name> ]\n" -; + "Usage: %s [ <options> ] <user name>\n" + "Creates a new user <user name>.\n" + "\n" + "Options:\n" + " -d <home>\n" + " Specifies the home directory for the new user.\n" + " -e <expiration>\n" + " Specifies the expiration date for the new user's account.\n" + " -f <inactive>\n" + " Specifies the number of days after the expiration of the new user's " + "password\n" + " until the account expires.\n" + " -g <gid>\n" + " Specifies the new user's primary group by ID or name.\n" + " -h, --help\n" + " Print usage info.\n" + " -s <shell>\n" + " Specifies the new user's login shell.\n" + " -n <real name>\n" + " Specifies the new user's real name.\n" + ; static void print_usage_and_exit(bool error) @@ -84,6 +102,7 @@ main(int argc, const char* const* argv) case 'g': gid = atoi(optarg); +// TODO: Support name! break; case 'h': ############################################################################ Commit: 222fb7a91ab71cda2bc8d7dd58227c7fd213b677 Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Mon Sep 16 10:14:34 2013 UTC getgrgid_r()/getgrname_r(): Fix group not found return value ---------------------------------------------------------------------------- diff --git a/src/system/libroot/posix/grp.cpp b/src/system/libroot/posix/grp.cpp index f8faac4..2a4882e 100644 --- a/src/system/libroot/posix/grp.cpp +++ b/src/system/libroot/posix/grp.cpp @@ -49,8 +49,9 @@ query_group_entry(const char* name, gid_t _gid, struct group *group, KMessage reply; status_t error = BPrivate::send_authentication_request_to_registrar(message, reply); - if (error != B_OK) - return error; + if (error != B_OK) { + return error == ENOENT ? B_OK : error; + } int32 gid; const char* password; ############################################################################ Commit: fb8a9c47106f9b5beaaa76416b314accc5d4562e Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Wed Sep 18 14:15:41 2013 UTC getpw{nam,uid}[_r]: Fix return value behavior ... when the user is not found. ---------------------------------------------------------------------------- diff --git a/src/system/libroot/posix/pwd.cpp b/src/system/libroot/posix/pwd.cpp index 57839ba..7d84451 100644 --- a/src/system/libroot/posix/pwd.cpp +++ b/src/system/libroot/posix/pwd.cpp @@ -50,7 +50,7 @@ query_passwd_entry(const char* name, uid_t _uid, struct passwd *passwd, status_t error = BPrivate::send_authentication_request_to_registrar(message, reply); if (error != B_OK) - return error; + return error == ENOENT ? B_OK : error; int32 uid; int32 gid; ############################################################################ Commit: de15b85e5c58a30265a5017bb16a2d3028f1eb70 Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Wed Sep 18 14:17:03 2013 UTC getgr{nam,gid}[_r](): Fix retrieving group members ---------------------------------------------------------------------------- diff --git a/src/system/libroot/posix/grp.cpp b/src/system/libroot/posix/grp.cpp index 2a4882e..f04f589 100644 --- a/src/system/libroot/posix/grp.cpp +++ b/src/system/libroot/posix/grp.cpp @@ -64,8 +64,8 @@ query_group_entry(const char* name, gid_t _gid, struct group *group, const char* members[MAX_GROUP_MEMBER_COUNT]; int memberCount = 0; - for (int memberCount = 0; memberCount < MAX_GROUP_MEMBER_COUNT;) { - if (reply.FindString("members", members + memberCount) != B_OK) + for (int32 index = 0; memberCount < MAX_GROUP_MEMBER_COUNT; index++) { + if (reply.FindString("members", index, members + memberCount) != B_OK) break; memberCount++; } ############################################################################ Commit: 0e9e586cacc38965a67a67d9f40a4f6bf4d7bda6 Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Mon Sep 16 10:15:52 2013 UTC useradd: Support specifying group by name ---------------------------------------------------------------------------- diff --git a/src/bin/multiuser/useradd.cpp b/src/bin/multiuser/useradd.cpp index febe75a..8bee29e 100644 --- a/src/bin/multiuser/useradd.cpp +++ b/src/bin/multiuser/useradd.cpp @@ -66,7 +66,7 @@ main(int argc, const char* const* argv) const char* home = "/boot/home"; int expiration = 99999; int inactive = -1; - gid_t gid = 100; + const char* group = NULL; const char* shell = "/bin/sh"; const char* realName = ""; @@ -101,9 +101,10 @@ main(int argc, const char* const* argv) break; case 'g': - gid = atoi(optarg); -// TODO: Support name! + { + group = optarg; break; + } case 'h': print_usage_and_exit(false); @@ -139,6 +140,57 @@ main(int argc, const char* const* argv) exit(1); } + // get group ID + gid_t gid = 100; + if (group != NULL) { + char* end; + gid = strtol(group, &end, 0); + if (*end == '\0') { + // seems to be a number + if (gid < 1) { + fprintf(stderr, "Error: Invalid group ID \"%s\".\n", + group); + exit(1); + } + } else { + // must be a group name -- get it + char* buffer = NULL; + ssize_t bufferSize = sysconf(_SC_GETGR_R_SIZE_MAX); + if (bufferSize <= 0) + bufferSize = 256; + for (;;) { + buffer = (char*)realloc(buffer, bufferSize); + if (buffer == NULL) { + fprintf(stderr, "Error: Out of memory!\n"); + exit(1); + } + + struct group groupBuffer; + struct group* groupFound; + int error = getgrnam_r(group, &groupBuffer, buffer, bufferSize, + &groupFound); + if (error == ERANGE) { + bufferSize *= 2; + continue; + } + + if (error != 0) { + fprintf(stderr, "Error: Failed to get info for group \"%s\".\n", + group); + exit(1); + } + if (groupFound == NULL) { + fprintf(stderr, "Error: Specified group \"%s\" doesn't " + "exist.\n", group); + exit(1); + } + + gid = groupFound->gr_gid; + break; + } + } + } + // read password char password[LINE_MAX]; if (read_password("password for user: ", password, sizeof(password), ############################################################################ Commit: e9d9ac713ffa301240e7a2e113bb0d5bb70082f8 Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Mon Sep 16 13:49:36 2013 UTC Add userdel ---------------------------------------------------------------------------- diff --git a/build/jam/images/HaikuImage b/build/jam/images/HaikuImage index fc8429a..a58a7f8 100644 --- a/build/jam/images/HaikuImage +++ b/build/jam/images/HaikuImage @@ -37,7 +37,7 @@ SYSTEM_BIN = [ FFilterByBuildFeatures tac tail tcpdump tcptester tee telnet telnetd test timeout top touch tr traceroute translate trash true truncate tsort tty uname unchop unexpand unmount uniq unlink unshar unzip unzipsfx - <bin>updatedb uptime urlwrapper useradd uudecode uuencode + <bin>updatedb uptime urlwrapper useradd userdel uudecode uuencode vdir version vmstat waitfor watch wc wget whoami writembr@x86 xargs xres yes diff --git a/build/jam/images/HaikuImageBootstrap b/build/jam/images/HaikuImageBootstrap index 1cf9810..71e5cca 100644 --- a/build/jam/images/HaikuImageBootstrap +++ b/build/jam/images/HaikuImageBootstrap @@ -37,7 +37,7 @@ SYSTEM_BIN = [ FFilterByBuildFeatures tac tail tcpdump tcptester tee telnet telnetd test timeout top touch tr traceroute trash true truncate tsort tty uname unchop unexpand unmount uniq unlink unshar unzip unzipsfx - <bin>updatedb uptime urlwrapper useradd uudecode uuencode + <bin>updatedb uptime urlwrapper useradd userdel uudecode uuencode vdir version vmstat waitfor watch wc wget whoami writembr@x86 xargs xres yes diff --git a/headers/private/app/RegistrarDefs.h b/headers/private/app/RegistrarDefs.h index c5144e2..ea3d20a 100644 --- a/headers/private/app/RegistrarDefs.h +++ b/headers/private/app/RegistrarDefs.h @@ -121,7 +121,9 @@ enum { B_REG_GET_GROUP = 'rggr', B_REG_GET_USER_GROUPS = 'rgug', B_REG_UPDATE_USER = 'ruus', + B_REG_DELETE_USER = 'rdus', B_REG_UPDATE_GROUP = 'rugr', + B_REG_DELETE_GROUP = 'rdgr', }; // B_REG_MIME_SET_PARAM "which" constants diff --git a/src/bin/multiuser/Jamfile b/src/bin/multiuser/Jamfile index 6a4bc30..24f3232 100644 --- a/src/bin/multiuser/Jamfile +++ b/src/bin/multiuser/Jamfile @@ -15,5 +15,7 @@ BinCommand passwd : passwd.cpp : libmultiuser_utils.a ; BinCommand useradd : useradd.cpp : libmultiuser_utils.a ; +BinCommand userdel : userdel.cpp ; + # set set-uid bit on passwd MODE on passwd = 04755 ; diff --git a/src/bin/multiuser/userdel.cpp b/src/bin/multiuser/userdel.cpp new file mode 100644 index 0000000..c31cff0 --- /dev/null +++ b/src/bin/multiuser/userdel.cpp @@ -0,0 +1,98 @@ +/* + * Copyright 2013, Ingo Weinhold, ingo_weinhold@xxxxxx. + * Distributed under the terms of the MIT License. + */ + +#include <getopt.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <OS.h> + +#include <RegistrarDefs.h> +#include <user_group.h> +#include <util/KMessage.h> + +#include "multiuser_utils.h" + + +extern const char *__progname; + + +static const char* kUsage = + "Usage: %s [ <options> ] <user name>\n" + "Deletes the specified user.\n" + "\n" + "Options:\n" + " -h, --help\n" + " Print usage info.\n" + ; + +static void +print_usage_and_exit(bool error) +{ + fprintf(error ? stderr : stdout, kUsage, __progname); + exit(error ? 1 : 0); +} + + +int +main(int argc, const char* const* argv) +{ + while (true) { + static struct option sLongOptions[] = { + { "help", no_argument, 0, 'h' }, + { 0, 0, 0, 0 } + }; + + opterr = 0; // don't print errors + int c = getopt_long(argc, (char**)argv, "h", sLongOptions, NULL); + if (c == -1) + break; + + + switch (c) { + case 'h': + print_usage_and_exit(false); + break; + + default: + print_usage_and_exit(true); + break; + } + } + + if (optind != argc - 1) + print_usage_and_exit(true); + + const char* user = argv[optind]; + + if (geteuid() != 0) { + fprintf(stderr, "Error: Only root may delete users.\n"); + exit(1); + } + + if (getpwnam(user) == NULL) { + fprintf(stderr, "Error: User \"%s\" doesn't exists.\n", user); + exit(1); + } + + // prepare request for the registrar + KMessage message(BPrivate::B_REG_DELETE_USER); + if (message.AddString("name", user) != B_OK) { + fprintf(stderr, "Error: Out of memory!\n"); + exit(1); + } + + // send the request + KMessage reply; + status_t error = send_authentication_request_to_registrar(message, reply); + if (error != B_OK) { + fprintf(stderr, "Error: Failed to delete user: %s\n", strerror(error)); + exit(1); + } + + return 0; +} diff --git a/src/servers/registrar/AuthenticationManager.cpp b/src/servers/registrar/AuthenticationManager.cpp index d841ad7..a3fe86a 100644 --- a/src/servers/registrar/AuthenticationManager.cpp +++ b/src/servers/registrar/AuthenticationManager.cpp @@ -435,6 +435,12 @@ public: return B_OK; } + void RemoveUser(User* user) + { + fUsersByID.erase(fUsersByID.find(user->UID())); + fUsersByName.erase(fUsersByName.find(user->Name())); + } + User* UserByID(uid_t uid) const { map<uid_t, User*>::const_iterator it = fUsersByID.find(uid); @@ -721,7 +727,7 @@ AuthenticationManager::_RequestThread() if (error == B_OK) { message.SendReply(fPasswdDBReply, -1, -1, 0, registrarTeam); } else { - fPasswdDBReply->SetTo(1); + _InvalidatePasswdDBReply(); KMessage reply(error); message.SendReply(&reply, -1, -1, 0, registrarTeam); } @@ -752,7 +758,7 @@ AuthenticationManager::_RequestThread() if (error == B_OK) { message.SendReply(fGroupDBReply, -1, -1, 0, registrarTeam); } else { - fGroupDBReply->SetTo(1); + _InvalidateGroupDBReply(); KMessage reply(error); message.SendReply(&reply, -1, -1, 0, registrarTeam); } @@ -789,7 +795,7 @@ AuthenticationManager::_RequestThread() message.SendReply(fShadowPwdDBReply, -1, -1, 0, registrarTeam); } else { - fShadowPwdDBReply->SetTo(1); + _InvalidateShadowPwdDBReply(); KMessage reply(error); message.SendReply(&reply, -1, -1, 0, registrarTeam); } @@ -915,7 +921,7 @@ AuthenticationManager::_RequestThread() error = B_BAD_VALUE; } - // only can change anything + // only root can change anything if (error == B_OK && !isRoot) error = EPERM; @@ -951,8 +957,8 @@ AuthenticationManager::_RequestThread() if (error == B_OK) { fUserDB->AddUser(user); fUserDB->WriteToDisk(); - fPasswdDBReply->SetTo(1); - fShadowPwdDBReply->SetTo(1); + _InvalidatePasswdDBReply(); + _InvalidateShadowPwdDBReply(); } } catch (...) { error = B_NO_MEMORY; @@ -971,13 +977,59 @@ AuthenticationManager::_RequestThread() break; } + + case B_REG_DELETE_USER: + { + // find user + User* user = NULL; + int32 uid; + const char* name; + + if (message.FindInt32("uid", &uid) == B_OK) { + user = fUserDB->UserByID(uid); + } else if (message.FindString("name", &name) == B_OK) { + user = fUserDB->UserByName(name); + } else { + error = B_BAD_VALUE; + } + + if (error == B_OK && user == NULL) + error = ENOENT; + + // only root can change anything + if (error == B_OK && !isRoot) + error = EPERM; + + // apply the change + if (error == B_OK) { + fUserDB->RemoveUser(user); + fUserDB->WriteToDisk(); + _InvalidatePasswdDBReply(); + _InvalidateShadowPwdDBReply(); + } + + // send reply + KMessage reply; + reply.SetWhat(error); + message.SendReply(&reply, -1, -1, 0, registrarTeam); + + break; + } + case B_REG_UPDATE_GROUP: debug_printf("B_REG_UPDATE_GROUP done: currently unsupported!\n"); break; + + case B_REG_DELETE_GROUP: + { + debug_printf( + "B_REG_DELETE_GROUP done: currently unsupported!\n"); + break; + } + default: debug_printf("REG: invalid message: %" B_PRIu32 "\n", message.What()); - } } } @@ -1132,3 +1184,24 @@ AuthenticationManager::_InitShadowPwdDB() return B_OK; } + + +void +AuthenticationManager::_InvalidatePasswdDBReply() +{ + fPasswdDBReply->SetTo(1); +} + + +void +AuthenticationManager::_InvalidateGroupDBReply() +{ + fGroupDBReply->SetTo(1); +} + + +void +AuthenticationManager::_InvalidateShadowPwdDBReply() +{ + fShadowPwdDBReply->SetTo(1); +} diff --git a/src/servers/registrar/AuthenticationManager.h b/src/servers/registrar/AuthenticationManager.h index ef43500..849cd52 100644 --- a/src/servers/registrar/AuthenticationManager.h +++ b/src/servers/registrar/AuthenticationManager.h @@ -35,6 +35,10 @@ private: status_t _InitGroupDB(); status_t _InitShadowPwdDB(); + void _InvalidatePasswdDBReply(); + void _InvalidateGroupDBReply(); + void _InvalidateShadowPwdDBReply(); + private: port_id fRequestPort; thread_id fRequestThread; ############################################################################ Commit: 82a064b57d73dded1109fa41be971d63b237fdc2 Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Mon Sep 16 14:33:26 2013 UTC useradd: small style fix ---------------------------------------------------------------------------- diff --git a/src/bin/multiuser/useradd.cpp b/src/bin/multiuser/useradd.cpp index 8bee29e..1900cfb 100644 --- a/src/bin/multiuser/useradd.cpp +++ b/src/bin/multiuser/useradd.cpp @@ -175,8 +175,8 @@ main(int argc, const char* const* argv) } if (error != 0) { - fprintf(stderr, "Error: Failed to get info for group \"%s\".\n", - group); + fprintf(stderr, "Error: Failed to get info for group " + "\"%s\".\n", group); exit(1); } if (groupFound == NULL) { ############################################################################ Commit: 032ea9a485abba103a82f0b782546dda8ff8d758 Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Mon Sep 16 16:00:48 2013 UTC useradd: Create the new user with a locked password ---------------------------------------------------------------------------- diff --git a/src/bin/multiuser/Jamfile b/src/bin/multiuser/Jamfile index 24f3232..f234bd7 100644 --- a/src/bin/multiuser/Jamfile +++ b/src/bin/multiuser/Jamfile @@ -13,7 +13,7 @@ BinCommand login : login.cpp : libmultiuser_utils.a ; BinCommand passwd : passwd.cpp : libmultiuser_utils.a ; -BinCommand useradd : useradd.cpp : libmultiuser_utils.a ; +BinCommand useradd : useradd.cpp ; BinCommand userdel : userdel.cpp ; diff --git a/src/bin/multiuser/useradd.cpp b/src/bin/multiuser/useradd.cpp index 1900cfb..476e6fa 100644 --- a/src/bin/multiuser/useradd.cpp +++ b/src/bin/multiuser/useradd.cpp @@ -130,7 +130,7 @@ main(int argc, const char* const* argv) const char* user = argv[optind]; if (geteuid() != 0) { - fprintf(stderr, "Error: You need to be root.\n"); + fprintf(stderr, "Error: Only root may add users.\n"); exit(1); } @@ -191,41 +191,6 @@ main(int argc, const char* const* argv) } } - // read password - char password[LINE_MAX]; - if (read_password("password for user: ", password, sizeof(password), - false) != B_OK) { - exit(1); - } - - if (strlen(password) >= MAX_SHADOW_PWD_PASSWORD_LEN) { - fprintf(stderr, "Error: The password is too long.\n"); - exit(1); - } - - // read password again - char repeatedPassword[LINE_MAX]; - if (read_password("repeat password: ", repeatedPassword, - sizeof(repeatedPassword), false) != B_OK) { - exit(1); - } - - // passwords need to match - if (strcmp(password, repeatedPassword) != 0) { - fprintf(stderr, "Error: passwords don't match\n"); - exit(1); - } - - memset(repeatedPassword, 0, sizeof(repeatedPassword)); - - // crypt it - char* encryptedPassword; - if (strlen(password) > 0) { - encryptedPassword = crypt(password, user); - memset(password, 0, sizeof(password)); - } else - encryptedPassword = password; - // find an unused UID uid_t uid = 1000; while (getpwuid(uid) != NULL) @@ -240,7 +205,7 @@ main(int argc, const char* const* argv) || message.AddString("home", home) != B_OK || message.AddString("shell", shell) != B_OK || message.AddString("real name", realName) != B_OK - || message.AddString("shadow password", encryptedPassword) != B_OK + || message.AddString("shadow password", "!") != B_OK || message.AddInt32("last changed", time(NULL)) != B_OK || message.AddInt32("min", min) != B_OK || message.AddInt32("max", max) != B_OK ############################################################################ Commit: 6c346b88e1134f09024879a85f358ea4992023dd Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Mon Sep 16 16:01:07 2013 UTC passwd: Add option -d to delete a user's password ---------------------------------------------------------------------------- diff --git a/src/bin/multiuser/passwd.cpp b/src/bin/multiuser/passwd.cpp index 58d8620..bd12bec 100644 --- a/src/bin/multiuser/passwd.cpp +++ b/src/bin/multiuser/passwd.cpp @@ -1,9 +1,10 @@ /* - * Copyright 2008, Ingo Weinhold, ingo_weinhold@xxxxxx. All Rights Reserved. + * Copyright 2008-2013, Ingo Weinhold, ingo_weinhold@xxxxxx. * Distributed under the terms of the MIT License. */ #include <errno.h> +#include <getopt.h> #include <pwd.h> #include <shadow.h> #include <stdio.h> @@ -28,8 +29,15 @@ extern const char *__progname; static const char* kUsage = -"Usage: %s [ <user name> ]\n" -; + "Usage: %s [ <options> ] [ <user name> ]\n" + "Deletes the specified user.\n" + "\n" + "Options:\n" + " -d\n" + " Delete the password for the specified user.\n" + " -h, --help\n" + " Print usage info.\n" + ; static void print_usage_and_exit(bool error) @@ -42,12 +50,39 @@ print_usage_and_exit(bool error) int main(int argc, const char* const* argv) { - if (argc > 2) + bool deletePassword = false;; + + while (true) { + static struct option sLongOptions[] = { + { "help", no_argument, 0, 'h' }, + { 0, 0, 0, 0 } + }; + + opterr = 0; // don't print errors + int c = getopt_long(argc, (char**)argv, "dh", sLongOptions, NULL); + if (c == -1) + break; + + + switch (c) { + case 'd': + deletePassword = true; + break; + + case 'h': + print_usage_and_exit(false); + break; + + default: + print_usage_and_exit(true); + break; + } + } + + if (optind + 1 < argc) print_usage_and_exit(true); - const char* user = NULL; - if (argc == 2) - user = argv[1]; + const char* user = optind < argc ? argv[optind] : NULL; if (geteuid() != 0) { fprintf(stderr, "Error: You need to be root.\n"); @@ -57,6 +92,18 @@ main(int argc, const char* const* argv) // this is a set-uid tool -- get the real UID uid_t uid = getuid(); + if (deletePassword) { + if (uid != 0) { + fprintf(stderr, "Error: Only root can delete users' passwords.\n"); + exit(1); + } + + if (user == NULL) { + fprintf(stderr, "Error: A user must be specified.\n"); + exit(1); + } + } + // get the passwd entry struct passwd* passwd; if (user != NULL) { @@ -90,40 +137,43 @@ main(int argc, const char* const* argv) } } - // read new password char password[LINE_MAX]; - if (read_password("new password: ", password, sizeof(password), false) - != B_OK) { - exit(1); - } + char* encryptedPassword; - if (strlen(password) >= MAX_SHADOW_PWD_PASSWORD_LEN) { - fprintf(stderr, "Error: The password is too long.\n"); - exit(1); - } + if (deletePassword) { + password[0] = '\0'; + encryptedPassword = password; + } else { + // read new password + if (read_password("new password: ", password, sizeof(password), false) + != B_OK) { + exit(1); + } - // read password again - char repeatedPassword[LINE_MAX]; - if (read_password("repeat new password: ", repeatedPassword, - sizeof(repeatedPassword), false) != B_OK) { - exit(1); - } + if (strlen(password) >= MAX_SHADOW_PWD_PASSWORD_LEN) { + fprintf(stderr, "Error: The password is too long.\n"); + exit(1); + } - // passwords need to match - if (strcmp(password, repeatedPassword) != 0) { - fprintf(stderr, "Error: passwords don't match\n"); - exit(1); - } + // read password again + char repeatedPassword[LINE_MAX]; + if (read_password("repeat new password: ", repeatedPassword, + sizeof(repeatedPassword), false) != B_OK) { + exit(1); + } + + // passwords need to match + if (strcmp(password, repeatedPassword) != 0) { + fprintf(stderr, "Error: passwords don't match\n"); + exit(1); + } - memset(repeatedPassword, 0, sizeof(repeatedPassword)); + memset(repeatedPassword, 0, sizeof(repeatedPassword)); - // crypt it - char* encryptedPassword; - if (strlen(password) > 0) { + // crypt it encryptedPassword = crypt(password, user); memset(password, 0, sizeof(password)); - } else - encryptedPassword = password; + } // prepare request for the registrar KMessage message(BPrivate::B_REG_UPDATE_USER); ############################################################################ Commit: dc3be296140d4b76f0de2630dd86e85f1ffbc8c5 Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Wed Sep 18 14:10:38 2013 UTC Enable -Werror in src/bin/multiuser ---------------------------------------------------------------------------- diff --git a/build/jam/ArchitectureRules b/build/jam/ArchitectureRules index 1181446..216ca71 100644 --- a/build/jam/ArchitectureRules +++ b/build/jam/ArchitectureRules @@ -627,6 +627,7 @@ rule ArchitectureSetupWarnings architecture EnableWerror src add-ons translators tiff ; # EnableWerror src add-ons translators wonderbrush ; EnableWerror src add-ons print ; + EnableWerror src bin multiuser ; EnableWerror src bin package ; EnableWerror src bin package_repo ; EnableWerror src bin pkgman ; ############################################################################ Commit: 519bb60aef35f6e7371dc0ccf0a9c989036ae9b4 Author: Ingo Weinhold <ingo_weinhold@xxxxxx> Date: Wed Sep 18 14:28:58 2013 UTC Add group{add,del,mod} ---------------------------------------------------------------------------- diff --git a/build/jam/images/HaikuImage b/build/jam/images/HaikuImage index a58a7f8..6ea1d85 100644 --- a/build/jam/images/HaikuImage +++ b/build/jam/images/HaikuImage @@ -14,7 +14,7 @@ SYSTEM_BIN = [ FFilterByBuildFeatures echo eject env error expand expr factor false fdinfo ffm filepanel find finddir FirstBootPrompt fmt fold fortune frcode ftp ftpd funzip fwcontrol - gawk gdb@x86 getlimits groups gzip gzexe + gawk gdb@x86 getlimits groupadd groupdel groupmod groups gzip gzexe hd head hey hostname id ident ifconfig <bin>install installsound iroster isvolume ideinfo@ide idestatus@ide diff --git a/build/jam/images/HaikuImageBootstrap b/build/jam/images/HaikuImageBootstrap index 71e5cca..ebf7d14 100644 --- a/build/jam/images/HaikuImageBootstrap +++ b/build/jam/images/HaikuImageBootstrap @@ -14,7 +14,7 @@ SYSTEM_BIN = [ FFilterByBuildFeatures echo eject env error expand expr factor false fdinfo ffm filepanel find finddir fmt fold fortune frcode ftp ftpd funzip - gawk gdb@x86 getlimits groups gzip gzexe + gawk gdb@x86 getlimits groupadd groupdel groupmod groups gzip gzexe hd head hey hostname id ident ifconfig <bin>install isvolume ideinfo@ide idestatus@ide diff --git a/src/bin/multiuser/Jamfile b/src/bin/multiuser/Jamfile index f234bd7..c79da87 100644 --- a/src/bin/multiuser/Jamfile +++ b/src/bin/multiuser/Jamfile @@ -17,5 +17,11 @@ BinCommand useradd : useradd.cpp ; BinCommand userdel : userdel.cpp ; +BinCommand groupadd : groupadd.cpp ; + +BinCommand groupdel : groupdel.cpp ; + +BinCommand groupmod : groupmod.cpp : $(TARGET_LIBSTDC++) ; + # set set-uid bit on passwd MODE on passwd = 04755 ; diff --git a/src/bin/multiuser/groupadd.cpp b/src/bin/multiuser/groupadd.cpp new file mode 100644 index 0000000..55e7bed --- /dev/null +++ b/src/bin/multiuser/groupadd.cpp @@ -0,0 +1,109 @@ +/* + * Copyright 2013, Ingo Weinhold, ingo_weinhold@xxxxxx. + * Distributed under the terms of the MIT License. + */ + +#include <errno.h> +#include <getopt.h> +#include <grp.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <OS.h> + +#include <RegistrarDefs.h> +#include <user_group.h> +#include <util/KMessage.h> + +#include "multiuser_utils.h" + + +extern const char *__progname; + + +static const char* kUsage = + "Usage: %s [ <options> ] <group name>\n" + "Creates a new group <group name>.\n" + "\n" + "Options:\n" + " -h, --help\n" + " Print usage info.\n" + ; + +static void +print_usage_and_exit(bool error) +{ + fprintf(error ? stderr : stdout, kUsage, __progname); + exit(error ? 1 : 0); +} + + +int +main(int argc, const char* const* argv) +{ + while (true) { + static struct option sLongOptions[] = { + { "help", no_argument, 0, 'h' }, + { 0, 0, 0, 0 } + }; + + opterr = 0; // don't print errors + int c = getopt_long(argc, (char**)argv, "h", sLongOptions, NULL); + if (c == -1) + break; + + + switch (c) { + case 'h': + print_usage_and_exit(false); + break; + + default: + print_usage_and_exit(true); + break; + } + } + + if (optind != argc - 1) + print_usage_and_exit(true); + + const char* group = argv[optind]; + + if (geteuid() != 0) { + fprintf(stderr, "Error: Only root may add groups.\n"); + exit(1); + } + + // check, if group already exists + if (getgrnam(group) != NULL) { + fprintf(stderr, "Error: Group \"%s\" already exists.\n", group); + exit(1); + } + + // find an unused GID + gid_t gid = 100; + while (getgrgid(gid) != NULL) + gid++; + + // prepare request for the registrar + KMessage message(BPrivate::B_REG_UPDATE_GROUP); + if (message.AddInt32("gid", gid) != B_OK + || message.AddString("name", group) != B_OK + || message.AddString("password", "x") != B_OK + || message.AddBool("add group", true) != B_OK) { + fprintf(stderr, "Error: Out of memory!\n"); + exit(1); + } + + // send the request + KMessage reply; + status_t error = send_authentication_request_to_registrar(message, reply); + if (error != B_OK) { + fprintf(stderr, "Error: Failed to create group: %s\n", strerror(error)); + exit(1); + } + + return 0; +} diff --git a/src/bin/multiuser/groupdel.cpp b/src/bin/multiuser/groupdel.cpp new file mode 100644 index 0000000..ab8d5ce --- /dev/null +++ b/src/bin/multiuser/groupdel.cpp @@ -0,0 +1,98 @@ +/* + * Copyright 2013, Ingo Weinhold, ingo_weinhold@xxxxxx. + * Distributed under the terms of the MIT License. + */ + +#include <getopt.h> +#include <grp.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <OS.h> + +#include <RegistrarDefs.h> +#include <user_group.h> +#include <util/KMessage.h> + +#include "multiuser_utils.h" + + +extern const char *__progname; + + +static const char* kUsage = + "Usage: %s [ <options> ] <group name>\n" + "Deletes the specified group.\n" + "\n" + "Options:\n" + " -h, --help\n" + " Print usage info.\n" + ; + +static void +print_usage_and_exit(bool error) +{ + fprintf(error ? stderr : stdout, kUsage, __progname); + exit(error ? 1 : 0); +} + + +int +main(int argc, const char* const* argv) +{ + while (true) { + static struct option sLongOptions[] = { + { "help", no_argument, 0, 'h' }, + { 0, 0, 0, 0 } + }; + + opterr = 0; // don't print errors + int c = getopt_long(argc, (char**)argv, "h", sLongOptions, NULL); + if (c == -1) + break; + + + switch (c) { + case 'h': + print_usage_and_exit(false); + break; + + default: + print_usage_and_exit(true); + break; + } + } + + if (optind != argc - 1) + print_usage_and_exit(true); + + const char* group = argv[optind]; + + if (geteuid() != 0) { + fprintf(stderr, "Error: Only root may delete groups.\n"); + exit(1); + } + + if (getgrnam(group) == NULL) { + fprintf(stderr, "Error: Group \"%s\" doesn't exists.\n", group); + exit(1); + } + + // prepare request for the registrar + KMessage message(BPrivate::B_REG_DELETE_GROUP); + if (message.AddString("name", group) != B_OK) { + fprintf(stderr, "Error: Out of memory!\n"); + exit(1); + } + + // send the request + KMessage reply; + status_t error = send_authentication_request_to_registrar(message, reply); + if (error != B_OK) { + fprintf(stderr, "Error: Failed to delete group: %s\n", strerror(error)); + exit(1); + } + + return 0; +} diff --git a/src/bin/multiuser/groupmod.cpp b/src/bin/multiuser/groupmod.cpp new file mode 100644 index 0000000..2fbb47d --- /dev/null +++ b/src/bin/multiuser/groupmod.cpp @@ -0,0 +1,159 @@ +/* + * Copyright 2013, Ingo Weinhold, ingo_weinhold@xxxxxx. + * Distributed under the terms of the MIT License. + */ + +#include <errno.h> +#include <getopt.h> +#include <grp.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <set> +#include <string> + +#include <OS.h> + +#include <RegistrarDefs.h> +#include <user_group.h> +#include <util/KMessage.h> + +#include "multiuser_utils.h" + + +extern const char *__progname; + + +static const char* kUsage = + "Usage: %s [ <options> ] <group name>\n" + "Creates a new group <group name>.\n" + "\n" + "Options:\n" + " -A, --add-user <user>\n" + " Add the user <user> to the group.\n" + " -h, --help\n" + " Print usage info.\n" + " -R, --remove-user <user>\n" + " Remove the user <user> from the group.\n" + ; + +static void +print_usage_and_exit(bool error) +{ + fprintf(error ? stderr : stdout, kUsage, __progname); + exit(error ? 1 : 0); +} + + +int +main(int argc, const char* const* argv) +{ + typedef std::set<std::string> StringSet; + + StringSet usersToAdd; + StringSet usersToRemove; + + while (true) { + static struct option sLongOptions[] = { + { "add-user", required_argument, 0, 'A' }, + { "help", no_argument, 0, 'h' }, + { "remove-user", required_argument, 0, 'A' }, + { 0, 0, 0, 0 } + }; + + opterr = 0; // don't print errors + int c = getopt_long(argc, (char**)argv, "A:hR:", sLongOptions, NULL); + if (c == -1) + break; + + + switch (c) { + case 'A': + usersToAdd.insert(optarg); + break; + + case 'h': + print_usage_and_exit(false); + break; + + case 'R': + usersToRemove.insert(optarg); + break; + + default: + print_usage_and_exit(true); + break; + } + } + + if (optind != argc - 1) + print_usage_and_exit(true); + + const char* group = argv[optind]; + + if (geteuid() != 0) { + fprintf(stderr, "Error: Only root may modify groups.\n"); + exit(1); + } + + // get the group + struct group* groupInfo = getgrnam(group); + if (groupInfo == NULL) { + fprintf(stderr, "Error: Group \"%s\" doesn't exist.\n", group); + exit(1); + } + + // check, if anything needs to be done + if (usersToAdd.empty() && usersToRemove.empty()) { + fprintf(stderr, "Error: No modification specified.\n"); + exit(1); + } + + // prepare request for the registrar + KMessage message(BPrivate::B_REG_UPDATE_GROUP); + if (message.AddInt32("gid", groupInfo->gr_gid) != B_OK + || message.AddString("name", group) != B_OK + || message.AddString("password", groupInfo->gr_passwd) != B_OK + || message.AddBool("add group", false) != B_OK) { + fprintf(stderr, "Error: Out of memory!\n"); + exit(1); + } + + for (int32 i = 0; const char* user = groupInfo->gr_mem[i]; i++) { + if (usersToRemove.erase(user) > 0) + continue; + + usersToAdd.insert(user); + } + + if (!usersToRemove.empty()) { + fprintf(stderr, "Error: \"%s\" is not a member of group \"%s\"\n", + usersToRemove.begin()->c_str(), group); + exit(1); + } + + // If the group doesn't have any more members, insert an empty string as an + // indicator for the registrar to remove all members. + if (usersToAdd.empty()) + usersToAdd.insert(""); + + for (StringSet::const_iterator it = usersToAdd.begin(); + it != usersToAdd.end(); ++it) { + if (message.AddString("members", it->c_str()) != B_OK) { + fprintf(stderr, "Error: Out of memory!\n"); + exit(1); + } + } + + // send the request + KMessage reply; + status_t error = send_authentication_request_to_registrar(message, reply); + if (error != B_OK) { + fprintf(stderr, "Error: Failed to create group: %s\n", strerror(error)); + exit(1); + } + + return 0; +} diff --git a/src/servers/registrar/AuthenticationManager.cpp b/src/servers/registrar/AuthenticationManager.cpp index a3fe86a..57742db 100644 --- a/src/servers/registrar/AuthenticationManager.cpp +++ b/src/servers/registrar/AuthenticationManager.cpp @@ -12,9 +12,11 @@ #include <map> #include <new> +#include <set> #include <string> #include <DataIO.h> +#include <StringList.h> #include <AutoDeleter.h> #include <RegistrarDefs.h> @@ -30,6 +32,9 @@ using std::string; using namespace BPrivate; +typedef std::set<std::string> StringSet; + + class AuthenticationManager::FlatStore { public: FlatStore() @@ -337,22 +342,29 @@ private: class AuthenticationManager::Group { public: + Group() + : + fGID(0), + fName(), + fPassword(), + fMembers() + { + } + Group(const char* name, const char* password, gid_t gid, const char* const* members, int memberCount) : fGID(gid), fName(name), fPassword(password), - fMembers(new string[memberCount]), - fMemberCount(memberCount) + fMembers() { for (int i = 0; i < memberCount; i++) - fMembers[i] = members[i]; + fMembers.insert(members[i]); } ~Group() { - delete[] fMembers; } const string& Name() const { return fName; } @@ -360,12 +372,40 @@ public: bool HasMember(const char* name) { - for (int i = 0; i < fMemberCount; i++) { - if (fMembers[i] == name) - return true; + try { + return fMembers.find(name) != fMembers.end(); + } catch (...) { + return false; } + } - return false; + bool MemberRemoved(const std::string& name) + { + return fMembers.erase(name) > 0; + } + + void UpdateFromMessage(const KMessage& message) + { + int32 intValue; + if (message.FindInt32("gid", &intValue) == B_OK) + fGID = intValue; + + const char* stringValue; + if (message.FindString("name", &stringValue) == B_OK) + fName = stringValue; + + if (message.FindString("password", &stringValue) == B_OK) + fPassword = stringValue; + + if (message.FindString("members", &stringValue) == B_OK) { + fMembers.clear(); + for (int32 i = 0; + (stringValue = message.GetString("members", i, NULL)) != NULL; + i++) { + if (stringValue != NULL && *stringValue != '\0') + fMembers.insert(stringValue); + } + } } group* WriteFlatGroup(FlatStore& store) const @@ -373,15 +413,18 @@ public: struct group group; char* members[MAX_GROUP_MEMBER_COUNT + 1]; - for (int i = 0; i < fMemberCount; i++) - members[i] = store.AppendString(fMembers[i].c_str()); - members[fMemberCount] = (char*)-1; + int32 count = 0; + for (StringSet::const_iterator it = fMembers.begin(); + it != fMembers.end(); ++it) { + members[count++] = store.AppendString(it->c_str()); + } + members[count] = (char*)-1; group.gr_gid = fGID; group.gr_name = store.AppendString(fName); group.gr_passwd = store.AppendString(fPassword); group.gr_mem = (char**)store.AppendData(members, - sizeof(char*) * (fMemberCount + 1), true); + sizeof(char*) * (count + 1), true); return store.AppendData(group); } @@ -396,22 +439,34 @@ public: return error; } - for (int i = 0; i < fMemberCount; i++) { - if ((error = message.AddString("members", fMembers[i].c_str())) - != B_OK) { + for (StringSet::const_iterator it = fMembers.begin(); + it != fMembers.end(); ++it) { + if ((error = message.AddString("members", it->c_str())) != B_OK) return error; - } } return B_OK; } + void WriteGroupLine(FILE* file) + { + fprintf(file, "%s:%s:%d:", + fName.c_str(), fPassword.c_str(), (int)fGID); + for (StringSet::const_iterator it = fMembers.begin(); + it != fMembers.end(); ++it) { + if (it == fMembers.begin()) + fprintf(file, "%s", it->c_str()); + else + fprintf(file, ",%s", it->c_str()); + } + fputs("\n", file); + } + private: - gid_t fGID; - string fName; - string fPassword; - string* fMembers; - int fMemberCount; + gid_t fGID; + string fName; + string fPassword; + StringSet fMembers; }; @@ -555,6 +610,23 @@ public: return B_OK; } + void RemoveGroup(Group* group) + { + fGroupsByID.erase(fGroupsByID.find(group->GID())); + fGroupsByName.erase(fGroupsByName.find(group->Name())); + } + + bool UserRemoved(const std::string& user) + { + bool changed = false; + for (map<gid_t, Group*>::const_iterator it = fGroupsByID.begin(); + it != fGroupsByID.end(); ++it) { + Group* group = it->second; + changed |= group->MemberRemoved(user); + } + return changed; + } + Group* GroupByID(gid_t gid) const { map<gid_t, Group*>::const_iterator it = fGroupsByID.find(gid); @@ -605,6 +677,31 @@ public: return count; } + void WriteToDisk() + { + // rename the old files + string groupBackup(kGroupFile); + groupBackup += ".old"; + + rename(kGroupFile, groupBackup.c_str()); + // Don't check errors. We can't do anything anyway. + + // open file + FILE* groupFile = fopen(kGroupFile, "w"); + if (groupFile == NULL) { + debug_printf("REG: Failed to open group file \"%s\" for " + "writing: %s\n", kGroupFile, strerror(errno)); + } + CObjectDeleter<FILE, int> _1(groupFile, fclose); + + // write groups + for (map<gid_t, Group*>::const_iterator it = fGroupsByID.begin(); + it != fGroupsByID.end(); ++it) { + Group* group = it->second; + group->WriteGroupLine(groupFile); + } + } + private: map<uid_t, Group*> fGroupsByID; map<string, Group*> fGroupsByName; @@ -1002,10 +1099,17 @@ AuthenticationManager::_RequestThread() // apply the change if (error == B_OK) { + std::string userName = user->Name(); + fUserDB->RemoveUser(user); fUserDB->WriteToDisk(); _InvalidatePasswdDBReply(); _InvalidateShadowPwdDBReply(); + + if (fGroupDB->UserRemoved(userName)) { + fGroupDB->WriteToDisk(); + _InvalidateGroupDBReply(); + } } // send reply @@ -1017,13 +1121,110 @@ AuthenticationManager::_RequestThread() } case B_REG_UPDATE_GROUP: - debug_printf("B_REG_UPDATE_GROUP done: currently unsupported!\n"); + { + // find group + Group* group = NULL; + int32 gid; + const char* name; + + if (message.FindInt32("gid", &gid) == B_OK) { + group = fGroupDB->GroupByID(gid); + } else if (message.FindString("name", &name) == B_OK) { + group = fGroupDB->GroupByName(name); + } else { + error = B_BAD_VALUE; + } + + // only root can change anything + if (error == B_OK && !isRoot) + error = EPERM; + + // check addGroup vs. existing group + bool addGroup = message.GetBool("add group", false); + if (error == B_OK) { + if (addGroup) { + if (group != NULL) + error = EEXIST; + } else if (group == NULL) + error = ENOENT; + } + + // apply all changes + if (error == B_OK) { + // clone the group object and update it from the message + Group* oldGroup = group; + group = NULL; + try { + group = (oldGroup != NULL ? new Group(*oldGroup) + : new Group); + group->UpdateFromMessage(message); + + // gid and name should remain the same + if (oldGroup != NULL) { + if (oldGroup->GID() != group->GID() + || oldGroup->Name() != group->Name()) { + error = B_BAD_VALUE; + } + } + + // replace the old group and write DBs to disk + if (error == B_OK) { + fGroupDB->AddGroup(group); + fGroupDB->WriteToDisk(); + _InvalidateGroupDBReply(); + } + } catch (...) { + error = B_NO_MEMORY; + } + + if (error == B_OK) + delete oldGroup; + else + delete group; + } + + // send reply + KMessage reply; + reply.SetWhat(error); + message.SendReply(&reply, -1, -1, 0, registrarTeam); + break; + } case B_REG_DELETE_GROUP: { - debug_printf( - "B_REG_DELETE_GROUP done: currently unsupported!\n"); + // find group + Group* group = NULL; + int32 gid; + const char* name; + + if (message.FindInt32("gid", &gid) == B_OK) { + group = fGroupDB->GroupByID(gid); + } else if (message.FindString("name", &name) == B_OK) { + group = fGroupDB->GroupByName(name); + } else { + error = B_BAD_VALUE; + } + + if (error == B_OK && group == NULL) + error = ENOENT; + + // only root can change anything + if (error == B_OK && !isRoot) + error = EPERM; + + // apply the change + if (error == B_OK) { + fGroupDB->RemoveGroup(group); + fGroupDB->WriteToDisk(); + _InvalidateGroupDBReply(); + } + + // send reply + KMessage reply; + reply.SetWhat(error); + message.SendReply(&reply, -1, -1, 0, registrarTeam); + break; }