* 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
This commit is contained in:
@@ -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 <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
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_
|
||||||
@@ -24,6 +24,9 @@ extern const char *kRAppLooperPortName;
|
|||||||
|
|
||||||
extern const char *get_roster_port_name();
|
extern const char *get_roster_port_name();
|
||||||
|
|
||||||
|
#define REGISTRAR_AUTHENTICATION_PORT_NAME "registrar: auth manager"
|
||||||
|
|
||||||
|
|
||||||
// message constants
|
// message constants
|
||||||
enum {
|
enum {
|
||||||
// replies
|
// replies
|
||||||
@@ -107,6 +110,16 @@ enum {
|
|||||||
|
|
||||||
// debug_server notifications
|
// debug_server notifications
|
||||||
B_REG_TEAM_DEBUGGER_ALERT = 'rtda',
|
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
|
// B_REG_MIME_SET_PARAM "which" constants
|
||||||
|
|||||||
@@ -34,6 +34,14 @@
|
|||||||
// MAX_GROUP_NAME_LEN and MAX_GROUP_PASSWORD_LEN are char* aligned
|
// 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 user_space_program_args;
|
||||||
struct real_time_data;
|
struct real_time_data;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008, Ingo Weinhold, [email protected]. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef _LIBROOT_USER_GROUP_COMMON_H
|
||||||
|
#define _LIBROOT_USER_GROUP_COMMON_H
|
||||||
|
|
||||||
|
#include <grp.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <shadow.h>
|
||||||
|
|
||||||
|
#include <OS.h>
|
||||||
|
|
||||||
|
#include <AutoLocker.h>
|
||||||
|
|
||||||
|
|
||||||
|
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<int, UserGroupLocking> {
|
||||||
|
public:
|
||||||
|
UserGroupLocker()
|
||||||
|
: AutoLocker<int, UserGroupLocking>((int*)1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
port_id get_registrar_authentication_port();
|
||||||
|
status_t send_authentication_request_to_registrar(KMessage& request,
|
||||||
|
KMessage& reply);
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
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
|
||||||
@@ -0,0 +1,902 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008, Ingo Weinhold, [email protected]. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "AuthenticationManager.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <new>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <DataIO.h>
|
||||||
|
|
||||||
|
#include <AutoDeleter.h>
|
||||||
|
#include <RegistrarDefs.h>
|
||||||
|
|
||||||
|
#include <libroot_private.h>
|
||||||
|
#include <user_group.h>
|
||||||
|
#include <util/KMessage.h>
|
||||||
|
|
||||||
|
|
||||||
|
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<typename Type>
|
||||||
|
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<typename Type>
|
||||||
|
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<uid_t, User*>::const_iterator it = fUsersByID.find(uid);
|
||||||
|
return (it == fUsersByID.end() ? NULL : it->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
User* UserByName(const char* name) const
|
||||||
|
{
|
||||||
|
map<string, User*>::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<passwd*> _(entries);
|
||||||
|
|
||||||
|
int32 index = 0;
|
||||||
|
for (map<uid_t, User*>::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<spwd*> _(entries);
|
||||||
|
|
||||||
|
int32 index = 0;
|
||||||
|
for (map<uid_t, User*>::const_iterator it = fUsersByID.begin();
|
||||||
|
it != fUsersByID.end(); ++it) {
|
||||||
|
entries[index++] = it->second->WriteFlatShadowPwd(store);
|
||||||
|
}
|
||||||
|
|
||||||
|
store.WriteData(offset, entries, entriesSpace);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
map<uid_t, User*> fUsersByID;
|
||||||
|
map<string, User*> 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<gid_t, Group*>::const_iterator it = fGroupsByID.find(gid);
|
||||||
|
return (it == fGroupsByID.end() ? NULL : it->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
Group* GroupByName(const char* name) const
|
||||||
|
{
|
||||||
|
map<string, Group*>::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<gid_t, Group*>::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<group*> _(entries);
|
||||||
|
|
||||||
|
int32 index = 0;
|
||||||
|
for (map<gid_t, Group*>::const_iterator it = fGroupsByID.begin();
|
||||||
|
it != fGroupsByID.end(); ++it) {
|
||||||
|
entries[index++] = it->second->WriteFlatGroup(store);
|
||||||
|
}
|
||||||
|
|
||||||
|
store.WriteData(offset, entries, entriesSpace);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
map<uid_t, Group*> fGroupsByID;
|
||||||
|
map<string, Group*> 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, int> _(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, int> _(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, int> _(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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008, Ingo Weinhold, [email protected]. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef AUTHENTICATION_MANAGER_H
|
||||||
|
#define AUTHENTICATION_MANAGER_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <OS.h>
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
@@ -2,6 +2,7 @@ SubDir HAIKU_TOP src servers registrar ;
|
|||||||
|
|
||||||
UsePrivateHeaders app ;
|
UsePrivateHeaders app ;
|
||||||
UsePrivateHeaders kernel ;
|
UsePrivateHeaders kernel ;
|
||||||
|
UsePrivateHeaders libroot ;
|
||||||
UsePrivateHeaders shared ;
|
UsePrivateHeaders shared ;
|
||||||
UsePrivateHeaders storage ;
|
UsePrivateHeaders storage ;
|
||||||
UsePrivateHeaders tracker ;
|
UsePrivateHeaders tracker ;
|
||||||
@@ -13,6 +14,7 @@ Server registrar
|
|||||||
:
|
:
|
||||||
AppInfoList.cpp
|
AppInfoList.cpp
|
||||||
AppInfoListMessagingTargetSet.cpp
|
AppInfoListMessagingTargetSet.cpp
|
||||||
|
AuthenticationManager.cpp
|
||||||
Clipboard.cpp
|
Clipboard.cpp
|
||||||
ClipboardHandler.cpp
|
ClipboardHandler.cpp
|
||||||
Event.cpp
|
Event.cpp
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include <RegistrarDefs.h>
|
#include <RegistrarDefs.h>
|
||||||
#include <RosterPrivate.h>
|
#include <RosterPrivate.h>
|
||||||
|
|
||||||
|
#include "AuthenticationManager.h"
|
||||||
#include "ClipboardHandler.h"
|
#include "ClipboardHandler.h"
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
#include "EventQueue.h"
|
#include "EventQueue.h"
|
||||||
@@ -60,7 +61,8 @@ Registrar::Registrar(status_t *error)
|
|||||||
fEventQueue(NULL),
|
fEventQueue(NULL),
|
||||||
fMessageRunnerManager(NULL),
|
fMessageRunnerManager(NULL),
|
||||||
fSanityEvent(NULL),
|
fSanityEvent(NULL),
|
||||||
fShutdownProcess(NULL)
|
fShutdownProcess(NULL),
|
||||||
|
fAuthenticationManager(NULL)
|
||||||
{
|
{
|
||||||
FUNCTION_START();
|
FUNCTION_START();
|
||||||
}
|
}
|
||||||
@@ -76,6 +78,7 @@ Registrar::~Registrar()
|
|||||||
FUNCTION_START();
|
FUNCTION_START();
|
||||||
Lock();
|
Lock();
|
||||||
fEventQueue->Die();
|
fEventQueue->Die();
|
||||||
|
delete fAuthenticationManager;
|
||||||
delete fMessageRunnerManager;
|
delete fMessageRunnerManager;
|
||||||
delete fEventQueue;
|
delete fEventQueue;
|
||||||
delete fSanityEvent;
|
delete fSanityEvent;
|
||||||
@@ -130,6 +133,10 @@ Registrar::ReadyToRun()
|
|||||||
// create event queue
|
// create event queue
|
||||||
fEventQueue = new EventQueue(kEventQueueName);
|
fEventQueue = new EventQueue(kEventQueueName);
|
||||||
|
|
||||||
|
// create authentication manager
|
||||||
|
fAuthenticationManager = new AuthenticationManager;
|
||||||
|
fAuthenticationManager->Init();
|
||||||
|
|
||||||
// create roster
|
// create roster
|
||||||
fRoster = new TRoster;
|
fRoster = new TRoster;
|
||||||
fRoster->Init();
|
fRoster->Init();
|
||||||
|
|||||||
@@ -28,6 +28,8 @@
|
|||||||
|
|
||||||
#include <Server.h>
|
#include <Server.h>
|
||||||
|
|
||||||
|
|
||||||
|
class AuthenticationManager;
|
||||||
class ClipboardHandler;
|
class ClipboardHandler;
|
||||||
class DiskDeviceManager;
|
class DiskDeviceManager;
|
||||||
class EventQueue;
|
class EventQueue;
|
||||||
@@ -38,6 +40,7 @@ class ShutdownProcess;
|
|||||||
|
|
||||||
class TRoster;
|
class TRoster;
|
||||||
|
|
||||||
|
|
||||||
class Registrar : public BServer {
|
class Registrar : public BServer {
|
||||||
public:
|
public:
|
||||||
Registrar(status_t *error);
|
Registrar(status_t *error);
|
||||||
@@ -62,6 +65,7 @@ private:
|
|||||||
MessageRunnerManager *fMessageRunnerManager;
|
MessageRunnerManager *fMessageRunnerManager;
|
||||||
MessageEvent *fSanityEvent;
|
MessageEvent *fSanityEvent;
|
||||||
ShutdownProcess *fShutdownProcess;
|
ShutdownProcess *fShutdownProcess;
|
||||||
|
AuthenticationManager *fAuthenticationManager;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // REGISTRAR_H
|
#endif // REGISTRAR_H
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
SubDir HAIKU_TOP src system libroot posix ;
|
SubDir HAIKU_TOP src system libroot posix ;
|
||||||
|
|
||||||
UsePrivateHeaders shared [ FDirName syslog_daemon ] ;
|
UsePrivateHeaders app shared [ FDirName syslog_daemon ] ;
|
||||||
UseHeaders $(TARGET_PRIVATE_KERNEL_HEADERS) : true ;
|
UseHeaders $(TARGET_PRIVATE_KERNEL_HEADERS) : true ;
|
||||||
|
|
||||||
if $(HAIKU_MULTIUSER_QUERY) = 1 {
|
if $(HAIKU_MULTIUSER_QUERY) = 1 {
|
||||||
PWD_BACKEND = pwd_query.c ;
|
PWD_BACKEND = pwd_query.c ;
|
||||||
} else {
|
} 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 :
|
MergeObject posix_main.o :
|
||||||
assert.c
|
assert.c
|
||||||
|
|||||||
+125
-107
@@ -14,111 +14,109 @@
|
|||||||
#include <OS.h>
|
#include <OS.h>
|
||||||
|
|
||||||
#include <libroot_private.h>
|
#include <libroot_private.h>
|
||||||
|
#include <RegistrarDefs.h>
|
||||||
|
#include <user_group.h>
|
||||||
|
|
||||||
#include "user_group_common.h"
|
#include <util/KMessage.h>
|
||||||
|
|
||||||
|
|
||||||
using BPrivate::GroupDB;
|
|
||||||
using BPrivate::GroupDBReader;
|
|
||||||
using BPrivate::GroupEntryHandler;
|
|
||||||
using BPrivate::UserGroupLocker;
|
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 struct group sGroupBuffer;
|
||||||
static char sGroupStringBuffer[MAX_GROUP_BUFFER_SIZE];
|
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 {
|
KMessage message(BPrivate::B_REG_GET_GROUP);
|
||||||
public:
|
if (name)
|
||||||
GroupEntryFindHandler(const char* name, uid_t gid,
|
message.AddString("name", name);
|
||||||
group* entry, char* buffer, size_t bufferSize)
|
else
|
||||||
:
|
message.AddInt32("gid", _gid);
|
||||||
fName(name),
|
|
||||||
fGID(gid),
|
KMessage reply;
|
||||||
fEntry(entry),
|
status_t error = BPrivate::send_authentication_request_to_registrar(message,
|
||||||
fBuffer(buffer),
|
reply);
|
||||||
fBufferSize(bufferSize)
|
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,
|
const char* members[MAX_GROUP_MEMBER_COUNT];
|
||||||
gid_t gid, const char* const* members, int memberCount)
|
int memberCount = 0;
|
||||||
{
|
for (int memberCount = 0; memberCount < MAX_GROUP_MEMBER_COUNT;) {
|
||||||
if (fName != NULL ? strcmp(fName, name) != 0 : fGID != gid)
|
if (reply.FindString("members", members + memberCount) != B_OK)
|
||||||
return 0;
|
break;
|
||||||
|
memberCount++;
|
||||||
// found
|
|
||||||
status_t error = BPrivate::copy_group_to_buffer(name, password, gid,
|
|
||||||
members, memberCount, fEntry, fBuffer, fBufferSize);
|
|
||||||
|
|
||||||
return error == B_OK ? 1 : error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
error = BPrivate::copy_group_to_buffer(name, password, gid, members,
|
||||||
const char* fName;
|
memberCount, group, buffer, bufferSize);
|
||||||
gid_t fGID;
|
if (error == B_OK)
|
||||||
group* fEntry;
|
*_result = group;
|
||||||
char* fBuffer;
|
|
||||||
size_t fBufferSize;
|
return error;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
class UserGroupEntryHandler : public BPrivate::GroupEntryHandler {
|
static status_t
|
||||||
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*
|
|
||||||
init_group_db()
|
init_group_db()
|
||||||
{
|
{
|
||||||
if (sGroupDB != NULL)
|
if (sGroupEntries != NULL)
|
||||||
return sGroupDB;
|
return B_OK;
|
||||||
|
|
||||||
sGroupDB = new(std::nothrow) GroupDB;
|
// ask the registrar
|
||||||
if (sGroupDB == NULL)
|
KMessage message(BPrivate::B_REG_GET_GROUP_DB);
|
||||||
return NULL;
|
status_t error = BPrivate::send_authentication_request_to_registrar(message,
|
||||||
|
sGroupDBReply);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
if (sGroupDB->Init() != B_OK) {
|
// unpack the reply
|
||||||
delete sGroupDB;
|
int32 count;
|
||||||
sGroupDB = NULL;
|
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;
|
*_result = NULL;
|
||||||
|
|
||||||
if (GroupDB* db = init_group_db()) {
|
if ((status = init_group_db()) == B_OK) {
|
||||||
status = db->GetNextEntry(group, buffer, bufferSize);
|
if (sIterationIndex >= sGroupEntryCount)
|
||||||
if (status == 0)
|
return ENOENT;
|
||||||
*_result = group;
|
|
||||||
|
|
||||||
|
status = BPrivate::copy_group_to_buffer(
|
||||||
|
sGroupEntries[sIterationIndex], group, buffer, bufferSize);
|
||||||
|
|
||||||
|
if (status == B_OK) {
|
||||||
|
sIterationIndex++;
|
||||||
|
*_result = group;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
@@ -163,8 +167,7 @@ setgrent(void)
|
|||||||
{
|
{
|
||||||
UserGroupLocker _;
|
UserGroupLocker _;
|
||||||
|
|
||||||
if (GroupDB* db = init_group_db())
|
sIterationIndex = 0;
|
||||||
db->RewindEntries();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -173,12 +176,10 @@ endgrent(void)
|
|||||||
{
|
{
|
||||||
UserGroupLocker locker;
|
UserGroupLocker locker;
|
||||||
|
|
||||||
GroupDB* db = sGroupDB;
|
sGroupDBReply.Unset();
|
||||||
sGroupDB = NULL;
|
sGroupEntries = NULL;
|
||||||
|
sGroupEntryCount = 0;
|
||||||
locker.Unlock();
|
sIterationIndex = 0;
|
||||||
|
|
||||||
delete db;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -198,11 +199,7 @@ int
|
|||||||
getgrnam_r(const char *name, struct group *group, char *buffer,
|
getgrnam_r(const char *name, struct group *group, char *buffer,
|
||||||
size_t bufferSize, struct group **_result)
|
size_t bufferSize, struct group **_result)
|
||||||
{
|
{
|
||||||
GroupEntryFindHandler handler(name, 0, group, buffer, bufferSize);
|
return query_group_entry(name, 0, group, buffer, bufferSize, _result);
|
||||||
status_t status = GroupDBReader(&handler).Read(BPrivate::kGroupFile);
|
|
||||||
|
|
||||||
*_result = (status == 1 ? group : NULL);
|
|
||||||
return (status == 1 ? 0 : (status == 0 ? ENOENT : status));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -222,11 +219,7 @@ int
|
|||||||
getgrgid_r(gid_t gid, struct group *group, char *buffer,
|
getgrgid_r(gid_t gid, struct group *group, char *buffer,
|
||||||
size_t bufferSize, struct group **_result)
|
size_t bufferSize, struct group **_result)
|
||||||
{
|
{
|
||||||
GroupEntryFindHandler handler(NULL, gid, group, buffer, bufferSize);
|
return query_group_entry(NULL, gid, group, buffer, bufferSize, _result);
|
||||||
status_t status = GroupDBReader(&handler).Read(BPrivate::kGroupFile);
|
|
||||||
|
|
||||||
*_result = (status == 1 ? group : NULL);
|
|
||||||
return (status == 1 ? 0 : (status == 0 ? ENOENT : status));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -237,10 +230,35 @@ getgrouplist(const char* user, gid_t baseGroup, gid_t* groupList,
|
|||||||
int maxGroupCount = *groupCount;
|
int maxGroupCount = *groupCount;
|
||||||
*groupCount = 0;
|
*groupCount = 0;
|
||||||
|
|
||||||
UserGroupEntryHandler handler(user, groupList, maxGroupCount, groupCount);
|
status_t error = B_OK;
|
||||||
BPrivate::GroupDBReader(&handler).Read(BPrivate::kGroupFile);
|
|
||||||
|
|
||||||
// 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)
|
if (*groupCount < maxGroupCount)
|
||||||
groupList[*groupCount] = baseGroup;
|
groupList[*groupCount] = baseGroup;
|
||||||
++*groupCount;
|
++*groupCount;
|
||||||
|
|||||||
@@ -14,76 +14,107 @@
|
|||||||
#include <OS.h>
|
#include <OS.h>
|
||||||
|
|
||||||
#include <libroot_private.h>
|
#include <libroot_private.h>
|
||||||
|
#include <RegistrarDefs.h>
|
||||||
|
#include <user_group.h>
|
||||||
|
|
||||||
#include "user_group_common.h"
|
#include <util/KMessage.h>
|
||||||
|
|
||||||
|
|
||||||
using BPrivate::PasswdDB;
|
|
||||||
using BPrivate::PasswdDBReader;
|
|
||||||
using BPrivate::PasswdEntryHandler;
|
|
||||||
using BPrivate::UserGroupLocker;
|
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 struct passwd sPasswdBuffer;
|
||||||
static char sPasswdStringBuffer[MAX_PASSWD_BUFFER_SIZE];
|
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 {
|
KMessage message(BPrivate::B_REG_GET_USER);
|
||||||
public:
|
if (name)
|
||||||
PasswdEntryFindHandler(const char* name, uid_t uid,
|
message.AddString("name", name);
|
||||||
passwd* entry, char* buffer, size_t bufferSize)
|
else
|
||||||
:
|
message.AddInt32("uid", _uid);
|
||||||
fName(name),
|
|
||||||
fUID(uid),
|
KMessage reply;
|
||||||
fEntry(entry),
|
status_t error = BPrivate::send_authentication_request_to_registrar(message,
|
||||||
fBuffer(buffer),
|
reply);
|
||||||
fBufferSize(bufferSize)
|
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,
|
error = BPrivate::copy_passwd_to_buffer(name, password, uid, gid, home,
|
||||||
uid_t uid, gid_t gid, const char* home, const char* shell,
|
shell, realName, passwd, buffer, bufferSize);
|
||||||
const char* realName)
|
if (error == B_OK)
|
||||||
{
|
*_result = passwd;
|
||||||
if (fName != NULL ? strcmp(fName, name) != 0 : fUID != uid)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// found
|
return error;
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
static PasswdDB*
|
static status_t
|
||||||
init_passwd_db()
|
init_passwd_db()
|
||||||
{
|
{
|
||||||
if (sPasswdDB != NULL)
|
if (sPasswdEntries != NULL)
|
||||||
return sPasswdDB;
|
return B_OK;
|
||||||
|
|
||||||
sPasswdDB = new(std::nothrow) PasswdDB;
|
// ask the registrar
|
||||||
if (sPasswdDB == NULL)
|
KMessage message(BPrivate::B_REG_GET_PASSWD_DB);
|
||||||
return NULL;
|
status_t error = BPrivate::send_authentication_request_to_registrar(message,
|
||||||
|
sPasswdDBReply);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
if (sPasswdDB->Init() != B_OK) {
|
// unpack the reply
|
||||||
delete sPasswdDB;
|
int32 count;
|
||||||
sPasswdDB = NULL;
|
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;
|
*_result = NULL;
|
||||||
|
|
||||||
if (PasswdDB* db = init_passwd_db()) {
|
if ((status = init_passwd_db()) == B_OK) {
|
||||||
status = db->GetNextEntry(passwd, buffer, bufferSize);
|
if (sIterationIndex >= sPasswdEntryCount)
|
||||||
if (status == 0)
|
return ENOENT;
|
||||||
*_result = passwd;
|
|
||||||
|
|
||||||
|
status = BPrivate::copy_passwd_to_buffer(
|
||||||
|
sPasswdEntries[sIterationIndex], passwd, buffer, bufferSize);
|
||||||
|
|
||||||
|
if (status == B_OK) {
|
||||||
|
sIterationIndex++;
|
||||||
|
*_result = passwd;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
@@ -128,8 +165,7 @@ setpwent(void)
|
|||||||
{
|
{
|
||||||
UserGroupLocker _;
|
UserGroupLocker _;
|
||||||
|
|
||||||
if (PasswdDB* db = init_passwd_db())
|
sIterationIndex = 0;
|
||||||
db->RewindEntries();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -138,12 +174,10 @@ endpwent(void)
|
|||||||
{
|
{
|
||||||
UserGroupLocker locker;
|
UserGroupLocker locker;
|
||||||
|
|
||||||
PasswdDB* db = sPasswdDB;
|
sPasswdDBReply.Unset();
|
||||||
sPasswdDB = NULL;
|
sPasswdEntries = NULL;
|
||||||
|
sPasswdEntryCount = 0;
|
||||||
locker.Unlock();
|
sIterationIndex = 0;
|
||||||
|
|
||||||
delete db;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -163,11 +197,7 @@ int
|
|||||||
getpwnam_r(const char *name, struct passwd *passwd, char *buffer,
|
getpwnam_r(const char *name, struct passwd *passwd, char *buffer,
|
||||||
size_t bufferSize, struct passwd **_result)
|
size_t bufferSize, struct passwd **_result)
|
||||||
{
|
{
|
||||||
PasswdEntryFindHandler handler(name, 0, passwd, buffer, bufferSize);
|
return query_passwd_entry(name, 0, passwd, buffer, bufferSize, _result);
|
||||||
status_t status = PasswdDBReader(&handler).Read(BPrivate::kPasswdFile);
|
|
||||||
|
|
||||||
*_result = (status == 1 ? passwd : NULL);
|
|
||||||
return (status == 1 ? 0 : (status == 0 ? ENOENT : status));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -187,9 +217,5 @@ int
|
|||||||
getpwuid_r(uid_t uid, struct passwd *passwd, char *buffer,
|
getpwuid_r(uid_t uid, struct passwd *passwd, char *buffer,
|
||||||
size_t bufferSize, struct passwd **_result)
|
size_t bufferSize, struct passwd **_result)
|
||||||
{
|
{
|
||||||
PasswdEntryFindHandler handler(NULL, uid, passwd, buffer, bufferSize);
|
return query_passwd_entry(NULL, uid, passwd, buffer, bufferSize, _result);
|
||||||
status_t status = PasswdDBReader(&handler).Read(BPrivate::kPasswdFile);
|
|
||||||
|
|
||||||
*_result = (status == 1 ? passwd : NULL);
|
|
||||||
return (status == 1 ? 0 : (status == 0 ? ENOENT : status));
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,275 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008, Ingo Weinhold, [email protected]. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <shadow.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#include <OS.h>
|
||||||
|
|
||||||
|
#include <AutoDeleter.h>
|
||||||
|
#include <libroot_private.h>
|
||||||
|
#include <RegistrarDefs.h>
|
||||||
|
#include <user_group.h>
|
||||||
|
|
||||||
|
#include <util/KMessage.h>
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
@@ -3,42 +3,33 @@
|
|||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "user_group_common.h"
|
#include <user_group.h>
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
#include <libroot_lock.h>
|
#include <libroot_lock.h>
|
||||||
#include <libroot_private.h>
|
#include <libroot_private.h>
|
||||||
|
#include <RegistrarDefs.h>
|
||||||
|
|
||||||
|
#include <util/KMessage.h>
|
||||||
|
|
||||||
|
|
||||||
using BPrivate::FileLineReader;
|
|
||||||
using BPrivate::Tokenizer;
|
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::kPasswdFile = "/etc/passwd";
|
||||||
const char* BPrivate::kGroupFile = "/etc/group";
|
const char* BPrivate::kGroupFile = "/etc/group";
|
||||||
|
const char* BPrivate::kShadowPwdFile = "/etc/shadow";
|
||||||
|
|
||||||
static benaphore sUserGroupLock;
|
static benaphore sUserGroupLock;
|
||||||
|
static port_id sRegistrarPort = -1;
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
@@ -55,83 +46,27 @@ BPrivate::user_group_unlock()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class FileLineReader {
|
port_id
|
||||||
public:
|
BPrivate::get_registrar_authentication_port()
|
||||||
FileLineReader(int fd)
|
{
|
||||||
: fFD(fd),
|
if (sRegistrarPort < 0)
|
||||||
fSize(0),
|
sRegistrarPort = find_port(REGISTRAR_AUTHENTICATION_PORT_NAME);
|
||||||
fOffset(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
char* NextLine()
|
return sRegistrarPort;
|
||||||
{
|
}
|
||||||
char* eol;
|
|
||||||
if (fOffset >= fSize
|
|
||||||
|| (eol = strchr(fBuffer + fOffset, '\n')) == NULL) {
|
|
||||||
_ReadBuffer();
|
|
||||||
if (fOffset >= fSize)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
eol = strchr(fBuffer + fOffset, '\n');
|
|
||||||
if (eol == NULL)
|
|
||||||
eol = fBuffer + fSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* result = fBuffer + fOffset;
|
status_t
|
||||||
*eol = '\0';
|
BPrivate::send_authentication_request_to_registrar(KMessage& request,
|
||||||
fOffset = eol + 1 - fBuffer;
|
KMessage& reply)
|
||||||
return result;
|
{
|
||||||
}
|
status_t error = request.SendTo(get_registrar_authentication_port(), 0,
|
||||||
|
&reply);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
char* NextNonEmptyLine()
|
return (status_t)reply.What();
|
||||||
{
|
}
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class Tokenizer {
|
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
|
// #pragma mark - passwd support
|
||||||
|
|
||||||
|
|
||||||
@@ -405,86 +176,29 @@ BPrivate::copy_passwd_to_buffer(const char* name, const char* password,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - PasswdDBEntry
|
status_t
|
||||||
|
BPrivate::copy_passwd_to_buffer(const passwd* from, passwd* entry, char* buffer,
|
||||||
|
size_t bufferSize)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
|
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
|
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(':');
|
Tokenizer tokenizer(line);
|
||||||
char* password = tokenizer.NextTrimmedToken(':');
|
|
||||||
|
name = tokenizer.NextTrimmedToken(':');
|
||||||
|
password = tokenizer.NextTrimmedToken(':');
|
||||||
char* userID = tokenizer.NextTrimmedToken(':');
|
char* userID = tokenizer.NextTrimmedToken(':');
|
||||||
char* groupID = tokenizer.NextTrimmedToken(':');
|
char* groupID = tokenizer.NextTrimmedToken(':');
|
||||||
char* realName = tokenizer.NextTrimmedToken(':');
|
realName = tokenizer.NextTrimmedToken(':');
|
||||||
char* home = tokenizer.NextTrimmedToken(':');
|
home = tokenizer.NextTrimmedToken(':');
|
||||||
char* shell = tokenizer.NextTrimmedToken(':');
|
shell = tokenizer.NextTrimmedToken(':');
|
||||||
|
|
||||||
// skip if invalid
|
// skip if invalid
|
||||||
size_t nameLen;
|
size_t nameLen;
|
||||||
@@ -495,44 +209,17 @@ PasswdDBReader::ParseEntryLine(Tokenizer& tokenizer)
|
|||||||
|| strlen(realName) >= MAX_PASSWD_REAL_NAME_LEN
|
|| strlen(realName) >= MAX_PASSWD_REAL_NAME_LEN
|
||||||
|| strlen(home) >= MAX_PASSWD_HOME_DIR_LEN
|
|| strlen(home) >= MAX_PASSWD_HOME_DIR_LEN
|
||||||
|| strlen(shell) >= MAX_PASSWD_SHELL_LEN) {
|
|| strlen(shell) >= MAX_PASSWD_SHELL_LEN) {
|
||||||
return B_OK;
|
return B_BAD_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
gid_t uid = atoi(userID);
|
uid = atoi(userID);
|
||||||
gid_t gid = atoi(groupID);
|
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;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - passwd support
|
// #pragma mark - group support
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
@@ -566,87 +253,27 @@ BPrivate::copy_group_to_buffer(const char* name, const char* password,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - GroupDBEntry
|
status_t
|
||||||
|
BPrivate::copy_group_to_buffer(const group* from, group* entry, char* buffer,
|
||||||
|
size_t bufferSize)
|
||||||
GroupDBEntry::GroupDBEntry()
|
|
||||||
: FileDBEntry(),
|
|
||||||
fPassword(NULL),
|
|
||||||
fMembers(NULL),
|
|
||||||
fMemberCount(0)
|
|
||||||
{
|
{
|
||||||
}
|
int memberCount = 0;
|
||||||
|
while (from->gr_mem[memberCount] != NULL)
|
||||||
|
memberCount++;
|
||||||
|
|
||||||
|
return copy_group_to_buffer(from->gr_name, from->gr_passwd,
|
||||||
GroupDBEntry::~GroupDBEntry()
|
from->gr_gid, from->gr_mem, memberCount, entry, buffer, bufferSize);
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
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(':');
|
Tokenizer tokenizer(line);
|
||||||
char* password = tokenizer.NextTrimmedToken(':');
|
|
||||||
|
name = tokenizer.NextTrimmedToken(':');
|
||||||
|
password = tokenizer.NextTrimmedToken(':');
|
||||||
char* groupID = tokenizer.NextTrimmedToken(':');
|
char* groupID = tokenizer.NextTrimmedToken(':');
|
||||||
|
|
||||||
// skip if invalid
|
// skip if invalid
|
||||||
@@ -654,13 +281,12 @@ GroupDBReader::ParseEntryLine(Tokenizer& tokenizer)
|
|||||||
if (groupID == NULL || (nameLen = strlen(name)) == 0 || !isdigit(*groupID)
|
if (groupID == NULL || (nameLen = strlen(name)) == 0 || !isdigit(*groupID)
|
||||||
|| nameLen >= MAX_GROUP_NAME_LEN
|
|| nameLen >= MAX_GROUP_NAME_LEN
|
||||||
|| strlen(password) >= MAX_GROUP_PASSWORD_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];
|
memberCount = 0;
|
||||||
int memberCount = 0;
|
|
||||||
|
|
||||||
while (char* groupUser = tokenizer.NextTrimmedToken(',')) {
|
while (char* groupUser = tokenizer.NextTrimmedToken(',')) {
|
||||||
// ignore invalid members
|
// ignore invalid members
|
||||||
@@ -674,32 +300,78 @@ GroupDBReader::ParseEntryLine(Tokenizer& tokenizer)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return fHandler->HandleEntry(name, password, gid, members, memberCount);
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - GroupDB
|
// #pragma mark - shadow password support
|
||||||
|
|
||||||
|
|
||||||
status_t
|
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
|
status_t
|
||||||
GroupDB::HandleEntry(const char* name, const char* password, gid_t gid,
|
BPrivate::copy_shadow_pwd_to_buffer(const spwd* from, spwd* entry,
|
||||||
const char* const* members, int memberCount)
|
char* buffer, size_t bufferSize)
|
||||||
{
|
{
|
||||||
GroupDBEntry* entry = new(std::nothrow) GroupDBEntry();
|
return copy_shadow_pwd_to_buffer(from->sp_namp, from->sp_pwdp,
|
||||||
if (entry == NULL || !entry->Init(name, password, gid, members,
|
from->sp_min, from->sp_max, from->sp_warn, from->sp_inact,
|
||||||
memberCount)) {
|
from->sp_expire, from->sp_flag, entry, buffer, bufferSize);
|
||||||
delete entry;
|
}
|
||||||
return B_NO_MEMORY;
|
|
||||||
|
|
||||||
|
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;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 <grp.h>
|
|
||||||
#include <pwd.h>
|
|
||||||
|
|
||||||
#include <SupportDefs.h>
|
|
||||||
|
|
||||||
#include <AutoLocker.h>
|
|
||||||
|
|
||||||
|
|
||||||
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<int, UserGroupLocking> {
|
|
||||||
public:
|
|
||||||
UserGroupLocker()
|
|
||||||
: AutoLocker<int, UserGroupLocking>((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
|
|
||||||
Reference in New Issue
Block a user