* Replaced the dummy implementations of the <grp.h> and <pwd.h>
functions by ones reading /etc/{group,passwd}.
* Added quasi-standard getpwent_r() and getgrent_r().
* Added _SC_GETGR_R_SIZE_MAX and _SC_GETPW_R_SIZE_MAX sysconf()
constants.
* Moved initgroups() and getgrouplist() definition to grp.cpp. They use
the same backend as the <grp.h> functions.
* Set the permissions of files created by the build system to what they
should be on the image (executables: 755, others: 644). Otherwise only
root could do anything under Haiku.
* Added build system variables HAIKU_ROOT_USER_NAME and
HAIKU_ROOT_USER_REAL_NAME to customize name and real name of Haiku's
root user.
* Added build system rules AddUserToHaikuImage and AddGroupToHaikuImage
for adding additional users and groups (by default only root user and
group and a "users" group are created).
* Adjusted BIND port and coreutils config.h files according to what
features have become available.
* Fixed HAIKU_DOCUMENTATION_OBJECT_DIR definition. Untested, but it used
a wrong variable name before.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24750 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -871,10 +871,16 @@ SUPPORTED_PLATFORMS = haiku ;
|
|||||||
KEEPOBJS = true ;
|
KEEPOBJS = true ;
|
||||||
|
|
||||||
|
|
||||||
|
# Set permissions to how they should be on the image.
|
||||||
|
EXEMODE = 755 ;
|
||||||
|
FILEMODE = 644 ;
|
||||||
|
SHELLMODE = 755 ;
|
||||||
|
|
||||||
|
|
||||||
# output directories
|
# output directories
|
||||||
# TODO: Review this.
|
# TODO: Review this.
|
||||||
HAIKU_DOCUMENTATION_DIR ?= [ FDirName $(HAIKU_OUTPUT_DIR) documentation ] ;
|
HAIKU_DOCUMENTATION_DIR ?= [ FDirName $(HAIKU_OUTPUT_DIR) documentation ] ;
|
||||||
HAIKU_DOCUMENTATION_OBJECT_DIR ?= [ FDirName $(HAIKU_COMMON_PLATFORM_DIR)
|
HAIKU_DOCUMENTATION_OBJECT_DIR ?= [ FDirName $(HAIKU_COMMON_PLATFORM_OBJECT_DIR)
|
||||||
documentation ] ;
|
documentation ] ;
|
||||||
|
|
||||||
# TODO: Rethink test stuff.
|
# TODO: Rethink test stuff.
|
||||||
|
|||||||
+11
-1
@@ -419,7 +419,7 @@ AddDirectoryToHaikuImage home config add-ons Translators ;
|
|||||||
AddDirectoryToHaikuImage beos etc synth ;
|
AddDirectoryToHaikuImage beos etc synth ;
|
||||||
AddDirectoryToHaikuImage beos system add-ons input_server methods ;
|
AddDirectoryToHaikuImage beos system add-ons input_server methods ;
|
||||||
|
|
||||||
#optional
|
# optional
|
||||||
AddFilesToHaikuImage optional beos system add-ons input_server methods : canna ;
|
AddFilesToHaikuImage optional beos system add-ons input_server methods : canna ;
|
||||||
|
|
||||||
# printers
|
# printers
|
||||||
@@ -481,6 +481,16 @@ if $(HAIKU_ADD_POSIX_TEST_SUITE_TO_IMAGE) {
|
|||||||
include [ FDirName $(HAIKU_BUILD_RULES_DIR) OptionalPackages ] ;
|
include [ FDirName $(HAIKU_BUILD_RULES_DIR) OptionalPackages ] ;
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - User/Group Setup
|
||||||
|
|
||||||
|
|
||||||
|
# add the root user and the root and users groups
|
||||||
|
AddUserToHaikuImage $(HAIKU_ROOT_USER_NAME:E=baron) : 0 : 0 : /boot/home
|
||||||
|
: /bin/bash : $(HAIKU_ROOT_USER_REAL_NAME:E="Root User") ;
|
||||||
|
AddGroupToHaikuImage root : 0 : ;
|
||||||
|
AddGroupToHaikuImage users : 100 : ;
|
||||||
|
|
||||||
|
|
||||||
#pragma mark - Build The Image
|
#pragma mark - Build The Image
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -676,6 +676,53 @@ rule InstallOptionalHaikuImagePackage package : url : dirTokens
|
|||||||
UnzipArchiveToHaikuImage $(dirTokens) : $(zipFile) ;
|
UnzipArchiveToHaikuImage $(dirTokens) : $(zipFile) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rule AddEntryToHaikuImageUserGroupFile file : entry
|
||||||
|
{
|
||||||
|
local allEntries = [ on $(file) return $(HAIKU_IMAGE_USER_GROUP_ENTRIES) ] ;
|
||||||
|
|
||||||
|
if $(allEntries) {
|
||||||
|
allEntries = $(allEntries)|$(entry) ;
|
||||||
|
} else {
|
||||||
|
allEntries = $(entry) ;
|
||||||
|
|
||||||
|
Always $(file) ;
|
||||||
|
MakeLocate $(file) : $(HAIKU_COMMON_PLATFORM_OBJECT_DIR) ;
|
||||||
|
BuildHaikuImageUserGroupFile $(file) ;
|
||||||
|
AddFilesToHaikuImage beos etc : $(file) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
HAIKU_IMAGE_USER_GROUP_ENTRIES on $(file) = $(allEntries) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
actions BuildHaikuImageUserGroupFile
|
||||||
|
{
|
||||||
|
echo "$(HAIKU_IMAGE_USER_GROUP_ENTRIES)" | tr '|' '\n' > $(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
rule AddUserToHaikuImage user : uid : gid : home : shell : realName
|
||||||
|
{
|
||||||
|
if ! $(user) || ! $(uid) || ! $(gid) || ! $(home) {
|
||||||
|
Exit "Invalid haiku user specification passed to AddUserToHaikuImage." ;
|
||||||
|
}
|
||||||
|
|
||||||
|
local entry
|
||||||
|
= $(user):x:$(uid):$(gid):$(realName:E=$(user)):$(home):$(shell:E="") ;
|
||||||
|
|
||||||
|
AddEntryToHaikuImageUserGroupFile <haiku-image>passwd : $(entry) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
rule AddGroupToHaikuImage group : gid : members
|
||||||
|
{
|
||||||
|
if ! $(group) || ! $(gid) {
|
||||||
|
Exit "Invalid haiku group specification passed to"
|
||||||
|
"AddGroupToHaikuImage." ;
|
||||||
|
}
|
||||||
|
|
||||||
|
local entry = $(group):x:$(gid):$(members:J=,:E) ;
|
||||||
|
|
||||||
|
AddEntryToHaikuImageUserGroupFile <haiku-image>group : $(entry) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
rule CreateHaikuImageMakeDirectoriesScript script
|
rule CreateHaikuImageMakeDirectoriesScript script
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -131,6 +131,22 @@ HAIKU_ADD_ALL_OPTIONAL_PACKAGES = 1 ;
|
|||||||
HAIKU_IMAGE_EARLY_USER_SCRIPTS = $(HAIKU_TOP)/../early-image-script.sh ;
|
HAIKU_IMAGE_EARLY_USER_SCRIPTS = $(HAIKU_TOP)/../early-image-script.sh ;
|
||||||
HAIKU_IMAGE_LATE_USER_SCRIPTS = $(HAIKU_TOP)/../late-image-script.sh ;
|
HAIKU_IMAGE_LATE_USER_SCRIPTS = $(HAIKU_TOP)/../late-image-script.sh ;
|
||||||
|
|
||||||
|
# Set name and real name of the root user. Defaults to "baron" and "Root User".
|
||||||
|
HAIKU_ROOT_USER_NAME = bond ;
|
||||||
|
HAIKU_ROOT_USER_REAL_NAME = "James Bond" ;
|
||||||
|
|
||||||
|
# Add user "walter" with user ID 1000 and group ID 100 (note, that a group with
|
||||||
|
# that ID should exist -- 100 already exists and is the "users" group), home
|
||||||
|
# directory "/boot/home", shell "/bin/bash", and real name "Just Walter" to the
|
||||||
|
# image.
|
||||||
|
AddUserToHaikuImage walter : 1000 : 100 : /boot/home : /bin/bash
|
||||||
|
: "Just Walter" ;
|
||||||
|
|
||||||
|
# Add group "party" with group ID 101 and members "baron" and "walter" to the
|
||||||
|
# image.
|
||||||
|
AddGroupToHaikuImage party : 101 : baron walter ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Creating Sourceable Shell Scripts
|
# Creating Sourceable Shell Scripts
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ extern int getgrnam_r(const char *name, struct group *group, char *buffer,
|
|||||||
size_t bufferSize, struct group **_result);
|
size_t bufferSize, struct group **_result);
|
||||||
|
|
||||||
extern struct group *getgrent(void);
|
extern struct group *getgrent(void);
|
||||||
|
extern int getgrent_r(struct group* group, char* buffer, size_t bufferSize,
|
||||||
|
struct group** _result);
|
||||||
extern void setgrent(void);
|
extern void setgrent(void);
|
||||||
extern void endgrent(void);
|
extern void endgrent(void);
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -22,10 +22,12 @@ struct passwd {
|
|||||||
|
|
||||||
/* traverse the user password database */
|
/* traverse the user password database */
|
||||||
extern struct passwd *getpwent(void);
|
extern struct passwd *getpwent(void);
|
||||||
|
extern int getpwent_r(struct passwd* pwbuf, char* buf, size_t buflen,
|
||||||
|
struct passwd** pwbufp);
|
||||||
extern void setpwent(void);
|
extern void setpwent(void);
|
||||||
extern void endpwent(void);
|
extern void endpwent(void);
|
||||||
|
|
||||||
/*search the user password database */
|
/* search the user password database */
|
||||||
extern struct passwd *getpwnam(const char *name);
|
extern struct passwd *getpwnam(const char *name);
|
||||||
extern int getpwnam_r(const char *name, struct passwd *passwd, char *buffer,
|
extern int getpwnam_r(const char *name, struct passwd *passwd, char *buffer,
|
||||||
size_t bufferSize, struct passwd **result);
|
size_t bufferSize, struct passwd **result);
|
||||||
|
|||||||
@@ -57,6 +57,8 @@
|
|||||||
#define _SC_STREAM_MAX 22
|
#define _SC_STREAM_MAX 22
|
||||||
#define _SC_TZNAME_MAX 23
|
#define _SC_TZNAME_MAX 23
|
||||||
#define _SC_VERSION 24
|
#define _SC_VERSION 24
|
||||||
|
#define _SC_GETGR_R_SIZE_MAX 25
|
||||||
|
#define _SC_GETPW_R_SIZE_MAX 26
|
||||||
|
|
||||||
/* lseek() constants */
|
/* lseek() constants */
|
||||||
#ifndef SEEK_SET
|
#ifndef SEEK_SET
|
||||||
|
|||||||
@@ -10,6 +10,30 @@
|
|||||||
#include <image.h>
|
#include <image.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define MAX_PASSWD_NAME_LEN (32)
|
||||||
|
#define MAX_PASSWD_PASSWORD_LEN (32)
|
||||||
|
#define MAX_PASSWD_REAL_NAME_LEN (128)
|
||||||
|
#define MAX_PASSWD_HOME_DIR_LEN (B_PATH_NAME_LENGTH)
|
||||||
|
#define MAX_PASSWD_SHELL_LEN (B_PATH_NAME_LENGTH)
|
||||||
|
|
||||||
|
#define MAX_PASSWD_BUFFER_SIZE ( \
|
||||||
|
MAX_PASSWD_NAME_LEN \
|
||||||
|
+ MAX_PASSWD_PASSWORD_LEN \
|
||||||
|
+ MAX_PASSWD_REAL_NAME_LEN \
|
||||||
|
+ MAX_PASSWD_HOME_DIR_LEN \
|
||||||
|
+ MAX_PASSWD_SHELL_LEN)
|
||||||
|
|
||||||
|
#define MAX_GROUP_NAME_LEN (32)
|
||||||
|
#define MAX_GROUP_PASSWORD_LEN (32)
|
||||||
|
#define MAX_GROUP_MEMBER_COUNT (32)
|
||||||
|
|
||||||
|
#define MAX_GROUP_BUFFER_SIZE ( \
|
||||||
|
MAX_GROUP_NAME_LEN \
|
||||||
|
+ MAX_GROUP_PASSWORD_LEN \
|
||||||
|
+ ((MAX_GROUP_MEMBER_COUNT + 1) * sizeof(char*)))
|
||||||
|
// MAX_GROUP_NAME_LEN and MAX_GROUP_PASSWORD_LEN are char* aligned
|
||||||
|
|
||||||
|
|
||||||
struct user_space_program_args;
|
struct user_space_program_args;
|
||||||
struct real_time_data;
|
struct real_time_data;
|
||||||
|
|
||||||
@@ -33,6 +57,8 @@ void __init_time(void);
|
|||||||
void __arch_init_time(struct real_time_data *data, bool setDefaults);
|
void __arch_init_time(struct real_time_data *data, bool setDefaults);
|
||||||
bigtime_t __arch_get_system_time_offset(struct real_time_data *data);
|
bigtime_t __arch_get_system_time_offset(struct real_time_data *data);
|
||||||
void __init_pwd_backend(void);
|
void __init_pwd_backend(void);
|
||||||
|
void __reinit_pwd_backend_after_fork(void);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -228,10 +228,10 @@
|
|||||||
/* #undef HAVE_CFPREFERENCESCOPYAPPVALUE */
|
/* #undef HAVE_CFPREFERENCESCOPYAPPVALUE */
|
||||||
|
|
||||||
/* Define to 1 if your system has a working `chown' function. */
|
/* Define to 1 if your system has a working `chown' function. */
|
||||||
/* #undef HAVE_CHOWN */
|
#define HAVE_CHOWN 1
|
||||||
|
|
||||||
/* Define to 1 if you have the `chroot' function. */
|
/* Define to 1 if you have the `chroot' function. */
|
||||||
/* #undef HAVE_CHROOT */
|
#define HAVE_CHROOT 1
|
||||||
|
|
||||||
/* Define to 1 if you have the `chsize' function. */
|
/* Define to 1 if you have the `chsize' function. */
|
||||||
/* #undef HAVE_CHSIZE */
|
/* #undef HAVE_CHSIZE */
|
||||||
@@ -671,7 +671,7 @@
|
|||||||
/* #undef HAVE_INET_NTOP */
|
/* #undef HAVE_INET_NTOP */
|
||||||
|
|
||||||
/* Define to 1 if you have the `initgroups' function. */
|
/* Define to 1 if you have the `initgroups' function. */
|
||||||
/* #undef HAVE_INITGROUPS */
|
#define HAVE_INITGROUPS 1
|
||||||
|
|
||||||
/* Define to 1 if the compiler supports one of the keywords 'inline',
|
/* Define to 1 if the compiler supports one of the keywords 'inline',
|
||||||
'__inline__', '__inline' and effectively inlines functions marked as such.
|
'__inline__', '__inline' and effectively inlines functions marked as such.
|
||||||
@@ -928,7 +928,7 @@
|
|||||||
#define HAVE_SETENV 1
|
#define HAVE_SETENV 1
|
||||||
|
|
||||||
/* Define to 1 if you have the `setgroups' function. */
|
/* Define to 1 if you have the `setgroups' function. */
|
||||||
/* #undef HAVE_SETGROUPS */
|
#define HAVE_SETGROUPS 1
|
||||||
|
|
||||||
/* Define to 1 if you have the `sethostname' function. */
|
/* Define to 1 if you have the `sethostname' function. */
|
||||||
#define HAVE_SETHOSTNAME 1
|
#define HAVE_SETHOSTNAME 1
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
/* define if prototype for getgrnam_r() is required */
|
/* define if prototype for getgrnam_r() is required */
|
||||||
#define NEED_GETGRNAM_R 1
|
#define NEED_GETGRNAM_R 1
|
||||||
#define NEED_GETGRGID_R 1
|
#define NEED_GETGRGID_R 1
|
||||||
#define NEED_GETGRENT_R 1
|
/*#define NEED_GETGRENT_R 1*/
|
||||||
#define NEED_SETGRENT_R 1
|
#define NEED_SETGRENT_R 1
|
||||||
#define NEED_ENDGRENT_R 1
|
#define NEED_ENDGRENT_R 1
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
#define NEED_SETPWENT_R 1
|
#define NEED_SETPWENT_R 1
|
||||||
#define NEED_SETPASSENT_R 1
|
#define NEED_SETPASSENT_R 1
|
||||||
#define NEED_SETPWENT_R 1
|
#define NEED_SETPWENT_R 1
|
||||||
#define NEED_GETPWENT_R 1
|
/*#define NEED_GETPWENT_R 1*/
|
||||||
#define NEED_ENDPWENT_R 1
|
#define NEED_ENDPWENT_R 1
|
||||||
|
|
||||||
#define NEED_SETPASSENT 1
|
#define NEED_SETPASSENT 1
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
SubDir HAIKU_TOP src system libroot posix ;
|
SubDir HAIKU_TOP src system libroot posix ;
|
||||||
|
|
||||||
UsePrivateHeaders [ FDirName syslog_daemon ] ;
|
UsePrivateHeaders shared [ FDirName syslog_daemon ] ;
|
||||||
UseHeaders $(TARGET_PRIVATE_KERNEL_HEADERS) : true ;
|
UseHeaders $(TARGET_PRIVATE_KERNEL_HEADERS) : true ;
|
||||||
|
|
||||||
if $(HAIKU_ENABLE_MULTIUSER) = 1 {
|
if $(HAIKU_MULTIUSER_QUERY) = 1 {
|
||||||
PWD_BACKEND = pwd_query.c ;
|
PWD_BACKEND = pwd_query.c ;
|
||||||
} else {
|
} else {
|
||||||
PWD_BACKEND = pwd.c grp.c ;
|
PWD_BACKEND = pwd.cpp grp.cpp user_group_common.cpp ;
|
||||||
}
|
}
|
||||||
MergeObject posix_main.o :
|
MergeObject posix_main.o :
|
||||||
assert.c
|
assert.c
|
||||||
|
|||||||
@@ -1,121 +0,0 @@
|
|||||||
/*
|
|
||||||
** Copyright 2004, Axel Dörfler, [email protected]. All rights reserved.
|
|
||||||
** Distributed under the terms of the Haiku License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Dumb group functions - only know the "users" group with group ID 0 right
|
|
||||||
* now - this should definitely be thought over :-)
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include <SupportDefs.h>
|
|
||||||
|
|
||||||
#include <grp.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
|
|
||||||
static int32 sGroupIndex;
|
|
||||||
static struct group sGroup;
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
get_users(struct group *gr)
|
|
||||||
{
|
|
||||||
static char *nothing = "";
|
|
||||||
|
|
||||||
gr->gr_name = "users";
|
|
||||||
gr->gr_passwd = NULL;
|
|
||||||
gr->gr_gid = 0;
|
|
||||||
gr->gr_mem = ¬hing;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
init_users()
|
|
||||||
{
|
|
||||||
if (sGroupIndex == 0) {
|
|
||||||
// initial construction of the group
|
|
||||||
get_users(&sGroup);
|
|
||||||
sGroupIndex = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct group *
|
|
||||||
getgrgid(gid_t gid)
|
|
||||||
{
|
|
||||||
if (gid != 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
init_users();
|
|
||||||
return &sGroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
getgrgid_r(gid_t gid, struct group *group, char *buffer,
|
|
||||||
size_t bufferSize, struct group **_result)
|
|
||||||
{
|
|
||||||
if (gid != 0) {
|
|
||||||
*_result = NULL;
|
|
||||||
return B_ENTRY_NOT_FOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
get_users(group);
|
|
||||||
*_result = group;
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct group *
|
|
||||||
getgrnam(const char *name)
|
|
||||||
{
|
|
||||||
if (strcmp("users", name))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
init_users();
|
|
||||||
return &sGroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
getgrnam_r(const char *name, struct group *group, char *buffer,
|
|
||||||
size_t bufferSize, struct group **_result)
|
|
||||||
{
|
|
||||||
if (strcmp("users", name)) {
|
|
||||||
*_result = NULL;
|
|
||||||
return B_ENTRY_NOT_FOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
get_users(group);
|
|
||||||
*_result = group;
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct group *
|
|
||||||
getgrent(void)
|
|
||||||
{
|
|
||||||
if (sGroupIndex > 1)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
init_users();
|
|
||||||
sGroupIndex++;
|
|
||||||
|
|
||||||
return &sGroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
setgrent(void)
|
|
||||||
{
|
|
||||||
init_users();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
endgrent(void)
|
|
||||||
{
|
|
||||||
init_users();
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -0,0 +1,260 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008, Ingo Weinhold, [email protected]. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <grp.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#include <OS.h>
|
||||||
|
|
||||||
|
#include <libroot_private.h>
|
||||||
|
|
||||||
|
#include "user_group_common.h"
|
||||||
|
|
||||||
|
|
||||||
|
using BPrivate::GroupDB;
|
||||||
|
using BPrivate::GroupDBReader;
|
||||||
|
using BPrivate::GroupEntryHandler;
|
||||||
|
using BPrivate::UserGroupLocker;
|
||||||
|
|
||||||
|
static GroupDB* sGroupDB = NULL;
|
||||||
|
|
||||||
|
static struct group sGroupBuffer;
|
||||||
|
static char sGroupStringBuffer[MAX_GROUP_BUFFER_SIZE];
|
||||||
|
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class GroupEntryFindHandler : public GroupEntryHandler {
|
||||||
|
public:
|
||||||
|
GroupEntryFindHandler(const char* name, uid_t gid,
|
||||||
|
group* entry, char* buffer, size_t bufferSize)
|
||||||
|
:
|
||||||
|
fName(name),
|
||||||
|
fGID(gid),
|
||||||
|
fEntry(entry),
|
||||||
|
fBuffer(buffer),
|
||||||
|
fBufferSize(bufferSize)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual status_t HandleEntry(const char* name, const char* password,
|
||||||
|
gid_t gid, const char* const* members, int memberCount)
|
||||||
|
{
|
||||||
|
if (fName != NULL ? strcmp(fName, name) != 0 : fGID != gid)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// found
|
||||||
|
status_t error = BPrivate::copy_group_to_buffer(name, password, gid,
|
||||||
|
members, memberCount, fEntry, fBuffer, fBufferSize);
|
||||||
|
|
||||||
|
return error == B_OK ? 1 : error;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char* fName;
|
||||||
|
gid_t fGID;
|
||||||
|
group* fEntry;
|
||||||
|
char* fBuffer;
|
||||||
|
size_t fBufferSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class UserGroupEntryHandler : public BPrivate::GroupEntryHandler {
|
||||||
|
public:
|
||||||
|
UserGroupEntryHandler(const char* user, gid_t* groupList, int maxGroupCount,
|
||||||
|
int* groupCount)
|
||||||
|
:
|
||||||
|
fUser(user),
|
||||||
|
fGroupList(groupList),
|
||||||
|
fMaxGroupCount(maxGroupCount),
|
||||||
|
fGroupCount(groupCount)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual status_t HandleEntry(const char* name, const char* password,
|
||||||
|
gid_t gid, const char* const* members, int memberCount)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < memberCount; i++) {
|
||||||
|
const char* member = members[i];
|
||||||
|
if (*member != '\0' && strcmp(member, fUser) == 0) {
|
||||||
|
if (*fGroupCount < fMaxGroupCount)
|
||||||
|
fGroupList[*fGroupCount] = gid;
|
||||||
|
++*fGroupCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char* fUser;
|
||||||
|
gid_t* fGroupList;
|
||||||
|
int fMaxGroupCount;
|
||||||
|
int* fGroupCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // empty namespace
|
||||||
|
|
||||||
|
|
||||||
|
static GroupDB*
|
||||||
|
init_group_db()
|
||||||
|
{
|
||||||
|
if (sGroupDB != NULL)
|
||||||
|
return sGroupDB;
|
||||||
|
|
||||||
|
sGroupDB = new(nothrow) GroupDB;
|
||||||
|
if (sGroupDB == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (sGroupDB->Init() != B_OK) {
|
||||||
|
delete sGroupDB;
|
||||||
|
sGroupDB = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sGroupDB;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
struct group*
|
||||||
|
getgrent(void)
|
||||||
|
{
|
||||||
|
struct group* result = NULL;
|
||||||
|
int status = getgrent_r(&sGroupBuffer, sGroupStringBuffer,
|
||||||
|
sizeof(sGroupStringBuffer), &result);
|
||||||
|
if (status != 0)
|
||||||
|
errno = status;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
getgrent_r(struct group* group, char* buffer, size_t bufferSize,
|
||||||
|
struct group** _result)
|
||||||
|
{
|
||||||
|
UserGroupLocker _;
|
||||||
|
|
||||||
|
int status = B_NO_MEMORY;
|
||||||
|
|
||||||
|
*_result = NULL;
|
||||||
|
|
||||||
|
if (GroupDB* db = init_group_db()) {
|
||||||
|
status = db->GetNextEntry(group, buffer, bufferSize);
|
||||||
|
if (status == 0)
|
||||||
|
*_result = group;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
setgrent(void)
|
||||||
|
{
|
||||||
|
UserGroupLocker _;
|
||||||
|
|
||||||
|
if (GroupDB* db = init_group_db())
|
||||||
|
db->RewindEntries();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
endgrent(void)
|
||||||
|
{
|
||||||
|
UserGroupLocker locker;
|
||||||
|
|
||||||
|
GroupDB* db = sGroupDB;
|
||||||
|
sGroupDB = NULL;
|
||||||
|
|
||||||
|
locker.Unlock();
|
||||||
|
|
||||||
|
delete db;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct group *
|
||||||
|
getgrnam(const char *name)
|
||||||
|
{
|
||||||
|
struct group* result = NULL;
|
||||||
|
int status = getgrnam_r(name, &sGroupBuffer, sGroupStringBuffer,
|
||||||
|
sizeof(sGroupStringBuffer), &result);
|
||||||
|
if (status != 0)
|
||||||
|
errno = status;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
getgrnam_r(const char *name, struct group *group, char *buffer,
|
||||||
|
size_t bufferSize, struct group **_result)
|
||||||
|
{
|
||||||
|
GroupEntryFindHandler handler(name, 0, group, buffer, bufferSize);
|
||||||
|
status_t status = GroupDBReader(&handler).Read(BPrivate::kGroupFile);
|
||||||
|
|
||||||
|
*_result = (status == 1 ? group : NULL);
|
||||||
|
return (status == 1 ? 0 : (status == 0 ? ENOENT : status));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct group *
|
||||||
|
getgrgid(gid_t gid)
|
||||||
|
{
|
||||||
|
struct group* result = NULL;
|
||||||
|
int status = getgrgid_r(gid, &sGroupBuffer, sGroupStringBuffer,
|
||||||
|
sizeof(sGroupStringBuffer), &result);
|
||||||
|
if (status != 0)
|
||||||
|
errno = status;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
getgrgid_r(gid_t gid, struct group *group, char *buffer,
|
||||||
|
size_t bufferSize, struct group **_result)
|
||||||
|
{
|
||||||
|
GroupEntryFindHandler handler(NULL, gid, group, buffer, bufferSize);
|
||||||
|
status_t status = GroupDBReader(&handler).Read(BPrivate::kGroupFile);
|
||||||
|
|
||||||
|
*_result = (status == 1 ? group : NULL);
|
||||||
|
return (status == 1 ? 0 : (status == 0 ? ENOENT : status));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
getgrouplist(const char* user, gid_t baseGroup, gid_t* groupList,
|
||||||
|
int* groupCount)
|
||||||
|
{
|
||||||
|
int maxGroupCount = *groupCount;
|
||||||
|
*groupCount = 0;
|
||||||
|
|
||||||
|
UserGroupEntryHandler handler(user, groupList, maxGroupCount, groupCount);
|
||||||
|
BPrivate::GroupDBReader(&handler).Read(BPrivate::kGroupFile);
|
||||||
|
|
||||||
|
// put in the base group
|
||||||
|
if (*groupCount < maxGroupCount)
|
||||||
|
groupList[*groupCount] = baseGroup;
|
||||||
|
++*groupCount;
|
||||||
|
|
||||||
|
return *groupCount <= maxGroupCount ? *groupCount : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
initgroups(const char* user, gid_t baseGroup)
|
||||||
|
{
|
||||||
|
gid_t groups[NGROUPS_MAX + 1];
|
||||||
|
int groupCount = NGROUPS_MAX + 1;
|
||||||
|
if (getgrouplist(user, baseGroup, groups, &groupCount) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return setgroups(groupCount, groups);
|
||||||
|
}
|
||||||
@@ -1,139 +0,0 @@
|
|||||||
/*
|
|
||||||
** Copyright 2002-2004, Axel Dörfler, [email protected]. All rights reserved.
|
|
||||||
** Copyright 2004, Eli Green, [email protected]. All rights reserved.
|
|
||||||
** Distributed under the terms of the OpenBeOS License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
** All the functions in this file return the "baron" user.
|
|
||||||
** baron is uid 0, gid 0. the pw_name field is set to either
|
|
||||||
** "baron" or the value of the USER environment variable.
|
|
||||||
**
|
|
||||||
** This is done to be fully compatible with BeOS R5. /etc/passwd
|
|
||||||
** is not consulted.
|
|
||||||
**
|
|
||||||
** One difference:
|
|
||||||
** R5's getpwnam always returns NULL, but the implementation in this
|
|
||||||
** file returns passwd struct for baron if the name argument is set to
|
|
||||||
** the USER environment variable, or "baron" if USER is unset.
|
|
||||||
**
|
|
||||||
** The reentrant versions do not exist under BeOS R5.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include <pwd.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
|
|
||||||
static char _pw_first = 1;
|
|
||||||
static struct passwd _pw_struct;
|
|
||||||
|
|
||||||
|
|
||||||
static char *
|
|
||||||
get_user_name()
|
|
||||||
{
|
|
||||||
char *user = getenv("USER");
|
|
||||||
if (user != NULL)
|
|
||||||
return user;
|
|
||||||
|
|
||||||
return "baron";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
getbaron(struct passwd *pw)
|
|
||||||
{
|
|
||||||
pw->pw_name = get_user_name();
|
|
||||||
pw->pw_passwd = "";
|
|
||||||
pw->pw_uid = 0;
|
|
||||||
pw->pw_gid = 0;
|
|
||||||
pw->pw_dir = "/boot/home";
|
|
||||||
pw->pw_shell = "/bin/sh";
|
|
||||||
pw->pw_gecos = "system";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct passwd *
|
|
||||||
getpwent(void)
|
|
||||||
{
|
|
||||||
if (!_pw_first)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
_pw_first = 0;
|
|
||||||
|
|
||||||
getbaron(&_pw_struct);
|
|
||||||
return &_pw_struct;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
setpwent(void)
|
|
||||||
{
|
|
||||||
_pw_first = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
endpwent(void)
|
|
||||||
{
|
|
||||||
_pw_first = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct passwd *
|
|
||||||
getpwnam(const char *name)
|
|
||||||
{
|
|
||||||
if (!strcmp(name, get_user_name())) {
|
|
||||||
getbaron(&_pw_struct);
|
|
||||||
return &_pw_struct;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
getpwnam_r(const char *name, struct passwd *passwd, char *buffer,
|
|
||||||
size_t bufferSize, struct passwd **_result)
|
|
||||||
{
|
|
||||||
if (strcmp(name, get_user_name())) {
|
|
||||||
*_result = NULL;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
getbaron(passwd);
|
|
||||||
*_result = passwd;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct passwd *
|
|
||||||
getpwuid(uid_t uid)
|
|
||||||
{
|
|
||||||
if (uid != 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
getbaron(&_pw_struct);
|
|
||||||
return &_pw_struct;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
getpwuid_r(uid_t uid, struct passwd *passwd, char *buffer,
|
|
||||||
size_t bufferSize, struct passwd **_result)
|
|
||||||
{
|
|
||||||
if (uid != 0) {
|
|
||||||
*_result = NULL;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
getbaron(passwd);
|
|
||||||
*_result = passwd;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void __init_pwd_backend(void)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -0,0 +1,194 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008, Ingo Weinhold, [email protected]. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <pwd.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#include <OS.h>
|
||||||
|
|
||||||
|
#include <libroot_private.h>
|
||||||
|
|
||||||
|
#include "user_group_common.h"
|
||||||
|
|
||||||
|
|
||||||
|
using BPrivate::PasswdDB;
|
||||||
|
using BPrivate::PasswdDBReader;
|
||||||
|
using BPrivate::PasswdEntryHandler;
|
||||||
|
using BPrivate::UserGroupLocker;
|
||||||
|
|
||||||
|
static PasswdDB* sPasswdDB = NULL;
|
||||||
|
|
||||||
|
static struct passwd sPasswdBuffer;
|
||||||
|
static char sPasswdStringBuffer[MAX_PASSWD_BUFFER_SIZE];
|
||||||
|
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class PasswdEntryFindHandler : public PasswdEntryHandler {
|
||||||
|
public:
|
||||||
|
PasswdEntryFindHandler(const char* name, uid_t uid,
|
||||||
|
passwd* entry, char* buffer, size_t bufferSize)
|
||||||
|
:
|
||||||
|
fName(name),
|
||||||
|
fUID(uid),
|
||||||
|
fEntry(entry),
|
||||||
|
fBuffer(buffer),
|
||||||
|
fBufferSize(bufferSize)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual status_t HandleEntry(const char* name, const char* password,
|
||||||
|
uid_t uid, gid_t gid, const char* home, const char* shell,
|
||||||
|
const char* realName)
|
||||||
|
{
|
||||||
|
if (fName != NULL ? strcmp(fName, name) != 0 : fUID != uid)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// found
|
||||||
|
status_t error = BPrivate::copy_passwd_to_buffer(name, password, uid,
|
||||||
|
gid, home, shell, realName, fEntry, fBuffer, fBufferSize);
|
||||||
|
return error == B_OK ? 1 : error;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char* fName;
|
||||||
|
uid_t fUID;
|
||||||
|
passwd* fEntry;
|
||||||
|
char* fBuffer;
|
||||||
|
size_t fBufferSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // empty namespace
|
||||||
|
|
||||||
|
|
||||||
|
static PasswdDB*
|
||||||
|
init_passwd_db()
|
||||||
|
{
|
||||||
|
if (sPasswdDB != NULL)
|
||||||
|
return sPasswdDB;
|
||||||
|
|
||||||
|
sPasswdDB = new(nothrow) PasswdDB;
|
||||||
|
if (sPasswdDB == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (sPasswdDB->Init() != B_OK) {
|
||||||
|
delete sPasswdDB;
|
||||||
|
sPasswdDB = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sPasswdDB;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
struct passwd*
|
||||||
|
getpwent(void)
|
||||||
|
{
|
||||||
|
struct passwd* result = NULL;
|
||||||
|
int status = getpwent_r(&sPasswdBuffer, sPasswdStringBuffer,
|
||||||
|
sizeof(sPasswdStringBuffer), &result);
|
||||||
|
if (status != 0)
|
||||||
|
errno = status;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
getpwent_r(struct passwd* passwd, char* buffer, size_t bufferSize,
|
||||||
|
struct passwd** _result)
|
||||||
|
{
|
||||||
|
UserGroupLocker _;
|
||||||
|
|
||||||
|
int status = B_NO_MEMORY;
|
||||||
|
|
||||||
|
*_result = NULL;
|
||||||
|
|
||||||
|
if (PasswdDB* db = init_passwd_db()) {
|
||||||
|
status = db->GetNextEntry(passwd, buffer, bufferSize);
|
||||||
|
if (status == 0)
|
||||||
|
*_result = passwd;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
setpwent(void)
|
||||||
|
{
|
||||||
|
UserGroupLocker _;
|
||||||
|
|
||||||
|
if (PasswdDB* db = init_passwd_db())
|
||||||
|
db->RewindEntries();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
endpwent(void)
|
||||||
|
{
|
||||||
|
UserGroupLocker locker;
|
||||||
|
|
||||||
|
PasswdDB* db = sPasswdDB;
|
||||||
|
sPasswdDB = NULL;
|
||||||
|
|
||||||
|
locker.Unlock();
|
||||||
|
|
||||||
|
delete db;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct passwd *
|
||||||
|
getpwnam(const char *name)
|
||||||
|
{
|
||||||
|
struct passwd* result = NULL;
|
||||||
|
int status = getpwnam_r(name, &sPasswdBuffer, sPasswdStringBuffer,
|
||||||
|
sizeof(sPasswdStringBuffer), &result);
|
||||||
|
if (status != 0)
|
||||||
|
errno = status;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
getpwnam_r(const char *name, struct passwd *passwd, char *buffer,
|
||||||
|
size_t bufferSize, struct passwd **_result)
|
||||||
|
{
|
||||||
|
PasswdEntryFindHandler handler(name, 0, passwd, buffer, bufferSize);
|
||||||
|
status_t status = PasswdDBReader(&handler).Read(BPrivate::kPasswdFile);
|
||||||
|
|
||||||
|
*_result = (status == 1 ? passwd : NULL);
|
||||||
|
return (status == 1 ? 0 : (status == 0 ? ENOENT : status));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct passwd *
|
||||||
|
getpwuid(uid_t uid)
|
||||||
|
{
|
||||||
|
struct passwd* result = NULL;
|
||||||
|
int status = getpwuid_r(uid, &sPasswdBuffer, sPasswdStringBuffer,
|
||||||
|
sizeof(sPasswdStringBuffer), &result);
|
||||||
|
if (status != 0)
|
||||||
|
errno = status;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
getpwuid_r(uid_t uid, struct passwd *passwd, char *buffer,
|
||||||
|
size_t bufferSize, struct passwd **_result)
|
||||||
|
{
|
||||||
|
PasswdEntryFindHandler handler(NULL, uid, passwd, buffer, bufferSize);
|
||||||
|
status_t status = PasswdDBReader(&handler).Read(BPrivate::kPasswdFile);
|
||||||
|
|
||||||
|
*_result = (status == 1 ? passwd : NULL);
|
||||||
|
return (status == 1 ? 0 : (status == 0 ? ENOENT : status));
|
||||||
|
}
|
||||||
@@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
#include <SupportDefs.h>
|
#include <SupportDefs.h>
|
||||||
|
|
||||||
|
#include <libroot_private.h>
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
getdtablesize(void)
|
getdtablesize(void)
|
||||||
@@ -52,6 +54,10 @@ sysconf(int name)
|
|||||||
return TZNAME_MAX;
|
return TZNAME_MAX;
|
||||||
case _SC_VERSION:
|
case _SC_VERSION:
|
||||||
return _POSIX_VERSION;
|
return _POSIX_VERSION;
|
||||||
|
case _SC_GETGR_R_SIZE_MAX:
|
||||||
|
return MAX_GROUP_BUFFER_SIZE;
|
||||||
|
case _SC_GETPW_R_SIZE_MAX:
|
||||||
|
return MAX_PASSWD_BUFFER_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <libroot_private.h>
|
||||||
#include <syscalls.h>
|
#include <syscalls.h>
|
||||||
#include <user_runtime.h>
|
#include <user_runtime.h>
|
||||||
|
|
||||||
@@ -156,6 +157,7 @@ fork(void)
|
|||||||
__main_thread_id = find_thread(NULL);
|
__main_thread_id = find_thread(NULL);
|
||||||
__init_fork();
|
__init_fork();
|
||||||
__gRuntimeLoader->reinit_after_fork();
|
__gRuntimeLoader->reinit_after_fork();
|
||||||
|
__reinit_pwd_backend_after_fork();
|
||||||
|
|
||||||
call_fork_hooks(sChildHooks);
|
call_fork_hooks(sChildHooks);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -31,131 +31,6 @@ set_errno_if_necessary(const T& result)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class FileLineReader {
|
|
||||||
public:
|
|
||||||
FileLineReader(int fd)
|
|
||||||
: fFD(fd),
|
|
||||||
fSize(0),
|
|
||||||
fOffset(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
char* NextLine()
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
*eol = '\0';
|
|
||||||
fOffset = eol + 1 - fBuffer;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* NextNonEmptyLine()
|
|
||||||
{
|
|
||||||
while (char* line = NextLine()) {
|
|
||||||
while (*line != '\0' && isspace(*line))
|
|
||||||
line++;
|
|
||||||
|
|
||||||
if (*line != '\0' && *line != '#')
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void _ReadBuffer()
|
|
||||||
{
|
|
||||||
// catch special cases: full buffer or already done with the file
|
|
||||||
if (fSize == LINE_MAX || fFD < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// move buffered bytes to the beginning of the buffer
|
|
||||||
int leftBytes = 0;
|
|
||||||
if (fOffset < fSize) {
|
|
||||||
leftBytes = fSize - fOffset;
|
|
||||||
memmove(fBuffer, fBuffer + fOffset, leftBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
fOffset = 0;
|
|
||||||
fSize = leftBytes;
|
|
||||||
|
|
||||||
// read
|
|
||||||
ssize_t bytesRead = read(fFD, fBuffer + leftBytes,
|
|
||||||
LINE_MAX - leftBytes);
|
|
||||||
if (bytesRead > 0)
|
|
||||||
fSize += bytesRead;
|
|
||||||
else
|
|
||||||
fFD = -1;
|
|
||||||
|
|
||||||
// null-terminate
|
|
||||||
fBuffer[fSize] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
int fFD;
|
|
||||||
char fBuffer[LINE_MAX + 1];
|
|
||||||
int fSize;
|
|
||||||
int fOffset;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class Tokenizer {
|
|
||||||
public:
|
|
||||||
Tokenizer(char* string)
|
|
||||||
: fString(string)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
char* NextToken(char separator)
|
|
||||||
{
|
|
||||||
if (fString == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
char* token = fString;
|
|
||||||
fString = strchr(fString, separator);
|
|
||||||
if (fString != NULL) {
|
|
||||||
*fString = '\0';
|
|
||||||
fString++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* NextTrimmedToken(char separator)
|
|
||||||
{
|
|
||||||
char* token = NextToken(separator);
|
|
||||||
if (token == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
// skip spaces at the beginning
|
|
||||||
while (*token != '\0' && isspace(*token))
|
|
||||||
token++;
|
|
||||||
|
|
||||||
// cut off spaces at the end
|
|
||||||
char* end = token + strlen(token);
|
|
||||||
while (end != token && isspace(end[-1]))
|
|
||||||
end--;
|
|
||||||
*end = '\0';
|
|
||||||
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
char* fString;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
@@ -229,51 +104,6 @@ setreuid(uid_t ruid, uid_t euid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
getgrouplist(const char* user, gid_t baseGroup, gid_t* groupList,
|
|
||||||
int* groupCount)
|
|
||||||
{
|
|
||||||
int maxGroupCount = *groupCount;
|
|
||||||
*groupCount = 0;
|
|
||||||
|
|
||||||
// read group file
|
|
||||||
int fd = open("/etc/group", O_RDONLY);
|
|
||||||
FileLineReader reader(fd);
|
|
||||||
|
|
||||||
while (char* line = reader.NextNonEmptyLine()) {
|
|
||||||
Tokenizer lineTokenizer(line);
|
|
||||||
lineTokenizer.NextTrimmedToken(':'); // group name
|
|
||||||
lineTokenizer.NextTrimmedToken(':'); // group password
|
|
||||||
char* groupID = lineTokenizer.NextTrimmedToken(':');
|
|
||||||
|
|
||||||
if (groupID == NULL || !isdigit(*groupID))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
gid_t gid = atol(groupID);
|
|
||||||
if (gid == baseGroup)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
while (char* groupUser = lineTokenizer.NextTrimmedToken(',')) {
|
|
||||||
if (*groupUser != '\0' && strcmp(groupUser, user) == 0) {
|
|
||||||
if (*groupCount < maxGroupCount)
|
|
||||||
groupList[*groupCount] = gid;
|
|
||||||
++*groupCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fd >= 0)
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
// put in the base group
|
|
||||||
if (*groupCount < maxGroupCount)
|
|
||||||
groupList[*groupCount] = baseGroup;
|
|
||||||
++*groupCount;
|
|
||||||
|
|
||||||
return *groupCount <= maxGroupCount ? *groupCount : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
getgroups(int groupCount, gid_t groupList[])
|
getgroups(int groupCount, gid_t groupList[])
|
||||||
{
|
{
|
||||||
@@ -281,20 +111,10 @@ getgroups(int groupCount, gid_t groupList[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
initgroups(const char* user, gid_t baseGroup)
|
|
||||||
{
|
|
||||||
gid_t groups[NGROUPS_MAX + 1];
|
|
||||||
int groupCount = NGROUPS_MAX + 1;
|
|
||||||
if (getgrouplist(user, baseGroup, groups, &groupCount) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return setgroups(groupCount, groups);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
setgroups(int groupCount, const gid_t* groupList)
|
setgroups(int groupCount, const gid_t* groupList)
|
||||||
{
|
{
|
||||||
return set_errno_if_necessary(_kern_setgroups(groupCount, groupList));
|
return set_errno_if_necessary(_kern_setgroups(groupCount, groupList));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: getgrouplist() and initgroups() are implemented in grp.cpp.
|
||||||
|
|||||||
@@ -0,0 +1,721 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008, Ingo Weinhold, [email protected]. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "user_group_common.h"
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#include <libroot_lock.h>
|
||||||
|
#include <libroot_private.h>
|
||||||
|
|
||||||
|
|
||||||
|
using BPrivate::FileLineReader;
|
||||||
|
using BPrivate::Tokenizer;
|
||||||
|
using BPrivate::FileDBEntry;
|
||||||
|
using BPrivate::FileDBReader;
|
||||||
|
using BPrivate::FileDB;
|
||||||
|
using BPrivate::PasswdDBEntry;
|
||||||
|
using BPrivate::PasswdEntryHandler;
|
||||||
|
using BPrivate::PasswdDBReader;
|
||||||
|
using BPrivate::PasswdDB;
|
||||||
|
using BPrivate::GroupDBEntry;
|
||||||
|
using BPrivate::GroupEntryHandler;
|
||||||
|
using BPrivate::GroupDBReader;
|
||||||
|
using BPrivate::GroupDB;
|
||||||
|
|
||||||
|
|
||||||
|
const char* BPrivate::kPasswdFile = "/etc/passwd";
|
||||||
|
const char* BPrivate::kGroupFile = "/etc/group";
|
||||||
|
|
||||||
|
static benaphore sUserGroupLock;
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BPrivate::user_group_lock()
|
||||||
|
{
|
||||||
|
return benaphore_lock(&sUserGroupLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BPrivate::user_group_unlock()
|
||||||
|
{
|
||||||
|
return benaphore_unlock(&sUserGroupLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class FileLineReader {
|
||||||
|
public:
|
||||||
|
FileLineReader(int fd)
|
||||||
|
: fFD(fd),
|
||||||
|
fSize(0),
|
||||||
|
fOffset(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
char* NextLine()
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
*eol = '\0';
|
||||||
|
fOffset = eol + 1 - fBuffer;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* NextNonEmptyLine()
|
||||||
|
{
|
||||||
|
while (char* line = NextLine()) {
|
||||||
|
while (*line != '\0' && isspace(*line))
|
||||||
|
line++;
|
||||||
|
|
||||||
|
if (*line != '\0' && *line != '#')
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _ReadBuffer()
|
||||||
|
{
|
||||||
|
// catch special cases: full buffer or already done with the file
|
||||||
|
if (fSize == LINE_MAX || fFD < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// move buffered bytes to the beginning of the buffer
|
||||||
|
int leftBytes = 0;
|
||||||
|
if (fOffset < fSize) {
|
||||||
|
leftBytes = fSize - fOffset;
|
||||||
|
memmove(fBuffer, fBuffer + fOffset, leftBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
fOffset = 0;
|
||||||
|
fSize = leftBytes;
|
||||||
|
|
||||||
|
// read
|
||||||
|
ssize_t bytesRead = read(fFD, fBuffer + leftBytes,
|
||||||
|
LINE_MAX - leftBytes);
|
||||||
|
if (bytesRead > 0)
|
||||||
|
fSize += bytesRead;
|
||||||
|
else
|
||||||
|
fFD = -1;
|
||||||
|
|
||||||
|
// null-terminate
|
||||||
|
fBuffer[fSize] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int fFD;
|
||||||
|
char fBuffer[LINE_MAX + 1];
|
||||||
|
int fSize;
|
||||||
|
int fOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Tokenizer {
|
||||||
|
public:
|
||||||
|
Tokenizer(char* string)
|
||||||
|
: fString(string)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
char* NextToken(char separator)
|
||||||
|
{
|
||||||
|
if (fString == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
char* token = fString;
|
||||||
|
fString = strchr(fString, separator);
|
||||||
|
if (fString != NULL) {
|
||||||
|
*fString = '\0';
|
||||||
|
fString++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* NextTrimmedToken(char separator)
|
||||||
|
{
|
||||||
|
char* token = NextToken(separator);
|
||||||
|
if (token == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// skip spaces at the beginning
|
||||||
|
while (*token != '\0' && isspace(*token))
|
||||||
|
token++;
|
||||||
|
|
||||||
|
// cut off spaces at the end
|
||||||
|
char* end = token + strlen(token);
|
||||||
|
while (end != token && isspace(end[-1]))
|
||||||
|
end--;
|
||||||
|
*end = '\0';
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
char* fString;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static char*
|
||||||
|
buffer_dup_string(const char* string, char*& buffer, size_t& bufferLen)
|
||||||
|
{
|
||||||
|
if (string == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
size_t size = strlen(string) + 1;
|
||||||
|
if (size > bufferLen)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
strcpy(buffer, string);
|
||||||
|
char* result = buffer;
|
||||||
|
buffer += size;
|
||||||
|
bufferLen -= size;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void*
|
||||||
|
buffer_allocate(size_t size, size_t align, char*& buffer, size_t& bufferSize)
|
||||||
|
{
|
||||||
|
// align padding
|
||||||
|
addr_t pad = align - (((addr_t)buffer - 1) & (align - 1)) - 1;
|
||||||
|
if (pad + size > bufferSize)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
char* result = buffer + pad;
|
||||||
|
buffer = result + size;
|
||||||
|
bufferSize -= pad + size;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #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
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BPrivate::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)
|
||||||
|
{
|
||||||
|
entry->pw_uid = uid;
|
||||||
|
entry->pw_gid = gid;
|
||||||
|
|
||||||
|
entry->pw_name = buffer_dup_string(name, buffer, bufferSize);
|
||||||
|
entry->pw_passwd = buffer_dup_string(password, buffer, bufferSize);
|
||||||
|
entry->pw_dir = buffer_dup_string(home, buffer, bufferSize);
|
||||||
|
entry->pw_shell = buffer_dup_string(shell, buffer, bufferSize);
|
||||||
|
entry->pw_gecos = buffer_dup_string(realName, buffer, bufferSize);
|
||||||
|
|
||||||
|
if (entry->pw_name && entry->pw_passwd && entry->pw_dir
|
||||||
|
&& entry->pw_shell && entry->pw_gecos) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - PasswdDBEntry
|
||||||
|
|
||||||
|
|
||||||
|
PasswdDBEntry::PasswdDBEntry()
|
||||||
|
: FileDBEntry(),
|
||||||
|
fPassword(NULL),
|
||||||
|
fHome(NULL),
|
||||||
|
fShell(NULL),
|
||||||
|
fRealName(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PasswdDBEntry::~PasswdDBEntry()
|
||||||
|
{
|
||||||
|
free(fName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
PasswdDBEntry::Init(const char* name, const char* password, uid_t uid,
|
||||||
|
gid_t gid, const char* home, const char* shell, const char* realName)
|
||||||
|
{
|
||||||
|
size_t bufferSize = strlen(name) + 1
|
||||||
|
+ strlen(password) + 1
|
||||||
|
+ strlen(home) + 1
|
||||||
|
+ strlen(shell) + 1
|
||||||
|
+ strlen(realName) + 1;
|
||||||
|
|
||||||
|
char* buffer = (char*)malloc(bufferSize);
|
||||||
|
if (buffer == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
fID = uid;
|
||||||
|
fGID = gid;
|
||||||
|
fName = buffer_dup_string(name, buffer, bufferSize);
|
||||||
|
fPassword = buffer_dup_string(password, buffer, bufferSize);
|
||||||
|
fHome = buffer_dup_string(home, buffer, bufferSize);
|
||||||
|
fShell = buffer_dup_string(shell, buffer, bufferSize);
|
||||||
|
fRealName = buffer_dup_string(realName, buffer, bufferSize);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
PasswdDBEntry::CopyToBuffer(void* entryBuffer, char* buffer, size_t bufferSize)
|
||||||
|
{
|
||||||
|
return copy_passwd_to_buffer(fName, fPassword, fID, fGID, fHome, fShell,
|
||||||
|
fRealName, (passwd*)entryBuffer, buffer, bufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - PasswdEntryHandler
|
||||||
|
|
||||||
|
|
||||||
|
PasswdEntryHandler::~PasswdEntryHandler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - PasswdDBReader
|
||||||
|
|
||||||
|
|
||||||
|
PasswdDBReader::PasswdDBReader(PasswdEntryHandler* handler)
|
||||||
|
: fHandler(handler)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
PasswdDBReader::ParseEntryLine(Tokenizer& tokenizer)
|
||||||
|
{
|
||||||
|
char* name = tokenizer.NextTrimmedToken(':');
|
||||||
|
char* password = tokenizer.NextTrimmedToken(':');
|
||||||
|
char* userID = tokenizer.NextTrimmedToken(':');
|
||||||
|
char* groupID = tokenizer.NextTrimmedToken(':');
|
||||||
|
char* realName = tokenizer.NextTrimmedToken(':');
|
||||||
|
char* home = tokenizer.NextTrimmedToken(':');
|
||||||
|
char* shell = tokenizer.NextTrimmedToken(':');
|
||||||
|
|
||||||
|
// skip if invalid
|
||||||
|
size_t nameLen;
|
||||||
|
if (shell == NULL || (nameLen = strlen(name)) == 0
|
||||||
|
|| !isdigit(*userID) || !isdigit(*groupID)
|
||||||
|
|| nameLen >= MAX_PASSWD_NAME_LEN
|
||||||
|
|| strlen(password) >= MAX_PASSWD_PASSWORD_LEN
|
||||||
|
|| strlen(realName) >= MAX_PASSWD_REAL_NAME_LEN
|
||||||
|
|| strlen(home) >= MAX_PASSWD_HOME_DIR_LEN
|
||||||
|
|| strlen(shell) >= MAX_PASSWD_SHELL_LEN) {
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
gid_t uid = atoi(userID);
|
||||||
|
gid_t 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(nothrow) PasswdDBEntry();
|
||||||
|
if (entry == NULL || !entry->Init(name, password, uid, gid, home, shell,
|
||||||
|
realName)) {
|
||||||
|
delete entry;
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddEntry(entry);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - passwd support
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BPrivate::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)
|
||||||
|
{
|
||||||
|
entry->gr_gid = gid;
|
||||||
|
|
||||||
|
// allocate member array (do that first for alignment reasons)
|
||||||
|
entry->gr_mem = (char**)buffer_allocate(sizeof(char*) * (memberCount + 1),
|
||||||
|
sizeof(char*), buffer, bufferSize);
|
||||||
|
if (entry->gr_mem == NULL)
|
||||||
|
return ERANGE;
|
||||||
|
|
||||||
|
// copy name and password
|
||||||
|
entry->gr_name = buffer_dup_string(name, buffer, bufferSize);
|
||||||
|
entry->gr_passwd = buffer_dup_string(password, buffer, bufferSize);
|
||||||
|
if (entry->gr_name == NULL || entry->gr_passwd == NULL)
|
||||||
|
return ERANGE;
|
||||||
|
|
||||||
|
// copy member array
|
||||||
|
for (int i = 0; i < memberCount; i++) {
|
||||||
|
entry->gr_mem[i] = buffer_dup_string(members[i], buffer, bufferSize);
|
||||||
|
if (entry->gr_mem[i] == NULL)
|
||||||
|
return ERANGE;
|
||||||
|
}
|
||||||
|
entry->gr_mem[memberCount] = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - GroupDBEntry
|
||||||
|
|
||||||
|
|
||||||
|
GroupDBEntry::GroupDBEntry()
|
||||||
|
: FileDBEntry(),
|
||||||
|
fPassword(NULL),
|
||||||
|
fMembers(NULL),
|
||||||
|
fMemberCount(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GroupDBEntry::~GroupDBEntry()
|
||||||
|
{
|
||||||
|
free(fMembers);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
GroupDBEntry::Init(const char* name, const char* password, gid_t gid,
|
||||||
|
const char* const* members, int memberCount)
|
||||||
|
{
|
||||||
|
size_t bufferSize = sizeof(char*) * (memberCount + 1)
|
||||||
|
+ strlen(name) + 1
|
||||||
|
+ strlen(password) + 1;
|
||||||
|
|
||||||
|
for (int i = 0; i < memberCount; i++)
|
||||||
|
bufferSize += strlen(members[i]) + 1;
|
||||||
|
|
||||||
|
char* buffer = (char*)malloc(bufferSize);
|
||||||
|
if (buffer == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// allocate member array first (for alignment reasons)
|
||||||
|
fMembers = (char**)buffer_allocate(sizeof(char*) * (memberCount + 1),
|
||||||
|
sizeof(char*), buffer, bufferSize);
|
||||||
|
|
||||||
|
fID = gid;
|
||||||
|
fName = buffer_dup_string(name, buffer, bufferSize);
|
||||||
|
fPassword = buffer_dup_string(password, buffer, bufferSize);
|
||||||
|
|
||||||
|
// copy members
|
||||||
|
for (int i = 0; i < memberCount; i++)
|
||||||
|
fMembers[i] = buffer_dup_string(members[i], buffer, bufferSize);
|
||||||
|
fMembers[memberCount] = NULL;
|
||||||
|
fMemberCount = memberCount;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
GroupDBEntry::CopyToBuffer(void* entryBuffer, char* buffer, size_t bufferSize)
|
||||||
|
{
|
||||||
|
return copy_group_to_buffer(fName, fPassword, fID, fMembers, fMemberCount,
|
||||||
|
(group*)entryBuffer, buffer, bufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - GroupEntryHandler
|
||||||
|
|
||||||
|
|
||||||
|
GroupEntryHandler::~GroupEntryHandler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - GroupDBReader
|
||||||
|
|
||||||
|
|
||||||
|
GroupDBReader::GroupDBReader(GroupEntryHandler* handler)
|
||||||
|
: fHandler(handler)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
GroupDBReader::ParseEntryLine(Tokenizer& tokenizer)
|
||||||
|
{
|
||||||
|
char* name = tokenizer.NextTrimmedToken(':');
|
||||||
|
char* password = tokenizer.NextTrimmedToken(':');
|
||||||
|
char* groupID = tokenizer.NextTrimmedToken(':');
|
||||||
|
|
||||||
|
// skip if invalid
|
||||||
|
size_t nameLen;
|
||||||
|
if (groupID == NULL || (nameLen = strlen(name)) == 0 || !isdigit(*groupID)
|
||||||
|
|| nameLen >= MAX_GROUP_NAME_LEN
|
||||||
|
|| strlen(password) >= MAX_GROUP_PASSWORD_LEN) {
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
gid_t gid = atol(groupID);
|
||||||
|
|
||||||
|
const char* members[MAX_GROUP_MEMBER_COUNT];
|
||||||
|
int memberCount = 0;
|
||||||
|
|
||||||
|
while (char* groupUser = tokenizer.NextTrimmedToken(',')) {
|
||||||
|
// ignore invalid members
|
||||||
|
if (*groupUser == '\0' || strlen(groupUser) >= MAX_PASSWD_NAME_LEN)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
members[memberCount++] = groupUser;
|
||||||
|
|
||||||
|
// ignore excess members
|
||||||
|
if (memberCount == MAX_GROUP_MEMBER_COUNT)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fHandler->HandleEntry(name, password, gid, members, memberCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - GroupDB
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
GroupDB::Init()
|
||||||
|
{
|
||||||
|
return GroupDBReader(this).Read(kGroupFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
GroupDB::HandleEntry(const char* name, const char* password, gid_t gid,
|
||||||
|
const char* const* members, int memberCount)
|
||||||
|
{
|
||||||
|
GroupDBEntry* entry = new(nothrow) GroupDBEntry();
|
||||||
|
if (entry == NULL || !entry->Init(name, password, gid, members,
|
||||||
|
memberCount)) {
|
||||||
|
delete entry;
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddEntry(entry);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
__init_pwd_backend(void)
|
||||||
|
{
|
||||||
|
benaphore_init(&sUserGroupLock, "user group");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
__reinit_pwd_backend_after_fork(void)
|
||||||
|
{
|
||||||
|
benaphore_init(&sUserGroupLock, "user group");
|
||||||
|
}
|
||||||
@@ -0,0 +1,239 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
* 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 <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