diff --git a/build/jam/images/definitions/minimum b/build/jam/images/definitions/minimum index cee093ef9f..9ce865a152 100644 --- a/build/jam/images/definitions/minimum +++ b/build/jam/images/definitions/minimum @@ -41,6 +41,7 @@ SYSTEM_APPS = [ FFilterByBuildFeatures CharacterMap Debugger DeskCalc Devices DiskProbe DiskUsage DriveSetup Expander + Login NetworkStatus ProcessController ShowImage StyledEdit @@ -277,6 +278,10 @@ SEARCH on $(networkSettingsFiles) = [ FDirName $(HAIKU_TOP) data settings network ] ; AddFilesToHaikuImage system settings network : $(networkSettingsFiles) ; +local userLaunchScripts = user ; +SEARCH on $(userLaunchScripts) = [ FDirName $(HAIKU_TOP) data launch ] ; +AddFilesToHaikuImage home config non-packaged data launch : $(userLaunchScripts) ; + # fresh install indicator file for the post install scripts SEARCH on fresh_install = [ FDirName $(HAIKU_TOP) data system settings ] ; diff --git a/data/launch/system b/data/launch/system index 43b1b253c2..e95676d5c2 100644 --- a/data/launch/system +++ b/data/launch/system @@ -71,13 +71,7 @@ service x-vnd.Haiku-power_daemon { legacy } -# The following will be moved into the user launch data -service x-vnd.Be-TRAK { - launch /system/Tracker - legacy -} - -service x-vnd.Be-TSKB { - launch /system/Deskbar +job x-vnd.Haiku-Login { + launch /system/apps/Login legacy } diff --git a/data/launch/user b/data/launch/user new file mode 100644 index 0000000000..da2117848d --- /dev/null +++ b/data/launch/user @@ -0,0 +1,9 @@ +service x-vnd.Be-TRAK { + launch /system/Tracker + legacy +} + +service x-vnd.Be-TSKB { + launch /system/Deskbar + legacy +} diff --git a/headers/private/app/LaunchDaemonDefs.h b/headers/private/app/LaunchDaemonDefs.h index 439266c97b..8f7cab4d52 100644 --- a/headers/private/app/LaunchDaemonDefs.h +++ b/headers/private/app/LaunchDaemonDefs.h @@ -24,7 +24,9 @@ namespace BPrivate { // message constants enum { - B_GET_LAUNCH_DATA = 'lncd', + B_GET_LAUNCH_DATA = 'lnda', + B_LAUNCH_SESSION = 'lnse', + B_REGISTER_LAUNCH_SESSION = 'lnrs', }; diff --git a/headers/private/app/LaunchRoster.h b/headers/private/app/LaunchRoster.h index 3fd3b17569..7e3320e1f3 100644 --- a/headers/private/app/LaunchRoster.h +++ b/headers/private/app/LaunchRoster.h @@ -22,7 +22,14 @@ public: port_id GetPort(const char* signature, const char* name); + status_t StartSession(const char* login, + const char* password); + + class Private; + private: + friend class Private; + void _InitMessenger(); private: diff --git a/headers/private/app/LaunchRosterPrivate.h b/headers/private/app/LaunchRosterPrivate.h new file mode 100644 index 0000000000..9dce48aa7d --- /dev/null +++ b/headers/private/app/LaunchRosterPrivate.h @@ -0,0 +1,24 @@ +/* + * Copyright 2015 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _LAUNCH_ROSTER_PRIVATE_H +#define _LAUNCH_ROSTER_PRIVATE_H + + +#include + + +class BLaunchRoster::Private { +public: + Private(BLaunchRoster* roster); + Private(BLaunchRoster& roster); + + status_t RegisterSession(const BMessenger& target); + +private: + BLaunchRoster* fRoster; +}; + + +#endif // _LAUNCH_ROSTER_PRIVATE_H diff --git a/src/apps/login/LoginApp.cpp b/src/apps/login/LoginApp.cpp index ade6df8405..30c5d7767b 100644 --- a/src/apps/login/LoginApp.cpp +++ b/src/apps/login/LoginApp.cpp @@ -16,15 +16,16 @@ #include #include +#include +#include +#include + +#include "multiuser_utils.h" + #include "LoginApp.h" #include "LoginWindow.h" #include "DesktopWindow.h" -#ifdef __HAIKU__ -#include -#include -#include "multiuser_utils.h" -#endif #undef B_TRANSLATION_CONTEXT #define B_TRANSLATION_CONTEXT "Login App" @@ -80,11 +81,9 @@ LoginApp::MessageReceived(BMessage *message) switch (message->what) { case kAttemptLogin: - message->PrintToStream(); TryLogin(message); // TODO break; -#ifdef __HAIKU__ case kHaltAction: reboot = false; // FALLTHROUGH @@ -111,9 +110,9 @@ LoginApp::MessageReceived(BMessage *message) alert->Go(); break; } -#endif - default: - BApplication::MessageReceived(message); + + default: + BApplication::MessageReceived(message); } } @@ -145,37 +144,31 @@ LoginApp::ArgvReceived(int32 argc, char **argv) void LoginApp::TryLogin(BMessage *message) { - status_t err; + status_t status = B_BAD_VALUE; + const char *login; const char *password; BMessage reply(kLoginBad); if (message->FindString("login", &login) == B_OK) { if (message->FindString("password", &password) < B_OK) password = NULL; - err = ValidateLogin(login, password); - printf(B_TRANSLATE_COMMENT("ValidateLogin: %s\n", - "A message returned from the ValidateLogin function. " - "It can be \"B_OK\"."), strerror(err)); - if (err == B_OK) { - reply.what = kLoginOk; - message->SendReply(&reply); - if (password == NULL) - return; + if (password != NULL) { + status = StartUserSession(login, password); + if (status == B_OK) + Quit(); + } else + status = ValidateLogin(login, password); - // start a session - //kSetProgress - StartUserSession(login); - } else { - reply.AddInt32("error", err); - message->SendReply(&reply); - return; - } + fprintf(stderr, "ValidateLogin: %s\n", strerror(status)); + } - } else { - reply.AddInt32("error", EINVAL); + if (status == B_OK) { + reply.what = kLoginOk; + message->SendReply(&reply); + } else { + reply.AddInt32("error", status); message->SendReply(&reply); - return; } } @@ -210,9 +203,12 @@ LoginApp::ValidateLogin(const char *login, const char *password) status_t -LoginApp::StartUserSession(const char *login) +LoginApp::StartUserSession(const char* login, const char* password) { - return B_ERROR; + if (login == NULL || password == NULL) + return B_BAD_VALUE; + + return BLaunchRoster().StartSession(login, password); } diff --git a/src/apps/login/LoginApp.h b/src/apps/login/LoginApp.h index 4619ef159a..588af96db6 100644 --- a/src/apps/login/LoginApp.h +++ b/src/apps/login/LoginApp.h @@ -29,7 +29,7 @@ public: private: void TryLogin(BMessage *message); status_t ValidateLogin(const char *login, const char *password); - status_t StartUserSession(const char *login); + status_t StartUserSession(const char *login, const char *password); int getpty(char *pty, char *tty); DesktopWindow* fDesktopWindow; diff --git a/src/kits/app/LaunchRoster.cpp b/src/kits/app/LaunchRoster.cpp index bdb558c128..4fd0ce72df 100644 --- a/src/kits/app/LaunchRoster.cpp +++ b/src/kits/app/LaunchRoster.cpp @@ -14,6 +14,7 @@ #include #include +#include #include @@ -23,6 +24,45 @@ using namespace BPrivate; const BLaunchRoster* be_launch_roster; +BLaunchRoster::Private::Private(BLaunchRoster* roster) + : + fRoster(roster) +{ +} + + +BLaunchRoster::Private::Private(BLaunchRoster& roster) + : + fRoster(&roster) +{ +} + + +status_t +BLaunchRoster::Private::RegisterSession(const BMessenger& target) +{ + BMessage request(B_REGISTER_LAUNCH_SESSION); + status_t status = request.AddInt32("user", getuid()); + if (status == B_OK) + status = request.AddMessenger("target", target); + if (status != B_OK) + return status; + + // send the request + BMessage result; + status = fRoster->fMessenger.SendMessage(&request, &result); + + // evaluate the reply + if (status == B_OK) + status = result.what; + + return status; +} + + +// #pragma mark - + + BLaunchRoster::BLaunchRoster() { _InitMessenger(); @@ -59,6 +99,8 @@ BLaunchRoster::GetData(const char* signature, BMessage& data) BMessage request(B_GET_LAUNCH_DATA); status_t status = request.AddString("name", signature); + if (status == B_OK) + status = request.AddInt32("user", getuid()); if (status != B_OK) return status; @@ -86,9 +128,8 @@ BLaunchRoster::GetPort(const char* name) port_id BLaunchRoster::GetPort(const char* signature, const char* name) { - BLaunchRoster launchRoster; BMessage data; - status_t status = launchRoster.GetData(signature, data); + status_t status = GetData(signature, data); if (status == B_OK) { BString fieldName; if (name != NULL) @@ -104,6 +145,33 @@ BLaunchRoster::GetPort(const char* signature, const char* name) } +status_t +BLaunchRoster::StartSession(const char* login, const char* password) +{ + if (login == NULL || password == NULL) + return B_BAD_VALUE; + + BMessage request(B_LAUNCH_SESSION); + status_t status = request.AddInt32("user", getuid()); + if (status == B_OK) + status = request.AddString("login", login); + if (status == B_OK) + status = request.AddString("password", password); + if (status != B_OK) + return status; + + // send the request + BMessage result; + status = fMessenger.SendMessage(&request, &result); + + // evaluate the reply + if (status == B_OK) + status = result.what; + + return status; +} + + void BLaunchRoster::_InitMessenger() { diff --git a/src/servers/launch/Jamfile b/src/servers/launch/Jamfile index e0fd5a1c42..df2833cdcf 100644 --- a/src/servers/launch/Jamfile +++ b/src/servers/launch/Jamfile @@ -3,6 +3,8 @@ SubDir HAIKU_TOP src servers launch ; UsePrivateHeaders app package shared storage support ; UsePrivateSystemHeaders ; +UseHeaders [ FDirName $(HAIKU_TOP) src bin multiuser ] ; + Server launch_daemon : LaunchDaemon.cpp @@ -14,7 +16,7 @@ Server launch_daemon InitSharedMemoryDirectoryJob.cpp InitTemporaryDirectoryJob.cpp : - be libshared.a [ TargetLibstdc++ ] + be libshared.a libmultiuser_utils.a [ TargetLibstdc++ ] : LaunchDaemon.rdef ; diff --git a/src/servers/launch/LaunchDaemon.cpp b/src/servers/launch/LaunchDaemon.cpp index 432c8caa2e..c9bf587da7 100644 --- a/src/servers/launch/LaunchDaemon.cpp +++ b/src/servers/launch/LaunchDaemon.cpp @@ -7,6 +7,8 @@ #include #include +#include +#include #include #include #include @@ -23,8 +25,11 @@ #include #include #include +#include #include +#include "multiuser_utils.h" + #include "InitRealTimeClockJob.h" #include "InitSharedMemoryDirectoryJob.h" #include "InitTemporaryDirectoryJob.h" @@ -65,6 +70,21 @@ const static settings_template kSettingsTemplate[] = { typedef std::map PortMap; +class Session { +public: + Session(uid_t user, const BMessenger& target); + + uid_t User() const + { return fUser; } + const BMessenger& Target() const + { return fTarget; } + +private: + uid_t fUser; + BMessenger fTarget; +}; + + class Target : public BJob { public: Target(const char* name); @@ -135,26 +155,30 @@ private: }; -typedef std::map JobMap; - - class JobFinder { public: virtual Job* FindJob(const char* name) const = 0; }; +typedef std::map JobMap; +typedef std::map SessionMap; + + class LaunchDaemon : public BServer, public JobFinder { public: - LaunchDaemon(status_t& error); + LaunchDaemon(bool userMode, status_t& error); virtual ~LaunchDaemon(); virtual Job* FindJob(const char* name) const; + Session* FindSession(uid_t user) const; virtual void ReadyToRun(); virtual void MessageReceived(BMessage* message); private: + uid_t _GetUserID(BMessage* message); + void _ReadPaths(const BStringList& paths); void _ReadEntry(const char* context, BEntry& entry); void _ReadDirectory(const char* context, @@ -166,6 +190,9 @@ private: void _LaunchJobs(); void _AddLaunchJob(Job* job); + status_t _StartSession(const char* login, + const char* password); + void _RetrieveKernelOptions(); void _SetupEnvironment(); void _InitSystem(); @@ -176,9 +203,11 @@ private: private: JobMap fJobs; JobQueue fJobQueue; + SessionMap fSessions; MainWorker* fMainWorker; Target* fInitTarget; bool fSafeMode; + bool fUserMode; }; @@ -508,6 +537,17 @@ Job::Execute() // #pragma mark - +Session::Session(uid_t user, const BMessenger& target) + : + fUser(user), + fTarget(target) +{ +} + + +// #pragma mark - + + Target::Target(const char* name) : BJob(name) @@ -525,12 +565,13 @@ Target::Execute() // #pragma mark - -LaunchDaemon::LaunchDaemon(status_t& error) +LaunchDaemon::LaunchDaemon(bool userMode, status_t& error) : BServer(kLaunchDaemonSignature, NULL, create_port(B_LOOPER_PORT_DEFAULT_CAPACITY, - B_LAUNCH_DAEMON_PORT_NAME), false, &error), - fInitTarget(new Target("init")) + userMode ? "AppPort" : B_LAUNCH_DAEMON_PORT_NAME), false, &error), + fInitTarget(userMode ? NULL : new Target("init")), + fUserMode(userMode) { fMainWorker = new MainWorker(fJobQueue); } @@ -555,23 +596,38 @@ LaunchDaemon::FindJob(const char* name) const } +Session* +LaunchDaemon::FindSession(uid_t user) const +{ + SessionMap::const_iterator found = fSessions.find(user); + if (found != fSessions.end()) + return found->second; + + return NULL; +} + + void LaunchDaemon::ReadyToRun() { _RetrieveKernelOptions(); _SetupEnvironment(); - _InitSystem(); + if (fUserMode) { + BLaunchRoster roster; + BLaunchRoster::Private(roster).RegisterSession(this); + } else + _InitSystem(); BStringList paths; BPathFinder::FindPaths(B_FIND_PATH_DATA_DIRECTORY, kLaunchDirectory, - B_FIND_PATHS_SYSTEM_ONLY, paths); + fUserMode ? B_FIND_PATHS_USER_ONLY : B_FIND_PATHS_SYSTEM_ONLY, paths); _ReadPaths(paths); BPathFinder::FindPaths(B_FIND_PATH_SETTINGS_DIRECTORY, kLaunchDirectory, - B_FIND_PATHS_SYSTEM_ONLY, paths); + fUserMode ? B_FIND_PATHS_USER_ONLY : B_FIND_PATHS_SYSTEM_ONLY, paths); _ReadPaths(paths); - _InitJobs(fInitTarget); + _InitJobs(fUserMode ? NULL : fInitTarget); _LaunchJobs(); } @@ -582,9 +638,19 @@ LaunchDaemon::MessageReceived(BMessage* message) switch (message->what) { case B_GET_LAUNCH_DATA: { + uid_t user = _GetUserID(message); + if (user < 0) + return; + BMessage reply((uint32)B_OK); Job* job = FindJob(get_leaf(message->GetString("name"))); if (job == NULL) { + Session* session = FindSession(user); + if (session != NULL) { + // Forward request to user launch_daemon + if (session->Target().SendMessage(message) == B_OK) + break; + } reply.what = B_NAME_NOT_FOUND; } else { // If the job has not been launched yet, we'll pass on our @@ -610,6 +676,54 @@ LaunchDaemon::MessageReceived(BMessage* message) break; } + case B_LAUNCH_SESSION: + { + uid_t user = _GetUserID(message); + if (user < 0) + break; + + status_t status = B_OK; + const char* login = message->GetString("login"); + const char* password = message->GetString("password"); + if (login == NULL || password == NULL) + status = B_BAD_VALUE; + if (status == B_OK && user != 0) { + // Only the root user can start sessions + status = B_PERMISSION_DENIED; + } + if (status == B_OK) + status = _StartSession(login, password); + + BMessage reply((uint32)status); + message->SendReply(&reply); + break; + } + + case B_REGISTER_LAUNCH_SESSION: + { + uid_t user = _GetUserID(message); + if (user < 0) + break; + + status_t status = B_OK; + + BMessenger target; + if (message->FindMessenger("target", &target) != B_OK) + status = B_BAD_VALUE; + + if (status == B_OK) { + Session* session = new (std::nothrow) Session(user, target); + if (session != NULL) + fSessions.insert(std::pair(user, session)); + else + status = B_NO_MEMORY; + } + + BMessage reply((uint32)status); + message->SendReply(&reply); + break; + } + default: BServer::MessageReceived(message); break; @@ -617,6 +731,18 @@ LaunchDaemon::MessageReceived(BMessage* message) } +uid_t +LaunchDaemon::_GetUserID(BMessage* message) +{ + uid_t user = (uid_t)message->GetInt32("user", -1); + if (user < 0) { + BMessage reply((uint32)B_BAD_VALUE); + message->SendReply(&reply); + } + return user; +} + + void LaunchDaemon::_ReadPaths(const BStringList& paths) { @@ -746,7 +872,7 @@ LaunchDaemon::_InitJobs(Target* target) strerror(status)); } - // Remove jobs that aren't user later on + // Remove jobs that won't be used later on fJobs.erase(remove); } } @@ -772,6 +898,67 @@ LaunchDaemon::_AddLaunchJob(Job* job) } +status_t +LaunchDaemon::_StartSession(const char* login, const char* password) +{ + Unlock(); + + // TODO: enable user/group code and password authentication + // The launch_daemon currently cannot talk to the registrar, though +/* + struct passwd* passwd = getpwnam(login); + if (passwd == NULL) + return B_NAME_NOT_FOUND; + if (strcmp(passwd->pw_name, login) != 0) + return B_NAME_NOT_FOUND; + + // TODO: check for auto-login, and ignore password then + if (!verify_password(passwd, getspnam(login), password)) + return B_PERMISSION_DENIED; + + // Check if there is a user session running already + uid_t user = passwd->pw_uid; + gid_t group = passwd->pw_gid; +*/ + + if (fork() == 0) { + if (setsid() < 0) + exit(EXIT_FAILURE); + +/* +debug_printf("session leader...\n"); + if (initgroups(login, group) == -1) { +debug_printf("1.ouch: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + //endgrent(); + if (setgid(group) != 0) { +debug_printf("2.ouch: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + if (setuid(user) != 0) { +debug_printf("3.ouch: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } +*/ + + // TODO: This leaks the parent application + be_app = NULL; + + // TODO: take over system jobs, and reserve their names + status_t status; + LaunchDaemon* daemon = new LaunchDaemon(true, status); + if (status == B_OK) + daemon->Run(); + + delete daemon; + exit(EXIT_SUCCESS); + } + Lock(); + return B_OK; +} + + void LaunchDaemon::_RetrieveKernelOptions() { @@ -834,16 +1021,8 @@ LaunchDaemon::_IsSafeMode() const int main() { - // TODO: remove this again - close(STDOUT_FILENO); - int fd = open("/dev/dprintf", O_WRONLY); - if (fd != STDOUT_FILENO) - dup2(fd, STDOUT_FILENO); - puts("launch_daemon is alive and kicking."); - fflush(stdout); - status_t status; - LaunchDaemon* daemon = new LaunchDaemon(status); + LaunchDaemon* daemon = new LaunchDaemon(false, status); if (status == B_OK) daemon->Run();