Base code for session manager that supports user authentification via dbus
This commit is contained in:
parent
d82845ecf8
commit
c75274f3d2
3
.gitignore
vendored
3
.gitignore
vendored
@ -139,4 +139,5 @@ m4/lt~obsolete.m4
|
|||||||
# can automatically generate from config.status script
|
# can automatically generate from config.status script
|
||||||
# (which is called by configure script))
|
# (which is called by configure script))
|
||||||
Makefile
|
Makefile
|
||||||
|
.vscode
|
||||||
|
build
|
29
README.md
29
README.md
@ -1,2 +1,31 @@
|
|||||||
# diya-session-manager
|
# diya-session-manager
|
||||||
|
|
||||||
|
## Running the daemon
|
||||||
|
|
||||||
|
By default, the daemon will look for this file in the following locations `/etc/diya/daemon.conf`
|
||||||
|
or it can be specified using the -c option:
|
||||||
|
|
||||||
|
```
|
||||||
|
diya-session-manager -c /path/to/daemon.conf
|
||||||
|
```
|
||||||
|
Example of configuration file can be found in `conf/daemon.conf`
|
||||||
|
|
||||||
|
As the session manager daemon listens on Dbus system bus,to run the daemon:
|
||||||
|
- the variable environment `DBUS_SYSTEM_BUS_ADDRESS` shall be set and known by the daemon
|
||||||
|
e.g. `DBUS_SYSTEM_BUS_ADDRESS=unix:path=/run/dbus/system_bus_socket`
|
||||||
|
- the bus policy shall be configured correctly in `/etc/dbus-1/system.d/` to allow or deny user
|
||||||
|
accessing tothe bus. See `conf/diya-dbus.conf` as an example of bus policy configuration
|
||||||
|
|
||||||
|
## test with dbus-send
|
||||||
|
|
||||||
|
```sh
|
||||||
|
#introspect
|
||||||
|
dbus-send --system --print-reply --reply-timeout=2000 --type=method_call --dest=dev.iohub.diya.SessionManager /dev/iohub/diya/SessionManager org.freedesktop.DBus.Introspectable.Introspect
|
||||||
|
|
||||||
|
# monitor the bus
|
||||||
|
dbus-monitor --system "path=/dev/iohub/diya/SessionManager"
|
||||||
|
|
||||||
|
|
||||||
|
# request user login
|
||||||
|
dbus-send --system --type=method_call --print-reply --dest=dev.iohub.diya.SessionManager /dev/iohub/diya/SessionManager dev.iohub.diya.SessionManager.login string:toto string:tata
|
||||||
|
```
|
24
conf/daemon.conf
Normal file
24
conf/daemon.conf
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# this file is the configuration file for the SessionMaganer daemon
|
||||||
|
# daemon
|
||||||
|
# By default, the daemon will look for this file in the following locations
|
||||||
|
# /etc/diya/daemon.conf
|
||||||
|
# or it can be specified using the -c option
|
||||||
|
# example: diya-session-manager -c /path/to/daemon.conf
|
||||||
|
|
||||||
|
# Login session command
|
||||||
|
# The command to run to start a login session
|
||||||
|
# this command will handle the user input and send user
|
||||||
|
# credentials to the daemon via Dbus message
|
||||||
|
login_session_command = /usr/bin/diya-login-shell
|
||||||
|
|
||||||
|
# login session user
|
||||||
|
# The user that owns the login session, root by default
|
||||||
|
# if this setting is not set
|
||||||
|
login_session_user = xdg
|
||||||
|
|
||||||
|
# User session command
|
||||||
|
# The command to run to start a user session after the
|
||||||
|
# login session is successful
|
||||||
|
# the logged in user will own this session
|
||||||
|
|
||||||
|
user_session_command = /usr/bin/diya-shell
|
29
conf/diya-dbus.conf
Normal file
29
conf/diya-dbus.conf
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<!DOCTYPE busconfig PUBLIC
|
||||||
|
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
|
||||||
|
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
||||||
|
<busconfig>
|
||||||
|
|
||||||
|
<!-- Only root can own the service -->
|
||||||
|
<policy user="root">
|
||||||
|
<allow own="dev.iohub.diya.SessionManager"/>
|
||||||
|
</policy>
|
||||||
|
|
||||||
|
<!--deny all access from another user-->
|
||||||
|
<policy context="default">
|
||||||
|
<deny send_destination="dev.iohub.diya.SessionManager"/>
|
||||||
|
<deny receive_sender="dev.iohub.diya.SessionManager"/>
|
||||||
|
</policy>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<policy group="xdg">
|
||||||
|
<allow send_destination="dev.iohub.diya.SessionManager"/>
|
||||||
|
<allow receive_sender="dev.iohub.diya.SessionManager"/>
|
||||||
|
</policy>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<policy user="root">
|
||||||
|
<allow send_destination="dev.iohub.diya.SessionManager"/>
|
||||||
|
<allow receive_sender="dev.iohub.diya.SessionManager"/>
|
||||||
|
</policy>
|
||||||
|
|
||||||
|
</busconfig>
|
38
meson.build
Normal file
38
meson.build
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
project('diya-session-manager',
|
||||||
|
['c'],
|
||||||
|
version: '0.1.0',
|
||||||
|
license: 'MIT',
|
||||||
|
meson_version: '>=0.58.0',
|
||||||
|
default_options: ['c_std=gnu11', 'warning_level=3'])
|
||||||
|
|
||||||
|
lib_so_version = '0'
|
||||||
|
|
||||||
|
glib = dependency('glib-2.0')
|
||||||
|
gobject = dependency('gobject-2.0')
|
||||||
|
gio = dependency('gio-2.0')
|
||||||
|
crypt = dependency('libcrypt')
|
||||||
|
add_project_arguments(
|
||||||
|
[
|
||||||
|
'-Wno-pedantic',
|
||||||
|
'-Werror=implicit-function-declaration',
|
||||||
|
'-Werror=return-type',
|
||||||
|
],
|
||||||
|
language: 'c')
|
||||||
|
|
||||||
|
|
||||||
|
gnome=import('gnome')
|
||||||
|
resources = gnome.compile_resources('resources','resources/gresource.xml')
|
||||||
|
|
||||||
|
|
||||||
|
src = [
|
||||||
|
'src/main.c',
|
||||||
|
'src/configuration.c',
|
||||||
|
'src/manager.c',
|
||||||
|
'src/base.c',
|
||||||
|
resources
|
||||||
|
]
|
||||||
|
|
||||||
|
executable(
|
||||||
|
'diya-session-manager',
|
||||||
|
src,
|
||||||
|
dependencies: [glib, gobject, gio, crypt])
|
6
resources/gresource.xml
Normal file
6
resources/gresource.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<gresources>
|
||||||
|
<gresource prefix="/dev/iohub/diya/SessionManager">
|
||||||
|
<file>resources/introspection.xml</file>
|
||||||
|
</gresource>
|
||||||
|
</gresources>
|
10
resources/introspection.xml
Normal file
10
resources/introspection.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<node name = "/dev/iohub/diya">
|
||||||
|
<interface name='dev.iohub.diya.SessionManager'>
|
||||||
|
<method name='login'>
|
||||||
|
<!--annotation name='org.gtk.GDBus.Annotation' value='OnMethod' /-->
|
||||||
|
<arg type='s' name='user' direction='in' />
|
||||||
|
<arg type='s' name='password' direction='in' />
|
||||||
|
<arg type='b' name='result' direction='out' />
|
||||||
|
</method>
|
||||||
|
</interface>
|
||||||
|
</node>
|
46
src/base.c
Normal file
46
src/base.c
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#include "base.h"
|
||||||
|
|
||||||
|
G_DEFINE_ABSTRACT_TYPE(BaseObject, base_object, G_TYPE_OBJECT)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Dispose the object
|
||||||
|
*/
|
||||||
|
static void base_object_dispose(GObject* object)
|
||||||
|
{
|
||||||
|
g_debug("base_object_dispose");
|
||||||
|
G_OBJECT_CLASS (base_object_parent_class)->dispose(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Class initialization
|
||||||
|
*/
|
||||||
|
static void base_object_class_init(BaseObjectClass *class)
|
||||||
|
{
|
||||||
|
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
|
||||||
|
class->to_string = NULL;
|
||||||
|
gobject_class->dispose = base_object_dispose;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Object initialization
|
||||||
|
*/
|
||||||
|
static void base_object_init(BaseObject *self)
|
||||||
|
{
|
||||||
|
(void) self;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the string representation of the object
|
||||||
|
*/
|
||||||
|
const gchar* base_object_to_string(gpointer object)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail(BASE_IS_OBJECT(object), NULL);
|
||||||
|
BaseObject *self = BASE_OBJECT(object);
|
||||||
|
BaseObjectClass *class = BASE_OBJECT_GET_CLASS(self);
|
||||||
|
if (class->to_string)
|
||||||
|
{
|
||||||
|
g_debug("calling to_string");
|
||||||
|
return class->to_string(self);
|
||||||
|
}
|
||||||
|
return "BaseObject";
|
||||||
|
}
|
23
src/base.h
Normal file
23
src/base.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#ifndef BASE_H
|
||||||
|
#define BASE_H
|
||||||
|
#include <glib-object.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class object
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define BASE_TYPE_OBJECT (base_object_get_type())
|
||||||
|
G_DECLARE_DERIVABLE_TYPE(BaseObject, base_object, BASE, OBJECT, GObject)
|
||||||
|
|
||||||
|
struct _BaseObjectClass
|
||||||
|
{
|
||||||
|
GObjectClass parent_class;
|
||||||
|
const gchar *(*to_string)(BaseObject *self);
|
||||||
|
/**
|
||||||
|
* @brief reserve for future use to
|
||||||
|
* define common API for descendants
|
||||||
|
*/
|
||||||
|
};
|
||||||
|
|
||||||
|
const gchar *base_object_to_string(gpointer object);
|
||||||
|
#endif
|
268
src/configuration.c
Normal file
268
src/configuration.c
Normal file
@ -0,0 +1,268 @@
|
|||||||
|
#include "configuration.h"
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define DEFAULT_LOGIN_SESSION_USER "root"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Object properties enumeration
|
||||||
|
*/
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
NO_PROP,
|
||||||
|
DAEMON_LOGIN_SESSION_COMMAND,
|
||||||
|
DAEMON_LOGIN_SESSION_USER,
|
||||||
|
DAEMON_SESSION_COMMAND,
|
||||||
|
N_PROPERTIES
|
||||||
|
};
|
||||||
|
static GParamSpec *conf_properties[N_PROPERTIES] = {0};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Object private structure
|
||||||
|
*/
|
||||||
|
struct _DaemonConfiguration
|
||||||
|
{
|
||||||
|
BaseObject parent_object;
|
||||||
|
gchar* login_session_command;
|
||||||
|
gchar* login_session_user;
|
||||||
|
gchar* session_command;
|
||||||
|
gchar* string;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_FINAL_TYPE(DaemonConfiguration, daemon_configuration, BASE_TYPE_OBJECT)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Dispose the object
|
||||||
|
*/
|
||||||
|
static void daemon_configuration_dispose(GObject* object)
|
||||||
|
{
|
||||||
|
DaemonConfiguration * self = DAEMON_CONFIGURATION(object);
|
||||||
|
g_debug("daemon_configuration_dispose: %s", base_object_to_string(self));
|
||||||
|
if(self->login_session_command)
|
||||||
|
{
|
||||||
|
g_free(self->login_session_command);
|
||||||
|
}
|
||||||
|
if(self->login_session_user)
|
||||||
|
{
|
||||||
|
g_free(self->login_session_user);
|
||||||
|
}
|
||||||
|
if(self->session_command)
|
||||||
|
{
|
||||||
|
g_free(self->session_command);
|
||||||
|
}
|
||||||
|
if(self->string)
|
||||||
|
{
|
||||||
|
g_free(self->string);
|
||||||
|
}
|
||||||
|
self->string = NULL;
|
||||||
|
G_OBJECT_CLASS(daemon_configuration_parent_class)->dispose(object);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief Set the object property
|
||||||
|
*/
|
||||||
|
static void daemon_configuration_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
(void)object;
|
||||||
|
(void)value;
|
||||||
|
(void)pspec;
|
||||||
|
// DaemonConfiguration * self = DAEMON_CONFIGURATION(object);
|
||||||
|
switch (property_id)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the object property
|
||||||
|
*/
|
||||||
|
static void daemon_configuration_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
DaemonConfiguration * self = DAEMON_CONFIGURATION(object);
|
||||||
|
switch (property_id)
|
||||||
|
{
|
||||||
|
case DAEMON_LOGIN_SESSION_COMMAND:
|
||||||
|
g_value_set_string(value, self->login_session_command);
|
||||||
|
break;
|
||||||
|
case DAEMON_LOGIN_SESSION_USER:
|
||||||
|
g_value_set_string(value, self->login_session_user);
|
||||||
|
break;
|
||||||
|
case DAEMON_SESSION_COMMAND:
|
||||||
|
g_value_set_string(value, self->session_command);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the string representation of the object
|
||||||
|
*/
|
||||||
|
static const gchar* daemon_configuration_to_string(BaseObject* object)
|
||||||
|
{
|
||||||
|
g_debug("Call daemon_configuration_to_string");
|
||||||
|
DaemonConfiguration* self = DAEMON_CONFIGURATION(object);
|
||||||
|
return self->string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Class initialization
|
||||||
|
*/
|
||||||
|
static void daemon_configuration_class_init(DaemonConfigurationClass *class)
|
||||||
|
{
|
||||||
|
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
|
||||||
|
BaseObjectClass *base_class = BASE_OBJECT_CLASS(class);
|
||||||
|
|
||||||
|
gobject_class->dispose = daemon_configuration_dispose;
|
||||||
|
gobject_class->set_property = daemon_configuration_set_property;
|
||||||
|
gobject_class->get_property = daemon_configuration_get_property;
|
||||||
|
|
||||||
|
base_class->to_string = daemon_configuration_to_string;
|
||||||
|
|
||||||
|
conf_properties[DAEMON_LOGIN_SESSION_COMMAND] = g_param_spec_string("login-session-command", NULL, "Login session command", NULL, G_PARAM_READABLE);
|
||||||
|
conf_properties[DAEMON_LOGIN_SESSION_USER] = g_param_spec_string("login-session-user", NULL, "Login session user", NULL, G_PARAM_READABLE);
|
||||||
|
conf_properties[DAEMON_SESSION_COMMAND] = g_param_spec_string("session-command", NULL, "Session command", NULL, G_PARAM_READABLE);
|
||||||
|
g_object_class_install_properties (gobject_class, N_PROPERTIES, conf_properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Object initialization
|
||||||
|
*/
|
||||||
|
static void daemon_configuration_init(DaemonConfiguration *self)
|
||||||
|
{
|
||||||
|
self->login_session_command = NULL;
|
||||||
|
self->login_session_user = NULL;
|
||||||
|
self->session_command = NULL;
|
||||||
|
self->string = NULL;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief Create a new DaemonConfiguration object
|
||||||
|
*
|
||||||
|
* read and parse the config_file
|
||||||
|
* The format of the config file is as follows:
|
||||||
|
* - line starting with # are comments and should be ignored
|
||||||
|
* - line starting with login_session_command= is the command to start the login session
|
||||||
|
* - line starting with login_session_user= is the user to start the login session
|
||||||
|
* - line starting with session_command= is the command to start the session
|
||||||
|
*
|
||||||
|
* @param config_file The path to the configuration file
|
||||||
|
* @return The DaemonConfiguration object
|
||||||
|
*/
|
||||||
|
DaemonConfiguration* daemon_configuration_new(const gchar* config_file)
|
||||||
|
{
|
||||||
|
FILE* file = fopen(config_file, "r");
|
||||||
|
if(!file)
|
||||||
|
{
|
||||||
|
g_critical("Error opening the configuration file %s: %s", config_file, strerror(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* read file line by line
|
||||||
|
*/
|
||||||
|
DaemonConfiguration* conf = g_object_new(DAEMON_TYPE_CONFIGURATION, NULL);
|
||||||
|
char* line = NULL;
|
||||||
|
ssize_t read;
|
||||||
|
gchar* ptr = NULL;
|
||||||
|
int conf_valid = 0;
|
||||||
|
size_t len = 0;
|
||||||
|
conf->string = g_strconcat("DaemonConfiguration from ",
|
||||||
|
config_file,
|
||||||
|
":\n",
|
||||||
|
NULL);
|
||||||
|
ptr = conf->string;
|
||||||
|
while ((read = getline(&line, &len, file)) != -1)
|
||||||
|
{
|
||||||
|
if (line[0] == '#')
|
||||||
|
{
|
||||||
|
free(line);
|
||||||
|
line = NULL;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* strip newline at the end
|
||||||
|
*/
|
||||||
|
if (line[read - 1] == '\n')
|
||||||
|
{
|
||||||
|
line[read - 1] = '\0';
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* parse line using strok
|
||||||
|
*/
|
||||||
|
char* value = NULL;
|
||||||
|
char* key = strtok_r(line, "=", &value);
|
||||||
|
if(!key || !value)
|
||||||
|
{
|
||||||
|
free(line);
|
||||||
|
line = NULL;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* strim key and value at the begin and the end
|
||||||
|
*/
|
||||||
|
while(*key == ' ')
|
||||||
|
{
|
||||||
|
key++;
|
||||||
|
}
|
||||||
|
char* end = key + strlen(key) - 1;
|
||||||
|
while(*end == ' ')
|
||||||
|
{
|
||||||
|
*end = '\0';
|
||||||
|
end--;
|
||||||
|
}
|
||||||
|
while(*value == ' ')
|
||||||
|
{
|
||||||
|
value++;
|
||||||
|
}
|
||||||
|
end = value + strlen(value) - 1;
|
||||||
|
while(*end == ' ')
|
||||||
|
{
|
||||||
|
*end = '\0';
|
||||||
|
end--;
|
||||||
|
}
|
||||||
|
conf_valid = 1;
|
||||||
|
if (strncmp(key, "login_session_command", 22) == 0)
|
||||||
|
{
|
||||||
|
conf->login_session_command = g_strdup(value);
|
||||||
|
}
|
||||||
|
else if (strncmp(key, "login_session_user", 19) == 0)
|
||||||
|
{
|
||||||
|
conf->login_session_user = g_strdup(value);
|
||||||
|
}
|
||||||
|
else if (strncmp(key, "user_session_command", 21) == 0)
|
||||||
|
{
|
||||||
|
conf->session_command = g_strdup(value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_warning("Ignore unknown configuration: [%s]:[%s]", key, value);
|
||||||
|
conf_valid = 0;
|
||||||
|
}
|
||||||
|
if(conf_valid)
|
||||||
|
{
|
||||||
|
conf->string = g_strconcat(ptr, " - ", key, ": ", value, "\n", NULL);
|
||||||
|
g_free(ptr);
|
||||||
|
ptr = conf->string;
|
||||||
|
}
|
||||||
|
free(line);
|
||||||
|
line = NULL;
|
||||||
|
}
|
||||||
|
if(line)
|
||||||
|
{
|
||||||
|
free(line);
|
||||||
|
}
|
||||||
|
fclose(file);
|
||||||
|
if(conf->login_session_user == NULL)
|
||||||
|
{
|
||||||
|
conf->login_session_user = g_strdup("root");
|
||||||
|
}
|
||||||
|
if(conf->login_session_command == NULL || conf->session_command == NULL)
|
||||||
|
{
|
||||||
|
g_critical("login_session_command or session_command is not set in the configuration file");
|
||||||
|
g_object_unref(conf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return conf;
|
||||||
|
}
|
10
src/configuration.h
Normal file
10
src/configuration.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#ifndef CONFIGURATION_H
|
||||||
|
#define CONFIGURATION_H
|
||||||
|
#include "base.h"
|
||||||
|
|
||||||
|
#define DAEMON_TYPE_CONFIGURATION (daemon_configuration_get_type())
|
||||||
|
G_DECLARE_FINAL_TYPE(DaemonConfiguration, daemon_configuration, DAEMON, CONFIGURATION, BaseObject)
|
||||||
|
|
||||||
|
DaemonConfiguration* daemon_configuration_new(const gchar* config_file);
|
||||||
|
|
||||||
|
#endif
|
93
src/main.c
Normal file
93
src/main.c
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <glib-unix.h>
|
||||||
|
|
||||||
|
#include "manager.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
#define DEFALT_CONF_FILE "/etc/diya/daemon.conf"
|
||||||
|
|
||||||
|
static gchar **g_shell_argv;
|
||||||
|
|
||||||
|
static void help(const char* name)
|
||||||
|
{
|
||||||
|
printf("Usage: %s [-c config_file]\n" ,name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean restart(gpointer d)
|
||||||
|
{
|
||||||
|
(void)d;
|
||||||
|
gint i, fdlimit;
|
||||||
|
|
||||||
|
fdlimit = (int)sysconf(_SC_OPEN_MAX);
|
||||||
|
g_debug("reload: closing fd's %d to %d", STDERR_FILENO + 1, fdlimit);
|
||||||
|
for (i = STDERR_FILENO + 1; i < fdlimit; i++)
|
||||||
|
{
|
||||||
|
fcntl(i, F_SETFD, FD_CLOEXEC);
|
||||||
|
}
|
||||||
|
g_debug("reload: exec: %s", g_shell_argv[0]);
|
||||||
|
execvp(g_shell_argv[0], g_shell_argv);
|
||||||
|
exit(1);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean quit(gpointer d)
|
||||||
|
{
|
||||||
|
g_debug("Quit the daemon");
|
||||||
|
session_manager_event_loop_stop((SessionManager*)d);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* const *argv)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Read command line arguments using getopt:
|
||||||
|
* - if the argument is -h or --help print the help message
|
||||||
|
* - if the argument is -c or --config set the configuration file
|
||||||
|
*/
|
||||||
|
const gchar* config_file = DEFALT_CONF_FILE;
|
||||||
|
int opt;
|
||||||
|
while ((opt = getopt(argc, argv, "hc:")) != -1)
|
||||||
|
{
|
||||||
|
switch (opt)
|
||||||
|
{
|
||||||
|
case 'h':
|
||||||
|
help(argv[0]);
|
||||||
|
return 0;
|
||||||
|
case 'c':
|
||||||
|
config_file = optarg;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
help(argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_shell_argv = g_malloc0(sizeof(gchar *) * (argc + 1));
|
||||||
|
for (int i = 0; i < argc; i++)
|
||||||
|
{
|
||||||
|
g_shell_argv[i] = argv[i];
|
||||||
|
}
|
||||||
|
SessionManager* manager = session_manager_new(config_file);
|
||||||
|
if (!manager)
|
||||||
|
{
|
||||||
|
g_error("Error creating the session manager");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
g_unix_signal_add(SIGHUP, (GSourceFunc)restart, NULL);
|
||||||
|
g_unix_signal_add(SIGINT,(GSourceFunc)quit,(void*)manager);
|
||||||
|
DaemonConfiguration* conf = NULL;
|
||||||
|
g_object_get(manager, "configuration", &conf, NULL);
|
||||||
|
if(conf)
|
||||||
|
{
|
||||||
|
g_debug("Run daemon with: %s", base_object_to_string(conf));
|
||||||
|
}
|
||||||
|
session_manager_event_loop_start(manager);
|
||||||
|
g_debug("Release the manager");
|
||||||
|
g_object_unref(manager);
|
||||||
|
return 0;
|
||||||
|
}
|
327
src/manager.c
Normal file
327
src/manager.c
Normal file
@ -0,0 +1,327 @@
|
|||||||
|
#include "manager.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
#include <gio/gio.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <grp.h>
|
||||||
|
#include <shadow.h>
|
||||||
|
|
||||||
|
#define DBUS_SERVER_NAME "dev.iohub.diya.SessionManager"
|
||||||
|
#define DBUS_SERVER_PATH "/dev/iohub/diya/SessionManager"
|
||||||
|
#define DBUS_SERVER_ERROR_NAME "dev.iohub.diya.SessionManager.Error"
|
||||||
|
/**
|
||||||
|
* @brief Object properties enumeration
|
||||||
|
*/
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
SESSION_MANAGER_NO_PROP,
|
||||||
|
SESSION_MANAGER_CONFIGURATION,
|
||||||
|
N_PROPERTIES
|
||||||
|
};
|
||||||
|
|
||||||
|
static GParamSpec *manager_properties[N_PROPERTIES] = {0};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Object private structure
|
||||||
|
*/
|
||||||
|
struct _SessionManager
|
||||||
|
{
|
||||||
|
BaseObject parent_object;
|
||||||
|
DaemonConfiguration *configuration;
|
||||||
|
pid_t session_pid;
|
||||||
|
pid_t login_session_pid;
|
||||||
|
GMainLoop *loop;
|
||||||
|
GDBusNodeInfo *introspection;
|
||||||
|
guint bus_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_FINAL_TYPE(SessionManager, session_manager, BASE_TYPE_OBJECT);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Dispose the object
|
||||||
|
*/
|
||||||
|
static void session_manager_dispose(GObject *object)
|
||||||
|
{
|
||||||
|
SessionManager *self = SESSION_MANAGER(object);
|
||||||
|
g_debug("session_manager_dispose: %s", base_object_to_string(self));
|
||||||
|
if (self->configuration)
|
||||||
|
{
|
||||||
|
g_object_unref(self->configuration);
|
||||||
|
}
|
||||||
|
if (self->loop)
|
||||||
|
{
|
||||||
|
g_main_loop_unref(self->loop);
|
||||||
|
}
|
||||||
|
if (self->introspection)
|
||||||
|
{
|
||||||
|
g_dbus_node_info_unref(self->introspection);
|
||||||
|
}
|
||||||
|
if (self->bus_id > 0)
|
||||||
|
{
|
||||||
|
g_bus_unown_name(self->bus_id);
|
||||||
|
}
|
||||||
|
G_OBJECT_CLASS(session_manager_parent_class)->dispose(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the string representation of the object
|
||||||
|
*/
|
||||||
|
static const gchar *session_manager_to_string(BaseObject *object)
|
||||||
|
{
|
||||||
|
(void)object;
|
||||||
|
// SessionManager* self = SESSION_MANAGER(object);
|
||||||
|
return "SessionManager";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the object property
|
||||||
|
*/
|
||||||
|
static void session_manager_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
SessionManager *self = SESSION_MANAGER(object);
|
||||||
|
switch (property_id)
|
||||||
|
{
|
||||||
|
case SESSION_MANAGER_CONFIGURATION:
|
||||||
|
g_value_set_pointer(value, self->configuration);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Class initialization
|
||||||
|
*/
|
||||||
|
static void session_manager_class_init(SessionManagerClass *class)
|
||||||
|
{
|
||||||
|
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
|
||||||
|
BaseObjectClass *base_class = BASE_OBJECT_CLASS(class);
|
||||||
|
gobject_class->dispose = session_manager_dispose;
|
||||||
|
gobject_class->get_property = session_manager_get_property;
|
||||||
|
|
||||||
|
base_class->to_string = session_manager_to_string;
|
||||||
|
|
||||||
|
manager_properties[SESSION_MANAGER_CONFIGURATION] = g_param_spec_pointer("configuration", NULL, "Configuration", G_PARAM_READABLE);
|
||||||
|
g_object_class_install_properties(gobject_class, N_PROPERTIES, manager_properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Object initialization
|
||||||
|
*/
|
||||||
|
static void session_manager_init(SessionManager *self)
|
||||||
|
{
|
||||||
|
self->configuration = NULL;
|
||||||
|
self->session_pid = 0;
|
||||||
|
self->login_session_pid = 0;
|
||||||
|
self->loop = g_main_loop_new(NULL, FALSE);
|
||||||
|
self->introspection = NULL;
|
||||||
|
self->bus_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean session_user_auth(const char *username, const char *password)
|
||||||
|
{
|
||||||
|
char *encrypted;
|
||||||
|
struct passwd *pwd;
|
||||||
|
struct spwd *spwd;
|
||||||
|
/* Look up password and shadow password records for username */
|
||||||
|
pwd = getpwnam(username);
|
||||||
|
if (pwd == NULL)
|
||||||
|
{
|
||||||
|
g_critical("getpwnam: %s", strerror(errno));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
spwd = getspnam(username);
|
||||||
|
/*
|
||||||
|
if (spwd == NULL)
|
||||||
|
{
|
||||||
|
g_critical("getspnam: %s", strerror(errno));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (spwd != NULL) /* If there is a shadow password record */
|
||||||
|
{
|
||||||
|
pwd->pw_passwd = spwd->sp_pwdp; /* Use the shadow password */
|
||||||
|
}
|
||||||
|
/* Encrypt password and erase cleartext version immediately */
|
||||||
|
encrypted = crypt(password, pwd->pw_passwd);
|
||||||
|
if (encrypted == NULL)
|
||||||
|
{
|
||||||
|
g_critical("crypt: %s", strerror(errno));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (strcmp(encrypted, pwd->pw_passwd) == 0)
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Method call handler on dbus interface
|
||||||
|
*/
|
||||||
|
static void session_manager_method_call(GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *method_name, GVariant *parameters, GDBusMethodInvocation *invocation, gpointer user_data)
|
||||||
|
{
|
||||||
|
(void)connection;
|
||||||
|
(void)sender;
|
||||||
|
(void)object_path;
|
||||||
|
(void)interface_name;
|
||||||
|
(void)parameters;
|
||||||
|
(void)user_data;
|
||||||
|
SessionManager *self = SESSION_MANAGER(user_data);
|
||||||
|
g_debug("session_manager_method_call: %s", method_name);
|
||||||
|
if (g_strcmp0(method_name, "login") == 0)
|
||||||
|
{
|
||||||
|
const gchar *username;
|
||||||
|
const gchar *password;
|
||||||
|
g_variant_get(parameters, "(&s&s)", &username, &password);
|
||||||
|
g_debug("Login request for user: %s with password %s", username, password);
|
||||||
|
|
||||||
|
if (self->session_pid > 0)
|
||||||
|
{
|
||||||
|
g_warning("Cannot process login request for user %s. A session is currently running", username);
|
||||||
|
g_dbus_method_invocation_return_dbus_error(invocation, DBUS_SERVER_ERROR_NAME, "A session is currently running");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(session_user_auth(username, password))
|
||||||
|
{
|
||||||
|
g_dbus_method_invocation_return_value(invocation, g_variant_new("(b)", TRUE));
|
||||||
|
/**
|
||||||
|
* TODO: exit login session and start a new user session
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_dbus_method_invocation_return_value(invocation, g_variant_new("(b)", FALSE));
|
||||||
|
}
|
||||||
|
// g_variant_unref(result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_dbus_method_invocation_return_dbus_error(invocation, DBUS_SERVER_ERROR_NAME, "Method not found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Bus listener callback
|
||||||
|
*/
|
||||||
|
static const GDBusInterfaceVTable interface_vtable =
|
||||||
|
{
|
||||||
|
.method_call = session_manager_method_call,
|
||||||
|
.get_property = NULL,
|
||||||
|
.set_property = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Bus acquired callback
|
||||||
|
*/
|
||||||
|
static void on_bus_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data)
|
||||||
|
{
|
||||||
|
SessionManager *self = SESSION_MANAGER(user_data);
|
||||||
|
g_debug("on_bus_acquired: %s", name);
|
||||||
|
GError *error = NULL;
|
||||||
|
if (!g_dbus_connection_register_object(
|
||||||
|
connection,
|
||||||
|
DBUS_SERVER_PATH,
|
||||||
|
self->introspection->interfaces[0],
|
||||||
|
&interface_vtable,
|
||||||
|
user_data,
|
||||||
|
NULL,
|
||||||
|
&error))
|
||||||
|
{
|
||||||
|
g_critical("Failed to register object: %s", error->message);
|
||||||
|
g_error_free(error);
|
||||||
|
session_manager_event_loop_stop(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Name acquired callback
|
||||||
|
*/
|
||||||
|
static void on_name_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data)
|
||||||
|
{
|
||||||
|
(void)connection;
|
||||||
|
(void)user_data;
|
||||||
|
g_debug("on_name_acquired: %s", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Name lost callback
|
||||||
|
*/
|
||||||
|
static void on_name_lost(GDBusConnection *connection, const gchar *name, gpointer user_data)
|
||||||
|
{
|
||||||
|
(void)connection;
|
||||||
|
g_critical("DBus session manager name lost, probably because of user not having access rights on the bus: %s", name);
|
||||||
|
SessionManager *self = SESSION_MANAGER(user_data);
|
||||||
|
session_manager_event_loop_stop(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a new SessionManager object
|
||||||
|
*/
|
||||||
|
SessionManager *session_manager_new(const gchar *config_file)
|
||||||
|
{
|
||||||
|
SessionManager *manager = g_object_new(SESSION_TYPE_MANAGER, NULL);
|
||||||
|
manager->configuration = daemon_configuration_new(config_file);
|
||||||
|
if (!manager->configuration)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
// load xml content from gresource
|
||||||
|
GError *err = NULL;
|
||||||
|
GBytes *bytes = g_resources_lookup_data("/dev/iohub/diya/SessionManager/resources/introspection.xml", 0, &err);
|
||||||
|
if (err != NULL)
|
||||||
|
{
|
||||||
|
g_critical("Unable to load introspection resource: %s", err->message);
|
||||||
|
g_error_free(err);
|
||||||
|
g_object_unref(manager);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
const char *data = g_bytes_get_data(bytes, NULL);
|
||||||
|
g_debug("introspection xml: \n %s", data);
|
||||||
|
manager->introspection = g_dbus_node_info_new_for_xml(data, &err);
|
||||||
|
g_bytes_unref(bytes);
|
||||||
|
if (err != NULL)
|
||||||
|
{
|
||||||
|
g_critical("Unable to parse introspection xml: %s", err->message);
|
||||||
|
g_error_free(err);
|
||||||
|
g_object_unref(manager);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
manager->bus_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
|
||||||
|
DBUS_SERVER_NAME,
|
||||||
|
G_BUS_NAME_OWNER_FLAGS_NONE,
|
||||||
|
on_bus_acquired,
|
||||||
|
on_name_acquired,
|
||||||
|
on_name_lost,
|
||||||
|
manager,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Start the session manager event loop
|
||||||
|
*/
|
||||||
|
void session_manager_event_loop_start(SessionManager *self)
|
||||||
|
{
|
||||||
|
if (g_main_loop_is_running(self->loop))
|
||||||
|
{
|
||||||
|
g_warning("Session manager already started. do nothing");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
g_debug("Session manager event loop");
|
||||||
|
|
||||||
|
g_main_loop_run(self->loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stop the session manager event loop
|
||||||
|
*/
|
||||||
|
void session_manager_event_loop_stop(SessionManager *self)
|
||||||
|
{
|
||||||
|
g_main_loop_quit(self->loop);
|
||||||
|
}
|
12
src/manager.h
Normal file
12
src/manager.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#ifndef MANAGER_H
|
||||||
|
#define MANAGER_H
|
||||||
|
|
||||||
|
#include "base.h"
|
||||||
|
|
||||||
|
#define SESSION_TYPE_MANAGER (session_manager_get_type())
|
||||||
|
G_DECLARE_FINAL_TYPE(SessionManager, session_manager, SESSION, MANAGER, BaseObject)
|
||||||
|
|
||||||
|
SessionManager* session_manager_new(const gchar* config_file);
|
||||||
|
void session_manager_event_loop_start(SessionManager* manager);
|
||||||
|
void session_manager_event_loop_stop(SessionManager* manager);
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user