launch_daemon: Basic user session implementation.

* Instead of launching Tracker/Deskbar directly, we now launch the
  Login application.
* This will now start a new session for the selected user (the password
  is currently ignored).
* When a user session is started, the launch_daemon forks, and the
  child then restarts the LaunchDaemon application in user mode.
* It then registers itself with its parent, in order to resolve user
  dependent services.
* Added a user launch file that will cause Tracker, and Deskbar to
  start in the new session.
This commit is contained in:
Axel Dörfler
2015-07-22 20:41:37 +02:00
parent 9cc27f7369
commit ac0a462fba
11 changed files with 353 additions and 67 deletions
+5
View File
@@ -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 = <data!launch>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 <post-install>fresh_install
= [ FDirName $(HAIKU_TOP) data system settings ] ;
+2 -8
View File
@@ -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
}
+9
View File
@@ -0,0 +1,9 @@
service x-vnd.Be-TRAK {
launch /system/Tracker
legacy
}
service x-vnd.Be-TSKB {
launch /system/Deskbar
legacy
}
+3 -1
View File
@@ -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',
};
+7
View File
@@ -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:
+24
View File
@@ -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 <LaunchRoster.h>
class BLaunchRoster::Private {
public:
Private(BLaunchRoster* roster);
Private(BLaunchRoster& roster);
status_t RegisterSession(const BMessenger& target);
private:
BLaunchRoster* fRoster;
};
#endif // _LAUNCH_ROSTER_PRIVATE_H
+29 -33
View File
@@ -16,15 +16,16 @@
#include <unistd.h>
#include <pwd.h>
#include <LaunchRoster.h>
#include <RosterPrivate.h>
#include <shadow.h>
#include "multiuser_utils.h"
#include "LoginApp.h"
#include "LoginWindow.h"
#include "DesktopWindow.h"
#ifdef __HAIKU__
#include <RosterPrivate.h>
#include <shadow.h>
#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);
}
+1 -1
View File
@@ -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;
+70 -2
View File
@@ -14,6 +14,7 @@
#include <launch.h>
#include <LaunchDaemonDefs.h>
#include <LaunchRosterPrivate.h>
#include <MessengerPrivate.h>
@@ -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()
{
+3 -1
View File
@@ -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
;
+200 -21
View File
@@ -7,6 +7,8 @@
#include <map>
#include <set>
#include <errno.h>
#include <grp.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -23,8 +25,11 @@
#include <AppMisc.h>
#include <DriverSettingsMessageAdapter.h>
#include <LaunchDaemonDefs.h>
#include <LaunchRosterPrivate.h>
#include <syscalls.h>
#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<BString, BMessage> 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<BString, Job*> JobMap;
class JobFinder {
public:
virtual Job* FindJob(const char* name) const = 0;
};
typedef std::map<BString, Job*> JobMap;
typedef std::map<uid_t, Session*> 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<uid_t, Session*>(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();