From a94ce1c912808a0129c989f8d5c2e2aff4fec871 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 17 Apr 2008 16:19:18 +0000 Subject: [PATCH] * Reorganized the passwd and group support: A dedicated thread in the registrar provides access to the DBs via a port message based protocol. The functions in libroot just ask the registrar now. * Added Linuxish shadow passwd support. No putspent() though -- we'll provide private functions. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25002 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/posix/shadow.h | 52 + headers/private/app/RegistrarDefs.h | 13 + headers/private/libroot/libroot_private.h | 8 + headers/private/libroot/user_group.h | 109 +++ .../registrar/AuthenticationManager.cpp | 902 ++++++++++++++++++ src/servers/registrar/AuthenticationManager.h | 49 + src/servers/registrar/Jamfile | 2 + src/servers/registrar/Registrar.cpp | 9 +- src/servers/registrar/Registrar.h | 4 + src/system/libroot/posix/Jamfile | 4 +- src/system/libroot/posix/grp.cpp | 232 ++--- src/system/libroot/posix/pwd.cpp | 166 ++-- src/system/libroot/posix/shadow.cpp | 275 ++++++ .../libroot/posix/user_group_common.cpp | 562 +++-------- src/system/libroot/posix/user_group_common.h | 239 ----- 15 files changed, 1762 insertions(+), 864 deletions(-) create mode 100644 headers/posix/shadow.h create mode 100644 headers/private/libroot/user_group.h create mode 100644 src/servers/registrar/AuthenticationManager.cpp create mode 100644 src/servers/registrar/AuthenticationManager.h create mode 100644 src/system/libroot/posix/shadow.cpp delete mode 100644 src/system/libroot/posix/user_group_common.h diff --git a/headers/posix/shadow.h b/headers/posix/shadow.h new file mode 100644 index 0000000000..0b660d8e53 --- /dev/null +++ b/headers/posix/shadow.h @@ -0,0 +1,52 @@ +/* + * Copyright 2008, Haiku Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _SHADOW_H_ +#define _SHADOW_H_ + +#include +#include + +struct spwd { + char* sp_namp; /* login name */ + char* sp_pwdp; /* encrypted password */ + int sp_min; /* min days between password changes */ + int sp_max; /* max days between password changes */ + int sp_warn; /* days to warn before password expired */ + int sp_inact; /* days of inactivity until account expiration */ + int sp_expire; /* date when the account expires (days since 1970) */ + int sp_flag; /* unused */ +}; + + +#ifdef __cplusplus +extern "C" { +#endif + + +extern struct spwd* getspent(void); +extern int getspent_r(struct spwd* spwd, char* buffer, size_t bufferSize, + struct spwd** _result); +extern void setspent(void); +extern void endspent(void); + +extern struct spwd* getspnam(const char* name); +extern int getspnam_r(const char* name, struct spwd* spwd, char* buffer, + size_t bufferSize, struct spwd** _result); + +extern struct spwd* sgetspent(const char* line); +extern int sgetspent_r(const char* line, struct spwd *spwd, char *buffer, + size_t bufferSize, struct spwd** _result); + +extern struct spwd* fgetspent(FILE* file); +extern int fgetspent_r(FILE* file, struct spwd* spwd, char* buffer, + size_t bufferSize, struct spwd** _result); + + +#ifdef __cplusplus +} +#endif + + +#endif // _SHADOW_H_ diff --git a/headers/private/app/RegistrarDefs.h b/headers/private/app/RegistrarDefs.h index 2afb90adcb..a4156910f3 100644 --- a/headers/private/app/RegistrarDefs.h +++ b/headers/private/app/RegistrarDefs.h @@ -24,6 +24,9 @@ extern const char *kRAppLooperPortName; extern const char *get_roster_port_name(); +#define REGISTRAR_AUTHENTICATION_PORT_NAME "registrar: auth manager" + + // message constants enum { // replies @@ -107,6 +110,16 @@ enum { // debug_server notifications B_REG_TEAM_DEBUGGER_ALERT = 'rtda', + + // authentication requests + B_REG_GET_PASSWD_DB = 'rpdb', + B_REG_GET_GROUP_DB = 'rgdb', + B_REG_GET_SHADOW_PASSWD_DB = 'rsdb', + B_REG_GET_USER = 'rgus', + B_REG_GET_GROUP = 'rggr', + B_REG_GET_USER_GROUPS = 'rgug', + B_REG_UPDATE_USER = 'ruus', + B_REG_UPDATE_GROUP = 'rugr', }; // B_REG_MIME_SET_PARAM "which" constants diff --git a/headers/private/libroot/libroot_private.h b/headers/private/libroot/libroot_private.h index a6d0c2dcb9..2f6c95d931 100644 --- a/headers/private/libroot/libroot_private.h +++ b/headers/private/libroot/libroot_private.h @@ -34,6 +34,14 @@ // MAX_GROUP_NAME_LEN and MAX_GROUP_PASSWORD_LEN are char* aligned +#define MAX_SHADOW_PWD_NAME_LEN (32) +#define MAX_SHADOW_PWD_PASSWORD_LEN (128) + +#define MAX_SHADOW_PWD_BUFFER_SIZE ( \ + MAX_SHADOW_PWD_NAME_LEN \ + + MAX_SHADOW_PWD_PASSWORD_LEN) + + struct user_space_program_args; struct real_time_data; diff --git a/headers/private/libroot/user_group.h b/headers/private/libroot/user_group.h new file mode 100644 index 0000000000..7aba8200b1 --- /dev/null +++ b/headers/private/libroot/user_group.h @@ -0,0 +1,109 @@ +/* + * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _LIBROOT_USER_GROUP_COMMON_H +#define _LIBROOT_USER_GROUP_COMMON_H + +#include +#include +#include + +#include + +#include + + +namespace BPrivate { + +class KMessage; +class Tokenizer; + +extern const char* kPasswdFile; +extern const char* kGroupFile; +extern const char* kShadowPwdFile; + + +// locking + +status_t user_group_lock(); +status_t user_group_unlock(); + + +class UserGroupLocking { +public: + inline bool Lock(int*) + { + return user_group_lock() == B_OK; + } + + inline void Unlock(int*) + { + user_group_unlock(); + } +}; + + +class UserGroupLocker : public AutoLocker { +public: + UserGroupLocker() + : AutoLocker((int*)1) + { + } +}; + + +port_id get_registrar_authentication_port(); +status_t send_authentication_request_to_registrar(KMessage& request, + KMessage& reply); + + +template +static inline Type* +relocate_pointer(addr_t baseAddress, Type*& address) +{ + return address = (Type*)(baseAddress + (addr_t)address); +} + + +// passwd + +status_t copy_passwd_to_buffer(const char* name, const char* password, uid_t uid, + gid_t gid, const char* home, const char* shell, const char* realName, + passwd* entry, char* buffer, size_t bufferSize); +status_t copy_passwd_to_buffer(const passwd* from, passwd* entry, char* buffer, + size_t bufferSize); + +status_t parse_passwd_line(char* line, char*& name, char*& password, uid_t& uid, + gid_t& gid, char*& home, char*& shell, char*& realName); + + +// group + +status_t copy_group_to_buffer(const char* name, const char* password, gid_t gid, + const char* const* members, int memberCount, group* entry, char* buffer, + size_t bufferSize); +status_t copy_group_to_buffer(const group* from, group* entry, char* buffer, + size_t bufferSize); + +status_t parse_group_line(char* line, char*& name, char*& password, gid_t& gid, + char** members, int& memberCount); + + +// shadow password + +status_t copy_shadow_pwd_to_buffer(const char* name, const char* password, + int min, int max, int warn, int inactive, int expiration, int flags, + spwd* entry, char* buffer, size_t bufferSize); +status_t copy_shadow_pwd_to_buffer(const spwd* from, spwd* entry, + char* buffer, size_t bufferSize); + +status_t parse_shadow_pwd_line(char* line, char*& name, char*& password, + int& lastChanged, int& min, int& max, int& warn, int& inactive, + int& expiration, int& flags); + + +} // namespace BPrivate + + +#endif // _LIBROOT_USER_GROUP_COMMON_H diff --git a/src/servers/registrar/AuthenticationManager.cpp b/src/servers/registrar/AuthenticationManager.cpp new file mode 100644 index 0000000000..e3a1759411 --- /dev/null +++ b/src/servers/registrar/AuthenticationManager.cpp @@ -0,0 +1,902 @@ +/* + * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ + +#include "AuthenticationManager.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include + + +using std::map; +using std::string; + +using namespace BPrivate; + + +class AuthenticationManager::FlatStore { +public: + FlatStore() + : fSize(0) + { + fBuffer.SetBlockSize(1024); + } + + void WriteData(size_t offset, const void* data, size_t length) + { + ssize_t result = fBuffer.WriteAt(offset, data, length); + if (result < 0) + throw status_t(result); + } + + template + void WriteData(size_t offset, const Type& data) + { + WriteData(&data, sizeof(Type)); + } + + size_t ReserveSpace(size_t length, bool align) + { + if (align) + fSize = _ALIGN(fSize); + + size_t pos = fSize; + fSize += length; + + return pos; + } + + void* AppendData(const void* data, size_t length, bool align) + { + size_t pos = ReserveSpace(length, align); + WriteData(pos, data, length); + return (void*)(addr_t)pos; + } + + template + Type* AppendData(const Type& data) + { + return (Type*)AppendData(&data, sizeof(Type), true); + } + + char* AppendString(const char* string) + { + return (char*)AppendData(string, strlen(string) + 1, false); + } + + char* AppendString(const string& str) + { + return (char*)AppendData(str.c_str(), str.length() + 1, false); + } + + const void* Buffer() const + { + return fBuffer.Buffer(); + } + + size_t BufferLength() const + { + return fSize; + } + +private: + BMallocIO fBuffer; + size_t fSize; +}; + + +class AuthenticationManager::User { +public: + User(const char* name, const char* password, uid_t uid, gid_t gid, + const char* home, const char* shell, const char* realName) + : + fUID(uid), + fGID(gid), + fName(name), + fPassword(password), + fHome(home), + fShell(shell), + fRealName(realName), + fLastChanged(0), + fMin(-1), + fMax(-1), + fWarn(-1), + fInactive(-1), + fExpiration(-1), + fFlags(0) + { + } + + const string& Name() const { return fName; } + const uid_t UID() const { return fUID; } + + void SetShadowInfo(const char* password, int lastChanged, int min, int max, + int warn, int inactive, int expiration, int flags) + { + fShadowPassword = password; + fLastChanged = lastChanged; + fMin = min; + fMax = max; + fWarn = warn; + fInactive = inactive; + fExpiration = expiration; + fFlags = flags; + } + + + passwd* WriteFlatPasswd(FlatStore& store) const + { + struct passwd passwd; + + passwd.pw_uid = fUID; + passwd.pw_gid = fGID; + passwd.pw_name = store.AppendString(fName); + passwd.pw_passwd = store.AppendString(fPassword); + passwd.pw_dir = store.AppendString(fHome); + passwd.pw_shell = store.AppendString(fShell); + passwd.pw_gecos = store.AppendString(fRealName); + + return store.AppendData(passwd); + } + + spwd* WriteFlatShadowPwd(FlatStore& store) const + { + struct spwd spwd; + + spwd.sp_namp = store.AppendString(fName); + spwd.sp_pwdp = store.AppendString(fShadowPassword); + spwd.sp_min = fMin; + spwd.sp_max = fMax; + spwd.sp_warn = fWarn; + spwd.sp_inact = fInactive; + spwd.sp_expire = fExpiration; + spwd.sp_flag = fFlags; + + return store.AppendData(spwd); + } + + status_t WriteToMessage(KMessage& message, bool addShadowPwd) + { + status_t error; + if ((error = message.AddInt32("uid", fUID)) != B_OK + || (error = message.AddInt32("gid", fGID)) != B_OK + || (error = message.AddString("name", fName.c_str())) != B_OK + || (error = message.AddString("password", fPassword.c_str())) + != B_OK + || (error = message.AddString("home", fHome.c_str())) != B_OK + || (error = message.AddString("shell", fShell.c_str())) != B_OK + || (error = message.AddString("real name", fRealName.c_str())) + != B_OK) { + return error; + } + + if (!addShadowPwd) + return B_OK; + + if ((error = message.AddString("shadow password", + fShadowPassword.c_str())) != B_OK + || (error = message.AddInt32("last changed", fLastChanged)) != B_OK + || (error = message.AddInt32("min", fMin)) != B_OK + || (error = message.AddInt32("max", fMax)) != B_OK + || (error = message.AddInt32("warn", fWarn)) != B_OK + || (error = message.AddInt32("inactive", fInactive)) != B_OK + || (error = message.AddInt32("expiration", fExpiration)) != B_OK + || (error = message.AddInt32("flags", fFlags)) != B_OK) { + return error; + } + + return B_OK; + } + +private: + uid_t fUID; + gid_t fGID; + string fName; + string fPassword; + string fHome; + string fShell; + string fRealName; + string fShadowPassword; + int fLastChanged; + int fMin; + int fMax; + int fWarn; + int fInactive; + int fExpiration; + int fFlags; +}; + + +class AuthenticationManager::Group { +public: + 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) + { + for (int i = 0; i < memberCount; i++) + fMembers[i] = members[i]; + } + + ~Group() + { + delete[] fMembers; + } + + const string& Name() const { return fName; } + const gid_t GID() const { return fGID; } + + bool HasMember(const char* name) + { + for (int i = 0; i < fMemberCount; i++) { + if (fMembers[i] == name) + return true; + } + + return false; + } + + group* WriteFlatGroup(FlatStore& store) const + { + 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; + + 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); + + return store.AppendData(group); + } + + status_t WriteToMessage(KMessage& message) + { + status_t error; + if ((error = message.AddInt32("gid", fGID)) != B_OK + || (error = message.AddString("name", fName.c_str())) != B_OK + || (error = message.AddString("password", fPassword.c_str())) + != B_OK) { + return error; + } + + for (int i = 0; i < fMemberCount; i++) { + if ((error = message.AddString("members", fMembers[i].c_str())) + != B_OK) { + return error; + } + } + + return B_OK; + } + +private: + gid_t fGID; + string fName; + string fPassword; + string* fMembers; + int fMemberCount; +}; + + +class AuthenticationManager::UserDB { +public: + status_t AddUser(User* user) + { + try { + fUsersByID[user->UID()] = user; + } catch (...) { + return B_NO_MEMORY; + } + + try { + fUsersByName[user->Name()] = user; + } catch (...) { + fUsersByID.erase(fUsersByID.find(user->UID())); + return B_NO_MEMORY; + } + + return B_OK; + } + + User* UserByID(uid_t uid) const + { + map::const_iterator it = fUsersByID.find(uid); + return (it == fUsersByID.end() ? NULL : it->second); + } + + User* UserByName(const char* name) const + { + map::const_iterator it = fUsersByName.find(name); + return (it == fUsersByName.end() ? NULL : it->second); + } + + int32 WriteFlatPasswdDB(FlatStore& store) const + { + int32 count = fUsersByID.size(); + + size_t entriesSpace = sizeof(passwd*) * count; + size_t offset = store.ReserveSpace(entriesSpace, true); + passwd** entries = new passwd*[count]; + ArrayDeleter _(entries); + + int32 index = 0; + for (map::const_iterator it = fUsersByID.begin(); + it != fUsersByID.end(); ++it) { + entries[index++] = it->second->WriteFlatPasswd(store); + } + + store.WriteData(offset, entries, entriesSpace); + + return count; + } + + int32 WriteFlatShadowDB(FlatStore& store) const + { + int32 count = fUsersByID.size(); + + size_t entriesSpace = sizeof(spwd*) * count; + size_t offset = store.ReserveSpace(entriesSpace, true); + spwd** entries = new spwd*[count]; + ArrayDeleter _(entries); + + int32 index = 0; + for (map::const_iterator it = fUsersByID.begin(); + it != fUsersByID.end(); ++it) { + entries[index++] = it->second->WriteFlatShadowPwd(store); + } + + store.WriteData(offset, entries, entriesSpace); + + return count; + } + +private: + map fUsersByID; + map fUsersByName; +}; + + +class AuthenticationManager::GroupDB { +public: + status_t AddGroup(Group* group) + { + try { + fGroupsByID[group->GID()] = group; + } catch (...) { + return B_NO_MEMORY; + } + + try { + fGroupsByName[group->Name()] = group; + } catch (...) { + fGroupsByID.erase(fGroupsByID.find(group->GID())); + return B_NO_MEMORY; + } + + return B_OK; + } + + Group* GroupByID(gid_t gid) const + { + map::const_iterator it = fGroupsByID.find(gid); + return (it == fGroupsByID.end() ? NULL : it->second); + } + + Group* GroupByName(const char* name) const + { + map::const_iterator it = fGroupsByName.find(name); + return (it == fGroupsByName.end() ? NULL : it->second); + } + + int32 GetUserGroups(const char* name, gid_t* groups, int maxCount) + { + int count = 0; + + for (map::const_iterator it = fGroupsByID.begin(); + it != fGroupsByID.end(); ++it) { + Group* group = it->second; + if (group->HasMember(name)) { + if (count < maxCount) + groups[count] = group->GID(); + count++; + } + } + + return count; + } + + + int32 WriteFlatGroupDB(FlatStore& store) const + { + int32 count = fGroupsByID.size(); + + size_t entriesSpace = sizeof(group*) * count; + size_t offset = store.ReserveSpace(entriesSpace, true); + group** entries = new group*[count]; + ArrayDeleter _(entries); + + int32 index = 0; + for (map::const_iterator it = fGroupsByID.begin(); + it != fGroupsByID.end(); ++it) { + entries[index++] = it->second->WriteFlatGroup(store); + } + + store.WriteData(offset, entries, entriesSpace); + + return count; + } + +private: + map fGroupsByID; + map fGroupsByName; +}; + + +AuthenticationManager::AuthenticationManager() + : + fRequestPort(-1), + fRequestThread(-1), + fUserDB(NULL), + fGroupDB(NULL), + fPasswdDBReply(NULL), + fGroupDBReply(NULL), + fShadowPwdDBReply(NULL) +{ +} + + +AuthenticationManager::~AuthenticationManager() +{ + // delete port and wait for the request thread to finish + if (fRequestPort >= 0) + delete_port(fRequestPort); + + status_t dummy; + wait_for_thread(fRequestThread, &dummy); + + delete fUserDB; + delete fGroupDB; + delete fPasswdDBReply; + delete fGroupDBReply; + delete fShadowPwdDBReply; +} + + +status_t +AuthenticationManager::Init() +{ + fUserDB = new(std::nothrow) UserDB; + fGroupDB = new(std::nothrow) GroupDB; + fPasswdDBReply = new(std::nothrow) KMessage(1); + fGroupDBReply = new(std::nothrow) KMessage(1); + fShadowPwdDBReply = new(std::nothrow) KMessage(1); + + if (fUserDB == NULL || fGroupDB == NULL || fPasswdDBReply == NULL + || fGroupDBReply == NULL || fShadowPwdDBReply == NULL) { + return B_NO_MEMORY; + } + + fRequestPort = create_port(100, REGISTRAR_AUTHENTICATION_PORT_NAME); + if (fRequestPort < 0) + return fRequestPort; + + fRequestThread = spawn_thread(&_RequestThreadEntry, + "authentication manager", B_NORMAL_PRIORITY, this); + if (fRequestThread < 0) + return fRequestThread; + + resume_thread(fRequestThread); + + return B_OK; +} + + +status_t +AuthenticationManager::_RequestThreadEntry(void* data) +{ + return ((AuthenticationManager*)data)->_RequestThread(); +} + + +status_t +AuthenticationManager::_RequestThread() +{ + // read the DB files + _InitPasswdDB(); + _InitGroupDB(); + _InitShadowPwdDB(); + + // get our team ID + team_id registrarTeam = -1; + { + thread_info info; + if (get_thread_info(find_thread(NULL), &info) == B_OK) + registrarTeam = info.team; + } + + // request loop + while (true) { + KMessage message; + status_t error = message.ReceiveFrom(fRequestPort); + if (error != B_OK) + return B_OK; + + switch (message.What()) { + case B_REG_GET_PASSWD_DB: + { + // lazily build the reply + try { + if (fPasswdDBReply->What() == 1) { + FlatStore store; + int32 count = fUserDB->WriteFlatPasswdDB(store); + if (fPasswdDBReply->AddInt32("count", count) != B_OK + || fPasswdDBReply->AddData("entries", B_RAW_TYPE, + store.Buffer(), store.BufferLength(), + false) != B_OK) { + error = B_NO_MEMORY; + } + + fPasswdDBReply->SetWhat(0); + } + } catch (...) { + error = B_NO_MEMORY; + } + + if (error == B_OK) { + message.SendReply(fPasswdDBReply, -1, -1, 0, registrarTeam); + } else { + fPasswdDBReply->SetTo(1); + KMessage reply(error); + message.SendReply(&reply, -1, -1, 0, registrarTeam); + } + + break; + } + + case B_REG_GET_GROUP_DB: + { + // lazily build the reply + try { + if (fGroupDBReply->What() == 1) { + FlatStore store; + int32 count = fGroupDB->WriteFlatGroupDB(store); + if (fGroupDBReply->AddInt32("count", count) != B_OK + || fGroupDBReply->AddData("entries", B_RAW_TYPE, + store.Buffer(), store.BufferLength(), + false) != B_OK) { + error = B_NO_MEMORY; + } + + fGroupDBReply->SetWhat(0); + } + } catch (...) { + error = B_NO_MEMORY; + } + + if (error == B_OK) { + message.SendReply(fGroupDBReply, -1, -1, 0, registrarTeam); + } else { + fGroupDBReply->SetTo(1); + KMessage reply(error); + message.SendReply(&reply, -1, -1, 0, registrarTeam); + } + + break; + } + + + case B_REG_GET_SHADOW_PASSWD_DB: + { +// TODO: Check permissions! + // lazily build the reply + try { + if (fShadowPwdDBReply->What() == 1) { + FlatStore store; + int32 count = fUserDB->WriteFlatShadowDB(store); + if (fShadowPwdDBReply->AddInt32("count", count) != B_OK + || fShadowPwdDBReply->AddData("entries", B_RAW_TYPE, + store.Buffer(), store.BufferLength(), + false) != B_OK) { + error = B_NO_MEMORY; + } + + fShadowPwdDBReply->SetWhat(0); + } + } catch (...) { + error = B_NO_MEMORY; + } + + if (error == B_OK) { + message.SendReply(fShadowPwdDBReply, -1, -1, 0, + registrarTeam); + } else { + fShadowPwdDBReply->SetTo(1); + KMessage reply(error); + message.SendReply(&reply, -1, -1, 0, registrarTeam); + } + + break; + } + + case B_REG_GET_USER: + { + User* user = NULL; + int32 uid; + const char* name; + + // find user + 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; + + // TODO: Check permissions! + bool getShadowPwd = message.GetBool("shadow", false); + + // add user to message + KMessage reply; + if (error == B_OK) + error = user->WriteToMessage(reply, getShadowPwd); + + // send reply + reply.SetWhat(error); + message.SendReply(&reply, -1, -1, 0, registrarTeam); + + break; + } + + case B_REG_GET_GROUP: + { + Group* group = NULL; + int32 gid; + const char* name; + + // find group + 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; + + // add group to message + KMessage reply; + if (error == B_OK) + error = group->WriteToMessage(reply); + + // send reply + reply.SetWhat(error); + message.SendReply(&reply, -1, -1, 0, registrarTeam); + + break; + } + + case B_REG_GET_USER_GROUPS: + { + // get user name + const char* name; + int32 maxCount; + if (message.FindString("name", &name) != B_OK + || message.FindInt32("max count", &maxCount) != B_OK + || maxCount <= 0) { + error = B_BAD_VALUE; + } + + // get groups + gid_t groups[NGROUPS_MAX + 1]; + int32 count = 0; + if (error == B_OK) { + maxCount = min_c(maxCount, NGROUPS_MAX + 1); + count = fGroupDB->GetUserGroups(name, groups, maxCount); + } + + // add groups to message + KMessage reply; + if (error == B_OK) { + if (reply.AddInt32("count", count) != B_OK + || reply.AddData("groups", B_INT32_TYPE, + groups, min_c(maxCount, count) * sizeof(gid_t), + false) != B_OK) { + error = B_NO_MEMORY; + } + } + + // send reply + reply.SetWhat(error); + message.SendReply(&reply, -1, -1, 0, registrarTeam); + + break; + } + + case B_REG_UPDATE_USER: + case B_REG_UPDATE_GROUP: + break; + } + } +} + + +status_t +AuthenticationManager::_InitPasswdDB() +{ + FILE* file = fopen(kPasswdFile, "r"); + if (file == NULL) { + debug_printf("REG: Failed to open passwd DB file \"%s\": %s\n", + kPasswdFile, strerror(errno)); + return errno; + } + CObjectDeleter _(file, fclose); + + char lineBuffer[LINE_MAX]; + while (char* line = fgets(lineBuffer, sizeof(lineBuffer), file)) { + if (strlen(line) == 0) + continue; + + char* name; + char* password; + uid_t uid; + gid_t gid; + char* home; + char* shell; + char* realName; + + status_t error = parse_passwd_line(line, name, password, uid, gid, + home, shell, realName); + if (error != B_OK) { + debug_printf("REG: Unparsable line in passwd DB file: \"%s\"\n", + strerror(errno)); + continue; + } + + User* user = NULL; + try { + user = new User(name, password, uid, gid, home, shell, realName); + } catch (...) { + } + + if (user == NULL || fUserDB->AddUser(user) != B_OK) { + delete user; + debug_printf("REG: Out of memory\n"); + return B_NO_MEMORY; + } + } + + return B_OK; +} + + +status_t +AuthenticationManager::_InitGroupDB() +{ + FILE* file = fopen(kGroupFile, "r"); + if (file == NULL) { + debug_printf("REG: Failed to open group DB file \"%s\": %s\n", + kGroupFile, strerror(errno)); + return errno; + } + CObjectDeleter _(file, fclose); + + char lineBuffer[LINE_MAX]; + while (char* line = fgets(lineBuffer, sizeof(lineBuffer), file)) { + if (strlen(line) == 0) + continue; + + char* name; + char* password; + gid_t gid; + char* members[MAX_GROUP_MEMBER_COUNT]; + int memberCount; + + + status_t error = parse_group_line(line, name, password, gid, members, + memberCount); + if (error != B_OK) { + debug_printf("REG: Unparsable line in group DB file: \"%s\"\n", + strerror(errno)); + continue; + } + + Group* group = NULL; + try { + group = new Group(name, password, gid, members, memberCount); + } catch (...) { + } + + if (group == NULL || fGroupDB->AddGroup(group) != B_OK) { + delete group; + debug_printf("REG: Out of memory\n"); + return B_NO_MEMORY; + } + } + + return B_OK; +} + + +status_t +AuthenticationManager::_InitShadowPwdDB() +{ + FILE* file = fopen(kShadowPwdFile, "r"); + if (file == NULL) { + debug_printf("REG: Failed to open shadow passwd DB file \"%s\": %s\n", + kShadowPwdFile, strerror(errno)); + return errno; + } + CObjectDeleter _(file, fclose); + + char lineBuffer[LINE_MAX]; + while (char* line = fgets(lineBuffer, sizeof(lineBuffer), file)) { + if (strlen(line) == 0) + continue; + + char* name; + char* password; + int lastChanged; + int min; + int max; + int warn; + int inactive; + int expiration; + int flags; + + status_t error = parse_shadow_pwd_line(line, name, password, + lastChanged, min, max, warn, inactive, expiration, flags); + if (error != B_OK) { + debug_printf("REG: Unparsable line in shadow passwd DB file: " + "\"%s\"\n", strerror(errno)); + continue; + } + + User* user = fUserDB->UserByName(name); + if (user == NULL) { + debug_printf("REG: shadow pwd entry for unknown user \"%s\"\n", + name); + continue; + } + + try { + user->SetShadowInfo(password, lastChanged, min, max, warn, inactive, + expiration, flags); + } catch (...) { + debug_printf("REG: Out of memory\n"); + return B_NO_MEMORY; + } + } + + return B_OK; +} diff --git a/src/servers/registrar/AuthenticationManager.h b/src/servers/registrar/AuthenticationManager.h new file mode 100644 index 0000000000..ef435008de --- /dev/null +++ b/src/servers/registrar/AuthenticationManager.h @@ -0,0 +1,49 @@ +/* + * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef AUTHENTICATION_MANAGER_H +#define AUTHENTICATION_MANAGER_H + + +#include + + +namespace BPrivate { + class KMessage; +} + + +class AuthenticationManager { +public: + AuthenticationManager(); + ~AuthenticationManager(); + + status_t Init(); + +private: + class FlatStore; + class User; + class Group; + class UserDB; + class GroupDB; + + static status_t _RequestThreadEntry(void* data); + status_t _RequestThread(); + + status_t _InitPasswdDB(); + status_t _InitGroupDB(); + status_t _InitShadowPwdDB(); + +private: + port_id fRequestPort; + thread_id fRequestThread; + UserDB* fUserDB; + GroupDB* fGroupDB; + BPrivate::KMessage* fPasswdDBReply; + BPrivate::KMessage* fGroupDBReply; + BPrivate::KMessage* fShadowPwdDBReply; +}; + + +#endif // AUTHENTICATION_MANAGER_H diff --git a/src/servers/registrar/Jamfile b/src/servers/registrar/Jamfile index a686fccda6..d58a0ab5da 100644 --- a/src/servers/registrar/Jamfile +++ b/src/servers/registrar/Jamfile @@ -2,6 +2,7 @@ SubDir HAIKU_TOP src servers registrar ; UsePrivateHeaders app ; UsePrivateHeaders kernel ; +UsePrivateHeaders libroot ; UsePrivateHeaders shared ; UsePrivateHeaders storage ; UsePrivateHeaders tracker ; @@ -13,6 +14,7 @@ Server registrar : AppInfoList.cpp AppInfoListMessagingTargetSet.cpp + AuthenticationManager.cpp Clipboard.cpp ClipboardHandler.cpp Event.cpp diff --git a/src/servers/registrar/Registrar.cpp b/src/servers/registrar/Registrar.cpp index 4c39d7f2d0..4885e429bf 100644 --- a/src/servers/registrar/Registrar.cpp +++ b/src/servers/registrar/Registrar.cpp @@ -19,6 +19,7 @@ #include #include +#include "AuthenticationManager.h" #include "ClipboardHandler.h" #include "Debug.h" #include "EventQueue.h" @@ -60,7 +61,8 @@ Registrar::Registrar(status_t *error) fEventQueue(NULL), fMessageRunnerManager(NULL), fSanityEvent(NULL), - fShutdownProcess(NULL) + fShutdownProcess(NULL), + fAuthenticationManager(NULL) { FUNCTION_START(); } @@ -76,6 +78,7 @@ Registrar::~Registrar() FUNCTION_START(); Lock(); fEventQueue->Die(); + delete fAuthenticationManager; delete fMessageRunnerManager; delete fEventQueue; delete fSanityEvent; @@ -130,6 +133,10 @@ Registrar::ReadyToRun() // create event queue fEventQueue = new EventQueue(kEventQueueName); + // create authentication manager + fAuthenticationManager = new AuthenticationManager; + fAuthenticationManager->Init(); + // create roster fRoster = new TRoster; fRoster->Init(); diff --git a/src/servers/registrar/Registrar.h b/src/servers/registrar/Registrar.h index 6b78455b1c..26c4a50f7d 100644 --- a/src/servers/registrar/Registrar.h +++ b/src/servers/registrar/Registrar.h @@ -28,6 +28,8 @@ #include + +class AuthenticationManager; class ClipboardHandler; class DiskDeviceManager; class EventQueue; @@ -38,6 +40,7 @@ class ShutdownProcess; class TRoster; + class Registrar : public BServer { public: Registrar(status_t *error); @@ -62,6 +65,7 @@ private: MessageRunnerManager *fMessageRunnerManager; MessageEvent *fSanityEvent; ShutdownProcess *fShutdownProcess; + AuthenticationManager *fAuthenticationManager; }; #endif // REGISTRAR_H diff --git a/src/system/libroot/posix/Jamfile b/src/system/libroot/posix/Jamfile index 8318e08d19..81b0fc1a47 100644 --- a/src/system/libroot/posix/Jamfile +++ b/src/system/libroot/posix/Jamfile @@ -1,12 +1,12 @@ SubDir HAIKU_TOP src system libroot posix ; -UsePrivateHeaders shared [ FDirName syslog_daemon ] ; +UsePrivateHeaders app shared [ FDirName syslog_daemon ] ; UseHeaders $(TARGET_PRIVATE_KERNEL_HEADERS) : true ; if $(HAIKU_MULTIUSER_QUERY) = 1 { PWD_BACKEND = pwd_query.c ; } else { - PWD_BACKEND = pwd.cpp grp.cpp user_group_common.cpp ; + PWD_BACKEND = pwd.cpp grp.cpp shadow.cpp user_group_common.cpp ; } MergeObject posix_main.o : assert.c diff --git a/src/system/libroot/posix/grp.cpp b/src/system/libroot/posix/grp.cpp index 307126a20d..e28db529f6 100644 --- a/src/system/libroot/posix/grp.cpp +++ b/src/system/libroot/posix/grp.cpp @@ -14,111 +14,109 @@ #include #include +#include +#include -#include "user_group_common.h" +#include -using BPrivate::GroupDB; -using BPrivate::GroupDBReader; -using BPrivate::GroupEntryHandler; using BPrivate::UserGroupLocker; +using BPrivate::relocate_pointer; -static GroupDB* sGroupDB = NULL; + +static KMessage sGroupDBReply; +static group** sGroupEntries = NULL; +static size_t sGroupEntryCount = 0; +static size_t sIterationIndex = 0; static struct group sGroupBuffer; static char sGroupStringBuffer[MAX_GROUP_BUFFER_SIZE]; -namespace { +static status_t +query_group_entry(const char* name, gid_t _gid, struct group *group, + char *buffer, size_t bufferSize, struct group **_result) +{ + *_result = NULL; -class GroupEntryFindHandler : public GroupEntryHandler { -public: - GroupEntryFindHandler(const char* name, uid_t gid, - group* entry, char* buffer, size_t bufferSize) - : - fName(name), - fGID(gid), - fEntry(entry), - fBuffer(buffer), - fBufferSize(bufferSize) - { + KMessage message(BPrivate::B_REG_GET_GROUP); + if (name) + message.AddString("name", name); + else + message.AddInt32("gid", _gid); + + KMessage reply; + status_t error = BPrivate::send_authentication_request_to_registrar(message, + reply); + if (error != B_OK) + return error; + + int32 gid; + const char* password; + + if ((error = reply.FindInt32("gid", &gid)) != B_OK + || (error = reply.FindString("name", &name)) != B_OK + || (error = reply.FindString("password", &password)) != B_OK) { + return error; } - virtual status_t HandleEntry(const char* name, const char* password, - gid_t gid, const char* const* members, int memberCount) - { - if (fName != NULL ? strcmp(fName, name) != 0 : fGID != gid) - return 0; - - // found - status_t error = BPrivate::copy_group_to_buffer(name, password, gid, - members, memberCount, fEntry, fBuffer, fBufferSize); - - return error == B_OK ? 1 : error; + 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) + break; + memberCount++; } -private: - const char* fName; - gid_t fGID; - group* fEntry; - char* fBuffer; - size_t fBufferSize; -}; + error = BPrivate::copy_group_to_buffer(name, password, gid, members, + memberCount, group, buffer, bufferSize); + if (error == B_OK) + *_result = group; + + return error; +} -class UserGroupEntryHandler : public BPrivate::GroupEntryHandler { -public: - UserGroupEntryHandler(const char* user, gid_t* groupList, int maxGroupCount, - int* groupCount) - : - fUser(user), - fGroupList(groupList), - fMaxGroupCount(maxGroupCount), - fGroupCount(groupCount) - { - } - - virtual status_t HandleEntry(const char* name, const char* password, - gid_t gid, const char* const* members, int memberCount) - { - for (int i = 0; i < memberCount; i++) { - const char* member = members[i]; - if (*member != '\0' && strcmp(member, fUser) == 0) { - if (*fGroupCount < fMaxGroupCount) - fGroupList[*fGroupCount] = gid; - ++*fGroupCount; - } - } - - return 0; - } - -private: - const char* fUser; - gid_t* fGroupList; - int fMaxGroupCount; - int* fGroupCount; -}; - -} // empty namespace - - -static GroupDB* +static status_t init_group_db() { - if (sGroupDB != NULL) - return sGroupDB; + if (sGroupEntries != NULL) + return B_OK; - sGroupDB = new(std::nothrow) GroupDB; - if (sGroupDB == NULL) - return NULL; + // ask the registrar + KMessage message(BPrivate::B_REG_GET_GROUP_DB); + status_t error = BPrivate::send_authentication_request_to_registrar(message, + sGroupDBReply); + if (error != B_OK) + return error; - if (sGroupDB->Init() != B_OK) { - delete sGroupDB; - sGroupDB = NULL; + // unpack the reply + int32 count; + group** entries; + int32 numBytes; + if ((error = sGroupDBReply.FindInt32("count", &count)) != B_OK + || (error = sGroupDBReply.FindData("entries", B_RAW_TYPE, + (const void**)&entries, &numBytes)) != B_OK) { + return error; } - return sGroupDB; + // relocate the entries + addr_t baseAddress = (addr_t)entries; + for (int32 i = 0; i < count; i++) { + group* entry = relocate_pointer(baseAddress, entries[i]); + relocate_pointer(baseAddress, entry->gr_name); + relocate_pointer(baseAddress, entry->gr_passwd); + relocate_pointer(baseAddress, entry->gr_mem); + int32 k = 0; + for (; entry->gr_mem[k] != (void*)-1; k++) + relocate_pointer(baseAddress, entry->gr_mem[k]); + entry->gr_mem[k] = NULL; + } + + sGroupEntries = entries; + sGroupEntryCount = count; + + return B_OK; } @@ -147,11 +145,17 @@ getgrent_r(struct group* group, char* buffer, size_t bufferSize, *_result = NULL; - if (GroupDB* db = init_group_db()) { - status = db->GetNextEntry(group, buffer, bufferSize); - if (status == 0) - *_result = group; + if ((status = init_group_db()) == B_OK) { + if (sIterationIndex >= sGroupEntryCount) + return ENOENT; + status = BPrivate::copy_group_to_buffer( + sGroupEntries[sIterationIndex], group, buffer, bufferSize); + + if (status == B_OK) { + sIterationIndex++; + *_result = group; + } } return status; @@ -163,8 +167,7 @@ setgrent(void) { UserGroupLocker _; - if (GroupDB* db = init_group_db()) - db->RewindEntries(); + sIterationIndex = 0; } @@ -173,12 +176,10 @@ endgrent(void) { UserGroupLocker locker; - GroupDB* db = sGroupDB; - sGroupDB = NULL; - - locker.Unlock(); - - delete db; + sGroupDBReply.Unset(); + sGroupEntries = NULL; + sGroupEntryCount = 0; + sIterationIndex = 0; } @@ -198,11 +199,7 @@ int getgrnam_r(const char *name, struct group *group, char *buffer, size_t bufferSize, struct group **_result) { - GroupEntryFindHandler handler(name, 0, group, buffer, bufferSize); - status_t status = GroupDBReader(&handler).Read(BPrivate::kGroupFile); - - *_result = (status == 1 ? group : NULL); - return (status == 1 ? 0 : (status == 0 ? ENOENT : status)); + return query_group_entry(name, 0, group, buffer, bufferSize, _result); } @@ -222,11 +219,7 @@ int getgrgid_r(gid_t gid, struct group *group, char *buffer, size_t bufferSize, struct group **_result) { - GroupEntryFindHandler handler(NULL, gid, group, buffer, bufferSize); - status_t status = GroupDBReader(&handler).Read(BPrivate::kGroupFile); - - *_result = (status == 1 ? group : NULL); - return (status == 1 ? 0 : (status == 0 ? ENOENT : status)); + return query_group_entry(NULL, gid, group, buffer, bufferSize, _result); } @@ -237,10 +230,35 @@ getgrouplist(const char* user, gid_t baseGroup, gid_t* groupList, int maxGroupCount = *groupCount; *groupCount = 0; - UserGroupEntryHandler handler(user, groupList, maxGroupCount, groupCount); - BPrivate::GroupDBReader(&handler).Read(BPrivate::kGroupFile); + status_t error = B_OK; - // put in the base group + // prepare request + KMessage message(BPrivate::B_REG_GET_USER_GROUPS); + if (message.AddString("name", user) != B_OK + || message.AddInt32("max count", maxGroupCount) != B_OK) { + return -1; + } + + // send request + KMessage reply; + error = BPrivate::send_authentication_request_to_registrar(message, reply); + if (error != B_OK) + return -1; + + // unpack reply + int32 count; + const int32* groups; + int32 groupsSize; + if (reply.FindInt32("count", &count) != B_OK + || reply.FindData("groups", B_INT32_TYPE, (const void**)&groups, + &groupsSize) != B_OK) { + return -1; + } + + memcpy(groupList, groups, groupsSize); + *groupCount = count; + + // add the base group if (*groupCount < maxGroupCount) groupList[*groupCount] = baseGroup; ++*groupCount; diff --git a/src/system/libroot/posix/pwd.cpp b/src/system/libroot/posix/pwd.cpp index fcb1575977..aa4ac55a60 100644 --- a/src/system/libroot/posix/pwd.cpp +++ b/src/system/libroot/posix/pwd.cpp @@ -14,76 +14,107 @@ #include #include +#include +#include -#include "user_group_common.h" +#include -using BPrivate::PasswdDB; -using BPrivate::PasswdDBReader; -using BPrivate::PasswdEntryHandler; using BPrivate::UserGroupLocker; +using BPrivate::relocate_pointer; -static PasswdDB* sPasswdDB = NULL; + +static KMessage sPasswdDBReply; +static passwd** sPasswdEntries = NULL; +static size_t sPasswdEntryCount = 0; +static size_t sIterationIndex = 0; static struct passwd sPasswdBuffer; static char sPasswdStringBuffer[MAX_PASSWD_BUFFER_SIZE]; -namespace { +static status_t +query_passwd_entry(const char* name, uid_t _uid, struct passwd *passwd, + char *buffer, size_t bufferSize, struct passwd **_result) +{ + *_result = NULL; -class PasswdEntryFindHandler : public PasswdEntryHandler { -public: - PasswdEntryFindHandler(const char* name, uid_t uid, - passwd* entry, char* buffer, size_t bufferSize) - : - fName(name), - fUID(uid), - fEntry(entry), - fBuffer(buffer), - fBufferSize(bufferSize) - { + KMessage message(BPrivate::B_REG_GET_USER); + if (name) + message.AddString("name", name); + else + message.AddInt32("uid", _uid); + + KMessage reply; + status_t error = BPrivate::send_authentication_request_to_registrar(message, + reply); + if (error != B_OK) + return error; + + int32 uid; + int32 gid; + const char* password; + const char* home; + const char* shell; + const char* realName; + + if ((error = reply.FindInt32("uid", &uid)) != B_OK + || (error = reply.FindInt32("gid", &gid)) != B_OK + || (error = reply.FindString("name", &name)) != B_OK + || (error = reply.FindString("password", &password)) != B_OK + || (error = reply.FindString("home", &home)) != B_OK + || (error = reply.FindString("shell", &shell)) != B_OK + || (error = reply.FindString("real name", &realName)) != B_OK) { + return error; } - virtual status_t HandleEntry(const char* name, const char* password, - uid_t uid, gid_t gid, const char* home, const char* shell, - const char* realName) - { - if (fName != NULL ? strcmp(fName, name) != 0 : fUID != uid) - return 0; + error = BPrivate::copy_passwd_to_buffer(name, password, uid, gid, home, + shell, realName, passwd, buffer, bufferSize); + if (error == B_OK) + *_result = passwd; - // found - status_t error = BPrivate::copy_passwd_to_buffer(name, password, uid, - gid, home, shell, realName, fEntry, fBuffer, fBufferSize); - return error == B_OK ? 1 : error; - } - -private: - const char* fName; - uid_t fUID; - passwd* fEntry; - char* fBuffer; - size_t fBufferSize; -}; - -} // empty namespace + return error; +} -static PasswdDB* +static status_t init_passwd_db() { - if (sPasswdDB != NULL) - return sPasswdDB; + if (sPasswdEntries != NULL) + return B_OK; - sPasswdDB = new(std::nothrow) PasswdDB; - if (sPasswdDB == NULL) - return NULL; + // ask the registrar + KMessage message(BPrivate::B_REG_GET_PASSWD_DB); + status_t error = BPrivate::send_authentication_request_to_registrar(message, + sPasswdDBReply); + if (error != B_OK) + return error; - if (sPasswdDB->Init() != B_OK) { - delete sPasswdDB; - sPasswdDB = NULL; + // unpack the reply + int32 count; + passwd** entries; + int32 numBytes; + if ((error = sPasswdDBReply.FindInt32("count", &count)) != B_OK + || (error = sPasswdDBReply.FindData("entries", B_RAW_TYPE, + (const void**)&entries, &numBytes)) != B_OK) { + return error; } - return sPasswdDB; + // relocate the entries + addr_t baseAddress = (addr_t)entries; + for (int32 i = 0; i < count; i++) { + passwd* entry = relocate_pointer(baseAddress, entries[i]); + relocate_pointer(baseAddress, entry->pw_name); + relocate_pointer(baseAddress, entry->pw_passwd); + relocate_pointer(baseAddress, entry->pw_dir); + relocate_pointer(baseAddress, entry->pw_shell); + relocate_pointer(baseAddress, entry->pw_gecos); + } + + sPasswdEntries = entries; + sPasswdEntryCount = count; + + return B_OK; } @@ -112,11 +143,17 @@ getpwent_r(struct passwd* passwd, char* buffer, size_t bufferSize, *_result = NULL; - if (PasswdDB* db = init_passwd_db()) { - status = db->GetNextEntry(passwd, buffer, bufferSize); - if (status == 0) - *_result = passwd; + if ((status = init_passwd_db()) == B_OK) { + if (sIterationIndex >= sPasswdEntryCount) + return ENOENT; + status = BPrivate::copy_passwd_to_buffer( + sPasswdEntries[sIterationIndex], passwd, buffer, bufferSize); + + if (status == B_OK) { + sIterationIndex++; + *_result = passwd; + } } return status; @@ -128,8 +165,7 @@ setpwent(void) { UserGroupLocker _; - if (PasswdDB* db = init_passwd_db()) - db->RewindEntries(); + sIterationIndex = 0; } @@ -138,12 +174,10 @@ endpwent(void) { UserGroupLocker locker; - PasswdDB* db = sPasswdDB; - sPasswdDB = NULL; - - locker.Unlock(); - - delete db; + sPasswdDBReply.Unset(); + sPasswdEntries = NULL; + sPasswdEntryCount = 0; + sIterationIndex = 0; } @@ -163,11 +197,7 @@ int getpwnam_r(const char *name, struct passwd *passwd, char *buffer, size_t bufferSize, struct passwd **_result) { - PasswdEntryFindHandler handler(name, 0, passwd, buffer, bufferSize); - status_t status = PasswdDBReader(&handler).Read(BPrivate::kPasswdFile); - - *_result = (status == 1 ? passwd : NULL); - return (status == 1 ? 0 : (status == 0 ? ENOENT : status)); + return query_passwd_entry(name, 0, passwd, buffer, bufferSize, _result); } @@ -187,9 +217,5 @@ int getpwuid_r(uid_t uid, struct passwd *passwd, char *buffer, size_t bufferSize, struct passwd **_result) { - PasswdEntryFindHandler handler(NULL, uid, passwd, buffer, bufferSize); - status_t status = PasswdDBReader(&handler).Read(BPrivate::kPasswdFile); - - *_result = (status == 1 ? passwd : NULL); - return (status == 1 ? 0 : (status == 0 ? ENOENT : status)); + return query_passwd_entry(NULL, uid, passwd, buffer, bufferSize, _result); } diff --git a/src/system/libroot/posix/shadow.cpp b/src/system/libroot/posix/shadow.cpp new file mode 100644 index 0000000000..58c05f19d3 --- /dev/null +++ b/src/system/libroot/posix/shadow.cpp @@ -0,0 +1,275 @@ +/* + * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ + +#include + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +#include + + +using BPrivate::UserGroupLocker; +using BPrivate::relocate_pointer; + + +static KMessage sShadowPwdDBReply; +static spwd** sShadowPwdEntries = NULL; +static size_t sShadowPwdEntryCount = 0; +static size_t sIterationIndex = 0; + +static struct spwd sShadowPwdBuffer; +static char sShadowPwdStringBuffer[MAX_SHADOW_PWD_BUFFER_SIZE]; + + +static status_t +init_shadow_pwd_db() +{ + if (sShadowPwdEntries != NULL) + return B_OK; + + // ask the registrar + KMessage message(BPrivate::B_REG_GET_SHADOW_PASSWD_DB); + status_t error = BPrivate::send_authentication_request_to_registrar(message, + sShadowPwdDBReply); + if (error != B_OK) + return error; + + // unpack the reply + int32 count; + spwd** entries; + int32 numBytes; + if ((error = sShadowPwdDBReply.FindInt32("count", &count)) != B_OK + || (error = sShadowPwdDBReply.FindData("entries", B_RAW_TYPE, + (const void**)&entries, &numBytes)) != B_OK) { + return error; + } + + // relocate the entries + addr_t baseAddress = (addr_t)entries; + for (int32 i = 0; i < count; i++) { + spwd* entry = relocate_pointer(baseAddress, entries[i]); + relocate_pointer(baseAddress, entry->sp_namp); + relocate_pointer(baseAddress, entry->sp_pwdp); + } + + sShadowPwdEntries = entries; + sShadowPwdEntryCount = count; + + return B_OK; +} + + +// #pragma mark - + + +struct spwd* +getspent(void) +{ + struct spwd* result = NULL; + int status = getspent_r(&sShadowPwdBuffer, sShadowPwdStringBuffer, + sizeof(sShadowPwdStringBuffer), &result); + if (status != 0) + errno = status; + return result; +} + + +int +getspent_r(struct spwd* spwd, char* buffer, size_t bufferSize, + struct spwd** _result) +{ + UserGroupLocker _; + + int status = B_NO_MEMORY; + + *_result = NULL; + + if ((status = init_shadow_pwd_db()) == B_OK) { + if (sIterationIndex >= sShadowPwdEntryCount) + return ENOENT; + + status = BPrivate::copy_shadow_pwd_to_buffer( + sShadowPwdEntries[sIterationIndex], spwd, buffer, bufferSize); + + if (status == B_OK) { + sIterationIndex++; + *_result = spwd; + } + } + + return status; +} + + +void +setspent(void) +{ + UserGroupLocker _; + + sIterationIndex = 0; +} + + +void +endspent(void) +{ + UserGroupLocker locker; + + sShadowPwdDBReply.Unset(); + sShadowPwdEntries = NULL; + sShadowPwdEntryCount = 0; + sIterationIndex = 0; +} + + +struct spwd * +getspnam(const char *name) +{ + struct spwd* result = NULL; + int status = getspnam_r(name, &sShadowPwdBuffer, sShadowPwdStringBuffer, + sizeof(sShadowPwdStringBuffer), &result); + if (status != 0) + errno = status; + return result; +} + + +int +getspnam_r(const char *name, struct spwd *spwd, char *buffer, + size_t bufferSize, struct spwd **_result) +{ + *_result = NULL; + + KMessage message(BPrivate::B_REG_GET_USER); + message.AddString("name", name); + message.AddBool("shadow", true); + + KMessage reply; + status_t error = BPrivate::send_authentication_request_to_registrar(message, + reply); + if (error != B_OK) + return error; + + const char* password; + int32 min; + int32 max; + int32 warn; + int32 inactive; + int32 expiration; + int32 flags; + + if ((error = reply.FindString("name", &name)) != B_OK + || (error = reply.FindString("shadow password", &password)) != B_OK + || (error = reply.FindInt32("min", &min)) != B_OK + || (error = reply.FindInt32("max", &max)) != B_OK + || (error = reply.FindInt32("warn", &warn)) != B_OK + || (error = reply.FindInt32("inactive", &inactive)) != B_OK + || (error = reply.FindInt32("expiration", &expiration)) != B_OK + || (error = reply.FindInt32("flags", &flags)) != B_OK) { + return error; + } + + error = BPrivate::copy_shadow_pwd_to_buffer(name, password, min, max, warn, + inactive, expiration, flags, spwd, buffer, bufferSize); + if (error == B_OK) + *_result = spwd; + + return error; +} + + +struct spwd* +sgetspent(const char* line) +{ + struct spwd* result = NULL; + int status = sgetspent_r(line, &sShadowPwdBuffer, sShadowPwdStringBuffer, + sizeof(sShadowPwdStringBuffer), &result); + if (status != 0) + errno = status; + return result; +} + + +int +sgetspent_r(const char* _line, struct spwd *spwd, char *buffer, + size_t bufferSize, struct spwd** _result) +{ + *_result = NULL; + + if (_line == NULL) + return B_BAD_VALUE; + + // we need a mutable copy of the line + char* line = strdup(_line); + if (line == NULL) + return B_NO_MEMORY; + MemoryDeleter _(line); + + char* name; + char* password; + int lastChanged; + int min; + int max; + int warn; + int inactive; + int expiration; + int flags; + + status_t status = BPrivate::parse_shadow_pwd_line(line, name, password, + lastChanged, min, max, warn, inactive, expiration, flags); + if (status != B_OK) + return status; + + status = BPrivate::copy_shadow_pwd_to_buffer(name, password, min, max, warn, + inactive, expiration, flags, spwd, buffer, bufferSize); + if (status != B_OK) + return status; + + *_result = spwd; + return 0; +} + + +struct spwd* +fgetspent(FILE* file) +{ + struct spwd* result = NULL; + int status = fgetspent_r(file, &sShadowPwdBuffer, sShadowPwdStringBuffer, + sizeof(sShadowPwdStringBuffer), &result); + if (status != 0) + errno = status; + return result; +} + + +int +fgetspent_r(FILE* file, struct spwd* spwd, char* buffer, size_t bufferSize, + struct spwd** _result) +{ + *_result = NULL; + + // read a line + char lineBuffer[LINE_MAX + 1]; + errno = 0; + char* line = fgets(lineBuffer, sizeof(lineBuffer), file); + if (line == NULL) { + if (errno != 0) + return errno; + return ENOENT; + } + + return sgetspent_r(line, spwd, buffer, bufferSize, _result); +} diff --git a/src/system/libroot/posix/user_group_common.cpp b/src/system/libroot/posix/user_group_common.cpp index c94425109a..82327496e5 100644 --- a/src/system/libroot/posix/user_group_common.cpp +++ b/src/system/libroot/posix/user_group_common.cpp @@ -3,42 +3,33 @@ * Distributed under the terms of the MIT License. */ -#include "user_group_common.h" +#include #include #include -#include #include #include #include #include -#include #include #include #include +#include + +#include -using BPrivate::FileLineReader; using BPrivate::Tokenizer; -using BPrivate::FileDBEntry; -using BPrivate::FileDBReader; -using BPrivate::FileDB; -using BPrivate::PasswdDBEntry; -using BPrivate::PasswdEntryHandler; -using BPrivate::PasswdDBReader; -using BPrivate::PasswdDB; -using BPrivate::GroupDBEntry; -using BPrivate::GroupEntryHandler; -using BPrivate::GroupDBReader; -using BPrivate::GroupDB; const char* BPrivate::kPasswdFile = "/etc/passwd"; const char* BPrivate::kGroupFile = "/etc/group"; +const char* BPrivate::kShadowPwdFile = "/etc/shadow"; static benaphore sUserGroupLock; +static port_id sRegistrarPort = -1; status_t @@ -55,83 +46,27 @@ BPrivate::user_group_unlock() } -class FileLineReader { -public: - FileLineReader(int fd) - : fFD(fd), - fSize(0), - fOffset(0) - { - } +port_id +BPrivate::get_registrar_authentication_port() +{ + if (sRegistrarPort < 0) + sRegistrarPort = find_port(REGISTRAR_AUTHENTICATION_PORT_NAME); - char* NextLine() - { - char* eol; - if (fOffset >= fSize - || (eol = strchr(fBuffer + fOffset, '\n')) == NULL) { - _ReadBuffer(); - if (fOffset >= fSize) - return NULL; + return sRegistrarPort; +} - eol = strchr(fBuffer + fOffset, '\n'); - if (eol == NULL) - eol = fBuffer + fSize; - } - char* result = fBuffer + fOffset; - *eol = '\0'; - fOffset = eol + 1 - fBuffer; - return result; - } +status_t +BPrivate::send_authentication_request_to_registrar(KMessage& request, + KMessage& reply) +{ + status_t error = request.SendTo(get_registrar_authentication_port(), 0, + &reply); + if (error != B_OK) + return error; - char* NextNonEmptyLine() - { - while (char* line = NextLine()) { - while (*line != '\0' && isspace(*line)) - line++; - - if (*line != '\0' && *line != '#') - return line; - } - - return NULL; - } - -private: - void _ReadBuffer() - { - // catch special cases: full buffer or already done with the file - if (fSize == LINE_MAX || fFD < 0) - return; - - // move buffered bytes to the beginning of the buffer - int leftBytes = 0; - if (fOffset < fSize) { - leftBytes = fSize - fOffset; - memmove(fBuffer, fBuffer + fOffset, leftBytes); - } - - fOffset = 0; - fSize = leftBytes; - - // read - ssize_t bytesRead = read(fFD, fBuffer + leftBytes, - LINE_MAX - leftBytes); - if (bytesRead > 0) - fSize += bytesRead; - else - fFD = -1; - - // null-terminate - fBuffer[fSize] = '\0'; - } - -private: - int fFD; - char fBuffer[LINE_MAX + 1]; - int fSize; - int fOffset; -}; + return (status_t)reply.What(); +} class Tokenizer { @@ -215,170 +150,6 @@ buffer_allocate(size_t size, size_t align, char*& buffer, size_t& bufferSize) } -// #pragma mark - FileDBEntry - - -FileDBEntry::FileDBEntry() - : - fName(NULL), - fID(-1), - fNext(NULL) -{ -} - - -FileDBEntry::~FileDBEntry() -{ -} - - -// #pragma mark - FileDBReader - - -FileDBReader::FileDBReader() -{ -} - - -FileDBReader::~FileDBReader() -{ -} - - -status_t -FileDBReader::Read(const char* path) -{ - // read file - int fd = open(path, O_RDONLY); - if (fd < 0) - return errno; - - FileLineReader reader(fd); - - status_t error = B_OK; - - while (char* line = reader.NextNonEmptyLine()) { - Tokenizer tokenizer(line); - error = ParseEntryLine(tokenizer); - if (error != B_OK) - break; - } - - close(fd); - - return error; -} - - -// #pragma mark - FileDB - - -FileDB::FileDB() - : - fEntries(NULL), - fLastEntry(NULL) -{ -} - - -FileDB::~FileDB() -{ - while (FileDBEntry* entry = fEntries) { - fEntries = entry->Next(); - delete entry; - } - fLastEntry = NULL; -} - - -int -FileDB::GetNextEntry(void* entryBuffer, char* buffer, size_t bufferSize) -{ - FileDBEntry* entry = NULL; - - if (fLastEntry == NULL) { - // rewound - entry = fEntries; - } else if (fLastEntry->Next() != NULL) { - // get next entry - entry = fLastEntry->Next(); - } - - // copy the entry, if we found one - if (entry != NULL) { - int result = entry->CopyToBuffer(entryBuffer, buffer, bufferSize); - if (result == 0) - fLastEntry = entry; - return result; - } - - return ENOENT; -} - - -void -FileDB::RewindEntries() -{ - fLastEntry = NULL; -} - - -FileDBEntry* -FileDB::FindEntry(const char* name) const -{ - // find the entry - FileDBEntry* entry = fEntries; - while (entry != NULL && strcmp(entry->Name(), name) != 0) - entry = entry->Next(); - - return entry; -} - - -FileDBEntry* -FileDB::FindEntry(int32 id) const -{ - // find the entry - FileDBEntry* entry = fEntries; - while (entry != NULL && entry->ID() != id) - entry = entry->Next(); - - return entry; -} - - -int -FileDB::GetEntry(const char* name, void* entryBuffer, char* buffer, - size_t bufferSize) const -{ - FileDBEntry* entry = FindEntry(name); - if (entry == NULL) - return ENOENT; - - return entry->CopyToBuffer(entryBuffer, buffer, bufferSize); -} - - -int -FileDB::GetEntry(int32 id, void* entryBuffer, char* buffer, - size_t bufferSize) const -{ - FileDBEntry* entry = FindEntry(id); - if (entry == NULL) - return ENOENT; - - return entry->CopyToBuffer(entryBuffer, buffer, bufferSize); -} - - -void -FileDB::AddEntry(FileDBEntry* entry) -{ - entry->SetNext(fEntries); - fEntries = entry; -} - - // #pragma mark - passwd support @@ -405,86 +176,29 @@ BPrivate::copy_passwd_to_buffer(const char* name, const char* password, } -// #pragma mark - PasswdDBEntry - - -PasswdDBEntry::PasswdDBEntry() - : FileDBEntry(), - fPassword(NULL), - fHome(NULL), - fShell(NULL), - fRealName(NULL) -{ -} - - -PasswdDBEntry::~PasswdDBEntry() -{ - free(fName); -} - - -bool -PasswdDBEntry::Init(const char* name, const char* password, uid_t uid, - gid_t gid, const char* home, const char* shell, const char* realName) -{ - size_t bufferSize = strlen(name) + 1 - + strlen(password) + 1 - + strlen(home) + 1 - + strlen(shell) + 1 - + strlen(realName) + 1; - - char* buffer = (char*)malloc(bufferSize); - if (buffer == NULL) - return false; - - fID = uid; - fGID = gid; - fName = buffer_dup_string(name, buffer, bufferSize); - fPassword = buffer_dup_string(password, buffer, bufferSize); - fHome = buffer_dup_string(home, buffer, bufferSize); - fShell = buffer_dup_string(shell, buffer, bufferSize); - fRealName = buffer_dup_string(realName, buffer, bufferSize); - - return true; -} - - -int -PasswdDBEntry::CopyToBuffer(void* entryBuffer, char* buffer, size_t bufferSize) -{ - return copy_passwd_to_buffer(fName, fPassword, fID, fGID, fHome, fShell, - fRealName, (passwd*)entryBuffer, buffer, bufferSize); -} - - -// #pragma mark - PasswdEntryHandler - - -PasswdEntryHandler::~PasswdEntryHandler() -{ -} - - -// #pragma mark - PasswdDBReader - - -PasswdDBReader::PasswdDBReader(PasswdEntryHandler* handler) - : fHandler(handler) +status_t +BPrivate::copy_passwd_to_buffer(const passwd* from, passwd* entry, char* buffer, + size_t bufferSize) { + return copy_passwd_to_buffer(from->pw_name, from->pw_passwd, from->pw_uid, + from->pw_gid, from->pw_dir, from->pw_shell, from->pw_gecos, entry, + buffer, bufferSize); } status_t -PasswdDBReader::ParseEntryLine(Tokenizer& tokenizer) +BPrivate::parse_passwd_line(char* line, char*& name, char*& password, + uid_t& uid, gid_t& gid, char*& home, char*& shell, char*& realName) { - char* name = tokenizer.NextTrimmedToken(':'); - char* password = tokenizer.NextTrimmedToken(':'); + Tokenizer tokenizer(line); + + name = tokenizer.NextTrimmedToken(':'); + password = tokenizer.NextTrimmedToken(':'); char* userID = tokenizer.NextTrimmedToken(':'); char* groupID = tokenizer.NextTrimmedToken(':'); - char* realName = tokenizer.NextTrimmedToken(':'); - char* home = tokenizer.NextTrimmedToken(':'); - char* shell = tokenizer.NextTrimmedToken(':'); + realName = tokenizer.NextTrimmedToken(':'); + home = tokenizer.NextTrimmedToken(':'); + shell = tokenizer.NextTrimmedToken(':'); // skip if invalid size_t nameLen; @@ -495,44 +209,17 @@ PasswdDBReader::ParseEntryLine(Tokenizer& tokenizer) || strlen(realName) >= MAX_PASSWD_REAL_NAME_LEN || strlen(home) >= MAX_PASSWD_HOME_DIR_LEN || strlen(shell) >= MAX_PASSWD_SHELL_LEN) { - return B_OK; + return B_BAD_VALUE; } - gid_t uid = atoi(userID); - gid_t gid = atoi(groupID); + uid = atoi(userID); + gid = atoi(groupID); - return fHandler->HandleEntry(name, password, uid, gid, home, shell, - realName); -} - - -// #pragma mark - PasswdDB - - -status_t -PasswdDB::Init() -{ - return PasswdDBReader(this).Read(kPasswdFile); -} - - -status_t -PasswdDB::HandleEntry(const char* name, const char* password, uid_t uid, - gid_t gid, const char* home, const char* shell, const char* realName) -{ - PasswdDBEntry* entry = new(std::nothrow) PasswdDBEntry(); - if (entry == NULL || !entry->Init(name, password, uid, gid, home, shell, - realName)) { - delete entry; - return B_NO_MEMORY; - } - - AddEntry(entry); return B_OK; } -// #pragma mark - passwd support +// #pragma mark - group support status_t @@ -566,87 +253,27 @@ BPrivate::copy_group_to_buffer(const char* name, const char* password, } -// #pragma mark - GroupDBEntry - - -GroupDBEntry::GroupDBEntry() - : FileDBEntry(), - fPassword(NULL), - fMembers(NULL), - fMemberCount(0) +status_t +BPrivate::copy_group_to_buffer(const group* from, group* entry, char* buffer, + size_t bufferSize) { -} + int memberCount = 0; + while (from->gr_mem[memberCount] != NULL) + memberCount++; - -GroupDBEntry::~GroupDBEntry() -{ - free(fMembers); -} - - -bool -GroupDBEntry::Init(const char* name, const char* password, gid_t gid, - const char* const* members, int memberCount) -{ - size_t bufferSize = sizeof(char*) * (memberCount + 1) - + strlen(name) + 1 - + strlen(password) + 1; - - for (int i = 0; i < memberCount; i++) - bufferSize += strlen(members[i]) + 1; - - char* buffer = (char*)malloc(bufferSize); - if (buffer == NULL) - return false; - - // allocate member array first (for alignment reasons) - fMembers = (char**)buffer_allocate(sizeof(char*) * (memberCount + 1), - sizeof(char*), buffer, bufferSize); - - fID = gid; - fName = buffer_dup_string(name, buffer, bufferSize); - fPassword = buffer_dup_string(password, buffer, bufferSize); - - // copy members - for (int i = 0; i < memberCount; i++) - fMembers[i] = buffer_dup_string(members[i], buffer, bufferSize); - fMembers[memberCount] = NULL; - fMemberCount = memberCount; - - return true; -} - - -int -GroupDBEntry::CopyToBuffer(void* entryBuffer, char* buffer, size_t bufferSize) -{ - return copy_group_to_buffer(fName, fPassword, fID, fMembers, fMemberCount, - (group*)entryBuffer, buffer, bufferSize); -} - - -// #pragma mark - GroupEntryHandler - - -GroupEntryHandler::~GroupEntryHandler() -{ -} - - -// #pragma mark - GroupDBReader - - -GroupDBReader::GroupDBReader(GroupEntryHandler* handler) - : fHandler(handler) -{ + return copy_group_to_buffer(from->gr_name, from->gr_passwd, + from->gr_gid, from->gr_mem, memberCount, entry, buffer, bufferSize); } status_t -GroupDBReader::ParseEntryLine(Tokenizer& tokenizer) +BPrivate::parse_group_line(char* line, char*& name, char*& password, gid_t& gid, + char** members, int& memberCount) { - char* name = tokenizer.NextTrimmedToken(':'); - char* password = tokenizer.NextTrimmedToken(':'); + Tokenizer tokenizer(line); + + name = tokenizer.NextTrimmedToken(':'); + password = tokenizer.NextTrimmedToken(':'); char* groupID = tokenizer.NextTrimmedToken(':'); // skip if invalid @@ -654,13 +281,12 @@ GroupDBReader::ParseEntryLine(Tokenizer& tokenizer) if (groupID == NULL || (nameLen = strlen(name)) == 0 || !isdigit(*groupID) || nameLen >= MAX_GROUP_NAME_LEN || strlen(password) >= MAX_GROUP_PASSWORD_LEN) { - return B_OK; + return B_BAD_VALUE; } - gid_t gid = atol(groupID); + gid = atol(groupID); - const char* members[MAX_GROUP_MEMBER_COUNT]; - int memberCount = 0; + memberCount = 0; while (char* groupUser = tokenizer.NextTrimmedToken(',')) { // ignore invalid members @@ -674,32 +300,78 @@ GroupDBReader::ParseEntryLine(Tokenizer& tokenizer) break; } - return fHandler->HandleEntry(name, password, gid, members, memberCount); + return B_OK; } -// #pragma mark - GroupDB +// #pragma mark - shadow password support status_t -GroupDB::Init() +BPrivate::copy_shadow_pwd_to_buffer(const char* name, const char* password, + int min, int max, int warn, int inactive, int expiration, int flags, + spwd* entry, char* buffer, size_t bufferSize) { - return GroupDBReader(this).Read(kGroupFile); + entry->sp_min = min; + entry->sp_max = max; + entry->sp_warn = warn; + entry->sp_inact = inactive; + entry->sp_expire = expiration; + entry->sp_flag = flags; + + entry->sp_namp = buffer_dup_string(name, buffer, bufferSize); + entry->sp_pwdp = buffer_dup_string(password, buffer, bufferSize); + + if (entry->sp_namp && entry->sp_pwdp) + return 0; + + return ERANGE; } status_t -GroupDB::HandleEntry(const char* name, const char* password, gid_t gid, - const char* const* members, int memberCount) +BPrivate::copy_shadow_pwd_to_buffer(const spwd* from, spwd* entry, + char* buffer, size_t bufferSize) { - GroupDBEntry* entry = new(std::nothrow) GroupDBEntry(); - if (entry == NULL || !entry->Init(name, password, gid, members, - memberCount)) { - delete entry; - return B_NO_MEMORY; + return copy_shadow_pwd_to_buffer(from->sp_namp, from->sp_pwdp, + from->sp_min, from->sp_max, from->sp_warn, from->sp_inact, + from->sp_expire, from->sp_flag, entry, buffer, bufferSize); +} + + +status_t +BPrivate::parse_shadow_pwd_line(char* line, char*& name, char*& password, + int& lastChanged, int& min, int& max, int& warn, int& inactive, + int& expiration, int& flags) +{ + Tokenizer tokenizer(line); + + name = tokenizer.NextTrimmedToken(':'); + password = tokenizer.NextTrimmedToken(':'); + char* lastChangedString = tokenizer.NextTrimmedToken(':'); + char* minString = tokenizer.NextTrimmedToken(':'); + char* maxString = tokenizer.NextTrimmedToken(':'); + char* warnString = tokenizer.NextTrimmedToken(':'); + char* inactiveString = tokenizer.NextTrimmedToken(':'); + char* expirationString = tokenizer.NextTrimmedToken(':'); + char* flagsString = tokenizer.NextTrimmedToken(':'); + + // skip if invalid + size_t nameLen; + if (flagsString == NULL || (nameLen = strlen(name)) == 0 + || nameLen >= MAX_SHADOW_PWD_NAME_LEN + || strlen(password) >= MAX_SHADOW_PWD_PASSWORD_LEN) { + return B_BAD_VALUE; } - AddEntry(entry); + lastChanged = atoi(lastChangedString); + min = minString[0] != '\0' ? atoi(minString) : -1; + max = maxString[0] != '\0' ? atoi(maxString) : -1; + warn = warnString[0] != '\0' ? atoi(warnString) : -1; + inactive = inactiveString[0] != '\0' ? atoi(inactiveString) : -1; + expiration = expirationString[0] != '\0' ? atoi(expirationString) : -1; + flags = atoi(flagsString); + return B_OK; } diff --git a/src/system/libroot/posix/user_group_common.h b/src/system/libroot/posix/user_group_common.h deleted file mode 100644 index 588e033e76..0000000000 --- a/src/system/libroot/posix/user_group_common.h +++ /dev/null @@ -1,239 +0,0 @@ - -/* - * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. All rights reserved. - * Distributed under the terms of the MIT License. - */ -#ifndef _LIBROOT_USER_GROUP_COMMON_H -#define _LIBROOT_USER_GROUP_COMMON_H - -#include -#include - -#include - -#include - - -namespace BPrivate { - -class FileLineReader; -class Tokenizer; - -extern const char* kPasswdFile; -extern const char* kGroupFile; - - -// locking - -status_t user_group_lock(); -status_t user_group_unlock(); - - -class UserGroupLocking { -public: - inline bool Lock(int*) - { - return user_group_lock() == B_OK; - } - - inline void Unlock(int*) - { - user_group_unlock(); - } -}; - - -class UserGroupLocker : public AutoLocker { -public: - UserGroupLocker() - : AutoLocker((int*)1) - { - } -}; - - -// #pragma mark - File DB Base Classes - - -class FileDBEntry { -public: - FileDBEntry(); - virtual ~FileDBEntry(); - - const char* Name() const { return fName; } - int32 ID() const { return fID; } - - FileDBEntry* Next() const { return fNext; } - void SetNext(FileDBEntry* next) { fNext = next; } - - virtual int CopyToBuffer(void* entryBuffer, char* buffer, - size_t bufferSize) = 0; - -protected: - char* fName; - int32 fID; - FileDBEntry* fNext; -}; - - -class FileDBReader { -public: - FileDBReader(); - virtual ~FileDBReader(); - - status_t Read(const char* path); - -protected: - virtual status_t ParseEntryLine(Tokenizer& tokenizer) = 0; -}; - - -class FileDB { -public: - FileDB(); - virtual ~FileDB(); - - int GetNextEntry(void* entryBuffer, char* buffer, size_t bufferSize); - void RewindEntries(); - - FileDBEntry* FindEntry(const char* name) const; - FileDBEntry* FindEntry(int32 id) const; - - int GetEntry(const char* name, void* entryBuffer, char* buffer, - size_t bufferSize) const; - int GetEntry(int32 id, void* entryBuffer, char* buffer, - size_t bufferSize) const; - -protected: - void AddEntry(FileDBEntry* entry); - -protected: - FileDBEntry* fEntries; - FileDBEntry* fLastEntry; -}; - - -// #pragma mark - Passwd DB - - -status_t -copy_passwd_to_buffer(const char* name, const char* password, uid_t uid, - gid_t gid, const char* home, const char* shell, const char* realName, - passwd* entry, char* buffer, size_t bufferSize); - - -class PasswdDBEntry : public FileDBEntry { -public: - PasswdDBEntry(); - virtual ~PasswdDBEntry(); - - bool Init(const char* name, const char* password, uid_t uid, gid_t gid, - const char* home, const char* shell, const char* realName); - - virtual int CopyToBuffer(void* entryBuffer, char* buffer, - size_t bufferSize); - -protected: - gid_t fGID; - char* fPassword; - char* fHome; - char* fShell; - char* fRealName; -}; - - -class PasswdEntryHandler { -public: - virtual ~PasswdEntryHandler(); - - virtual status_t HandleEntry(const char* name, const char* password, - uid_t uid, gid_t gid, const char* home, const char* shell, - const char* realName) = 0; -}; - - -class PasswdDBReader : public FileDBReader { -public: - PasswdDBReader(PasswdEntryHandler* handler); - -protected: - virtual status_t ParseEntryLine(Tokenizer& tokenizer); - -private: - PasswdEntryHandler* fHandler; -}; - - -class PasswdDB : public FileDB, private PasswdEntryHandler { -public: - status_t Init(); - -private: - virtual status_t HandleEntry(const char* name, const char* password, - uid_t uid, gid_t gid, const char* home, const char* shell, - const char* realName); -}; - - -// #pragma mark - Group DB - - -status_t -copy_group_to_buffer(const char* name, const char* password, gid_t gid, - const char* const* members, int memberCount, group* entry, char* buffer, - size_t bufferSize); - - -class GroupDBEntry : public FileDBEntry { -public: - GroupDBEntry(); - virtual ~GroupDBEntry(); - - bool Init(const char* name, const char* password, gid_t gid, - const char* const* members, int memberCount); - - virtual int CopyToBuffer(void* entryBuffer, char* buffer, - size_t bufferSize); - -protected: - char* fPassword; - char** fMembers; - int fMemberCount; -}; - - -class GroupEntryHandler { -public: - virtual ~GroupEntryHandler(); - - virtual status_t HandleEntry(const char* name, const char* password, - gid_t gid, const char* const* members, int memberCount) = 0; -}; - - -class GroupDBReader : public FileDBReader { -public: - GroupDBReader(GroupEntryHandler* handler); - -protected: - virtual status_t ParseEntryLine(Tokenizer& tokenizer); - -private: - GroupEntryHandler* fHandler; -}; - - -class GroupDB : public FileDB, private GroupEntryHandler { -public: - status_t Init(); - -private: - virtual status_t HandleEntry(const char* name, const char* password, - gid_t gid, const char* const* members, int memberCount); -}; - - -} // namespace BPrivate - - -#endif // _LIBROOT_USER_GROUP_COMMON_H