Hello,

Following the recent discussions on multiuser support in Tizen 3.0, I dug further on the steps involved in a user session creation.

NB: I used the latest IVI release 20131015.1 for investigation.

Actual situation
================

The default Systemd target is the graphical.target. In particular, this target will launch the following services in this order:
  * ac.service (AMD daemon)
* [email protected] (launchpad for binary apps: OSP Apps, Core Apps and even usual apps like weston-terminal)
  * [email protected] (launchpad for web apps)
* [email protected]: opens the 'app' user session (starts systemd --user)

So before the user-session start, we have AMD and its launchpads running as root (despite the name '[email protected]' for launchpads).

The [email protected] is particular, as it contains:
- User=%I (i.e. User=app)
- PAMName=login
- ExecStart=-/usr/lib/systemd/systemd --user
- Environment=.... (static env variables)

The PAMName=login setting makes that systemd will open a PAM session with the pam service 'login' before starting systemd --user as 'app'. Respectively, when the user session terminates, the PAM session is closed too.

In the actual pam configuration, opening a 'login' session will call the pam_systemd module (included in systemd). This modules sends a DBus message to systemd login manager (systemd-logind) and gets some information in the response. This information is used to initialize some important environment variables. When the session terminates, the pam_systemd module also tells systemd-logind that the user session ended (and depending on its configuration, systemd-logind could kill any remaining user processes).

The following diagram tries to show what happens when systemd starts the user-session (bold=run as root, other run as user)

---------------------------- *systemd-logind*
--------*systemd*                  |
 |          |                      ^
 |          |                      |
 |          v                      |(un)register
 |     *PAM session*               |
 |     *pam_systemd*-<-(dbus msg)--
 |          |
 |          |
 |          v
 |       systemd --user -------------------
 |                                |
 |                                |
 |                                -> ... services inside user session
 |
 |
 |
---> *amd & launchpads* ------------------------------------------------------

NB on IVI: actually, weston is started inside the user session using weston-launch. IMO this is not the right way to do things as weston-launch (setuid root) clears the actual environment, opens a new PAM session then forks a login shell which exec() weston (!). So there's a second PAM session opened but moreover, all the environment variables propagated from the top are erased: that's why we have to put workarounds for environment vars everywhere (in service files, in /etc/sysconfig, in /etc/profile.d and probably in some other places)...

Proposition for the future
==========================

As described previously on this list, we'll probably agree on having a global AMD daemon with its launchpads, running as root (or at least as a privileged user). The consequence is that we have to push information to AMD concerning the user sessions and appropriate environment within each session.

From what I've seen in pam_systemd code (see here: https://review.tizen.org/gerrit/gitweb?p=platform/upstream/systemd.git;a=blob;f=src/login/pam-module.c;h=13290fd8ea6de3fcbb621e99dc7d92e7be50a030;hb=HEAD), we have the following vars initialized before running systemd --user:
- coming from pam_env.so (/etc/environment)
  * nothing (yet)
- coming from systemd-logind:
  * XDG_SESSION_ID
  * XDG_RUNTIME_DIR
  * XDG_SEAT
  * XDG_VTNR
- coming from [email protected] (static vars in service):
  * DISPLAY
  * XDG_RUNTIME_DIR (useless...)
  * DBUS_SESSION_BUS_ADDRESS
- other usual variables set at login time:
  * HOME
  * USER
  * LOGNAME
  * LANG
  * PATH

So, to initialize a user-session environment in AMD, we could have a pam_amd module started *after* pam_systemd and responsible for sending the "init" request to AMD with the current environment. AMD would record the appropriate environment for the given user/session (uid, sid). This env would then be pushed to launchpads every time an application must be started.

Later during the user session, when the environment is complete (ex: desktop is started and we have WAYLAND_DISPLAY set), we could then update the environment in AMD, with some update policies: for example, an environment variable that was already set at init() time can't be updated by update() (we keep the initial value).

We'd get something like this:

---------------------------- *systemd-logind*
----------*systemd*                  |
 |            |                      ^
 |            |                      |
 |            v                      |(un)register
 |       *PAM session*               |
 |       *pam_systemd*-<-(dbus msg)--
 |    ---*pam_amd*
 |    |       |
 |    |       |
 |    |       v
 |    |    systemd --user -------------------
 |    |                    |
 |    |                    |
| | -> ...... services inside user session ...........
 |    |                         |                        |               ^
 |    |                         |                        |               |
 |    |init(uid,sid,[env])      |update(uid,sid,[env])   |launch(app)    |
 |    |                         |                        |               |
 |    V                         v                        V               |
 -> *amd* -----------------------------------------------+------         |
 |                                                       |               |
 |                                                       |      apply env|
 |                                  launch(app,uid,[env])|   & launch app|
 |                                                       v               |
------> *launchpads*---------------------------------------------------------

Remark 1: Wether we have one environment per user or one environment per session is actually discussed... Given the previous diagram, do we know that a launch request comes from a given session ? It seems that we can handle both cases by adding the origin session id to the launch request. But I'm a bit wary about handling uid+session id actually because of extra error handling and added complexity. Do we have use cases for this ?

Remark 2: I didn't draw user session termination. Of course, it's the opposite: pam_amd would send an exit(uid,sid) to AMD to block any future launch for this session.


Discussion
==========

What do you think of this "pam_amd" module ?

Even later when some new mechanisms will be used to open a user session, I'm quite sure we'll still have a PAM session: this is just a standard behaviour on any linux distro. So using a PAM lib to propagate the session environment to AMD makes sense and would certainly allow a smoother transition to anything else in the future.

Hope you love ASCII art ;)
--
Stéphane Desneux
Intel OTC - Vannes/FR
_______________________________________________
Dev mailing list
[email protected]
https://lists.tizen.org/listinfo/dev

Reply via email to