Add group{add,del,mod}
This commit is contained in:
@@ -14,7 +14,7 @@ SYSTEM_BIN = [ FFilterByBuildFeatures
|
|||||||
echo eject env error expand expr
|
echo eject env error expand expr
|
||||||
factor false fdinfo ffm filepanel find finddir FirstBootPrompt fmt fold
|
factor false fdinfo ffm filepanel find finddir FirstBootPrompt fmt fold
|
||||||
fortune frcode ftp ftpd funzip fwcontrol
|
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
|
hd head hey hostname
|
||||||
id ident ifconfig <bin>install installsound iroster isvolume
|
id ident ifconfig <bin>install installsound iroster isvolume
|
||||||
ideinfo@ide idestatus@ide
|
ideinfo@ide idestatus@ide
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ SYSTEM_BIN = [ FFilterByBuildFeatures
|
|||||||
echo eject env error expand expr
|
echo eject env error expand expr
|
||||||
factor false fdinfo ffm filepanel find finddir fmt fold
|
factor false fdinfo ffm filepanel find finddir fmt fold
|
||||||
fortune frcode ftp ftpd funzip
|
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
|
hd head hey hostname
|
||||||
id ident ifconfig <bin>install isvolume
|
id ident ifconfig <bin>install isvolume
|
||||||
ideinfo@ide idestatus@ide
|
ideinfo@ide idestatus@ide
|
||||||
|
|||||||
@@ -17,5 +17,11 @@ BinCommand useradd : useradd.cpp ;
|
|||||||
|
|
||||||
BinCommand userdel : userdel.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
|
# set set-uid bit on passwd
|
||||||
MODE on passwd = 04755 ;
|
MODE on passwd = 04755 ;
|
||||||
|
|||||||
@@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013, Ingo Weinhold, [email protected].
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013, Ingo Weinhold, [email protected].
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013, Ingo Weinhold, [email protected].
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
@@ -12,9 +12,11 @@
|
|||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <new>
|
#include <new>
|
||||||
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <DataIO.h>
|
#include <DataIO.h>
|
||||||
|
#include <StringList.h>
|
||||||
|
|
||||||
#include <AutoDeleter.h>
|
#include <AutoDeleter.h>
|
||||||
#include <RegistrarDefs.h>
|
#include <RegistrarDefs.h>
|
||||||
@@ -30,6 +32,9 @@ using std::string;
|
|||||||
using namespace BPrivate;
|
using namespace BPrivate;
|
||||||
|
|
||||||
|
|
||||||
|
typedef std::set<std::string> StringSet;
|
||||||
|
|
||||||
|
|
||||||
class AuthenticationManager::FlatStore {
|
class AuthenticationManager::FlatStore {
|
||||||
public:
|
public:
|
||||||
FlatStore()
|
FlatStore()
|
||||||
@@ -337,22 +342,29 @@ private:
|
|||||||
|
|
||||||
class AuthenticationManager::Group {
|
class AuthenticationManager::Group {
|
||||||
public:
|
public:
|
||||||
|
Group()
|
||||||
|
:
|
||||||
|
fGID(0),
|
||||||
|
fName(),
|
||||||
|
fPassword(),
|
||||||
|
fMembers()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
Group(const char* name, const char* password, gid_t gid,
|
Group(const char* name, const char* password, gid_t gid,
|
||||||
const char* const* members, int memberCount)
|
const char* const* members, int memberCount)
|
||||||
:
|
:
|
||||||
fGID(gid),
|
fGID(gid),
|
||||||
fName(name),
|
fName(name),
|
||||||
fPassword(password),
|
fPassword(password),
|
||||||
fMembers(new string[memberCount]),
|
fMembers()
|
||||||
fMemberCount(memberCount)
|
|
||||||
{
|
{
|
||||||
for (int i = 0; i < memberCount; i++)
|
for (int i = 0; i < memberCount; i++)
|
||||||
fMembers[i] = members[i];
|
fMembers.insert(members[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
~Group()
|
~Group()
|
||||||
{
|
{
|
||||||
delete[] fMembers;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const string& Name() const { return fName; }
|
const string& Name() const { return fName; }
|
||||||
@@ -360,12 +372,40 @@ public:
|
|||||||
|
|
||||||
bool HasMember(const char* name)
|
bool HasMember(const char* name)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < fMemberCount; i++) {
|
try {
|
||||||
if (fMembers[i] == name)
|
return fMembers.find(name) != fMembers.end();
|
||||||
return true;
|
} 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
|
group* WriteFlatGroup(FlatStore& store) const
|
||||||
@@ -373,15 +413,18 @@ public:
|
|||||||
struct group group;
|
struct group group;
|
||||||
|
|
||||||
char* members[MAX_GROUP_MEMBER_COUNT + 1];
|
char* members[MAX_GROUP_MEMBER_COUNT + 1];
|
||||||
for (int i = 0; i < fMemberCount; i++)
|
int32 count = 0;
|
||||||
members[i] = store.AppendString(fMembers[i].c_str());
|
for (StringSet::const_iterator it = fMembers.begin();
|
||||||
members[fMemberCount] = (char*)-1;
|
it != fMembers.end(); ++it) {
|
||||||
|
members[count++] = store.AppendString(it->c_str());
|
||||||
|
}
|
||||||
|
members[count] = (char*)-1;
|
||||||
|
|
||||||
group.gr_gid = fGID;
|
group.gr_gid = fGID;
|
||||||
group.gr_name = store.AppendString(fName);
|
group.gr_name = store.AppendString(fName);
|
||||||
group.gr_passwd = store.AppendString(fPassword);
|
group.gr_passwd = store.AppendString(fPassword);
|
||||||
group.gr_mem = (char**)store.AppendData(members,
|
group.gr_mem = (char**)store.AppendData(members,
|
||||||
sizeof(char*) * (fMemberCount + 1), true);
|
sizeof(char*) * (count + 1), true);
|
||||||
|
|
||||||
return store.AppendData(group);
|
return store.AppendData(group);
|
||||||
}
|
}
|
||||||
@@ -396,22 +439,34 @@ public:
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < fMemberCount; i++) {
|
for (StringSet::const_iterator it = fMembers.begin();
|
||||||
if ((error = message.AddString("members", fMembers[i].c_str()))
|
it != fMembers.end(); ++it) {
|
||||||
!= B_OK) {
|
if ((error = message.AddString("members", it->c_str())) != B_OK)
|
||||||
return error;
|
return error;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return B_OK;
|
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:
|
private:
|
||||||
gid_t fGID;
|
gid_t fGID;
|
||||||
string fName;
|
string fName;
|
||||||
string fPassword;
|
string fPassword;
|
||||||
string* fMembers;
|
StringSet fMembers;
|
||||||
int fMemberCount;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -555,6 +610,23 @@ public:
|
|||||||
return B_OK;
|
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
|
Group* GroupByID(gid_t gid) const
|
||||||
{
|
{
|
||||||
map<gid_t, Group*>::const_iterator it = fGroupsByID.find(gid);
|
map<gid_t, Group*>::const_iterator it = fGroupsByID.find(gid);
|
||||||
@@ -605,6 +677,31 @@ public:
|
|||||||
return count;
|
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:
|
private:
|
||||||
map<uid_t, Group*> fGroupsByID;
|
map<uid_t, Group*> fGroupsByID;
|
||||||
map<string, Group*> fGroupsByName;
|
map<string, Group*> fGroupsByName;
|
||||||
@@ -1002,10 +1099,17 @@ AuthenticationManager::_RequestThread()
|
|||||||
|
|
||||||
// apply the change
|
// apply the change
|
||||||
if (error == B_OK) {
|
if (error == B_OK) {
|
||||||
|
std::string userName = user->Name();
|
||||||
|
|
||||||
fUserDB->RemoveUser(user);
|
fUserDB->RemoveUser(user);
|
||||||
fUserDB->WriteToDisk();
|
fUserDB->WriteToDisk();
|
||||||
_InvalidatePasswdDBReply();
|
_InvalidatePasswdDBReply();
|
||||||
_InvalidateShadowPwdDBReply();
|
_InvalidateShadowPwdDBReply();
|
||||||
|
|
||||||
|
if (fGroupDB->UserRemoved(userName)) {
|
||||||
|
fGroupDB->WriteToDisk();
|
||||||
|
_InvalidateGroupDBReply();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// send reply
|
// send reply
|
||||||
@@ -1017,13 +1121,110 @@ AuthenticationManager::_RequestThread()
|
|||||||
}
|
}
|
||||||
|
|
||||||
case B_REG_UPDATE_GROUP:
|
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;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case B_REG_DELETE_GROUP:
|
case B_REG_DELETE_GROUP:
|
||||||
{
|
{
|
||||||
debug_printf(
|
// find group
|
||||||
"B_REG_DELETE_GROUP done: currently unsupported!\n");
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user