[systemd-devel] Crond session, pam_access and pam_systemd

Thomas HUMMEL thomas.hummel at pasteur.fr
Fri Oct 16 13:13:31 UTC 2020


On 16/10/2020 13:22, Mantas Mikulėnas wrote:

> But I think you're still confusing the two different kinds of "sessions" 
> that exist here. PAM open_session creates a PAM session, which 
> eventually *causes* a systemd-logind session to be created, but isn't 
> 100% the same thing.

Yes I probably did.
My undestanding is that a pam session is anything pam modules do between 
pam_open_session() and pam_close_session(), which could be things like 
write to /var/run/utmp for instance and a systemd-logind session is just 
a scope holding all a user processes between his login and logout

> Not exactly. For cron and sshd, all those PAM functions are called 
> directly by cron or sshd themselves.

Ok. That's indeed what I thought initially, being later confused by the 
sd-pam thing.

> The sd-pam helper only does this task when systemd pid1 (the service 
> manager) needs to call PAM for a service that has PAMName= set in its unit.

https://www.freedesktop.org/software/systemd/man/systemd.exec.html#PAMName=

describes sd-pam as a pam session handler when a service unit uses 
PAMNane= indeed (sorry, I didn't read it before - hence the confusion)

[By the way I don't know how a child process can wait for its parent - 
waiting for its parent to send a signal ?]

> As far as I could figure out, the entire process works like this:
> 
> sshd (listener)
> └ sshd (connection worker)
>    ├ pam_start(sshd, ...)
>    ├ pam_acct_mgmt()
>    │ └ pam_access.so
>    ├ pam_open_session()
>    │ └ pam_systemd.so
>    │   └ DBus call to systemd-logind: CreateSession(service=sshd, uid=1000)
>    ├ fork login shell
>    │ └ /bin/bash
>    └ pam_close_session()

Ok. So pam_systemd registers a (systemd-logind) session via dbus to 
systemd-logind. This session will contain the ssh login shell and so on.

> systemd-logind
> └ receives CreateSession(uid=1000)
>    ├ DBus call to systemd: Start(user at 1000.service)
>    └ DBus call to systemd: StartTransientUnit(session-1234.scope)

See comment at the end.

> systemd (pid1)
>user at 1000.service
>    └ sd-pam
>      ├ pam_start(systemd-user, ...)
>      ├ pam_acct_mgmt()
>      │ └ pam_access.so
>      ├ pam_open_session()
>      ├ fork sd-pam child
>      │ └ sd-pam (waits for parent to exit)
>      │   └ pam_close_session()
>      └ exec systemd --user
> 
>     - such a worker is started by a systemd --user instance
> 
> 
> No, it's actually started by the systemd system manager itself, because 
> user at .service has PAMName= set. It only *appears* to be a child of 
> systemd --user, because it is a child of the process which first forked 
> sd-pam, then exec'd systemd --user.

So basically user@<uid>.service is a service using PAMName=systemd-user 
with an sd-pam pam session handler and which main process (similar to an 
ExecStart in a standard service unit) is systemd --user correct ?

Why has it got to work the other way around compared to as service 
wainting for its child to finish to call pam_close_session() as you said ?


> Most tools (sudo, sshd, crond) handle all PAM calls in the parent 
> process, just forking your shell or cronjob as a child, then waiting for 
> the child to exit before they can call pam_close_session(). Systemd does 
> it the other way around – it also forks, but the *child* waits for the 
> parent to exit before calling pam_close_session(), whereas the parent 
> directly execs the ExecStart command.

So the second sd-pam you mentionned in your tree above is this handler 
mentionnend in the doc I mentionned and waiting for systemd --user to 
finish to take proper action when closing the pam session ?

> So if you had a basic unit with "ExecStart=/bin/sleep 1h", if it also 
> had User= and PAMName=, then you would see 'sd-pam' as a child of 'sleep 
> 1h'.

Ok.


> user@<uid>.service is where the name is configured, but sd-pam is the 
> process which actually calls PAM for that service name.

Ok.


> I don't know why you're seeing the different behavior between crond and 
> sshd.
> 
> However, a systemd-logind session doesn't actually *need* user at .service 
> (systemd --user), it can be created without. So even if 
> user@<uid>.service could not be started due to PAM not authorizing it 
> (or due to some other reason), this will still not prevent pam_systemd 
> from registering the session and creating user-<uid>.slice and making it 
> appear in `loginctl`.

Ok.

Regarding the following part :

 > systemd-logind
 > └ receives CreateSession(uid=1000)
 >    ├ DBus call to systemd: Start(user at 1000.service)
 >    └ DBus call to systemd: StartTransientUnit(session-1234.scope)

Since you said systemd-logind does not need systemd --user to creates 
the session I guess the second job (start transient unit) can be done 
without it. So can I conclude that this is just the way systemd-logind 
is designed : when instructed to create a session, it also start the 
user@<uid>.service just for the user to be able to use its own systemd 
instance (which in my case of user crontab is not used) ?

I all of my guesses are correct I still have to figure out the exact 
problem I had when the user (who had a crontab) was not allowed to 
access systemd-user pam service.

Thanks for your help

--
Thomas HUMMEL


More information about the systemd-devel mailing list