Hi. I have an autologin program which authenticates a user without asking for a
password and starts a child process executing a user shell (for example, Bash,
Xorg, or a Wayland compositor).
This program is a systemd service. I discovered that systemd kills the
autologin program, but does not kill the child of the autologin program. As I
understand from the systemd documentation, systemd should kill both.
I composed a minimal example in C at the end. It's lengthy. The service file
`/etc/systemd/system/testa.service`:
```
[Unit]
Description=Autologin
After=systemd-user-sessions.service plymouth-quit-wait.service
[Service]
Type=simple
ExecStart=autologin
[Install]
Alias=display-manager.service
WantedBy=multi-user.target
```
I test it like this:
```
[root@beroal test-autologin]# ps --forest -e -o
pid,ppid,cgroup,pgid,sid,label,uid,command | grep 1004
55809 55651 0::/user.slice/user-1002.sl 55808 11243 unconfined
0 \_ grep 1004
[root@beroal test-autologin]# systemctl start testa
[root@beroal test-autologin]# ps --forest -e -o
pid,ppid,cgroup,pgid,sid,label,uid,command | grep 1004
55824 55651 0::/user.slice/user-1002.sl 55823 11243 unconfined
0 \_ grep 1004
55812 1 0::/user.slice/user-1004.sl 55812 55812 unconfined
0 autologin
55822 55812 0::/user.slice/user-1004.sl 55812 55812 unconfined
0 \_ sleep 600
55814 1 0::/user.slice/user-1004.sl 55814 55814 unconfined
1004 /usr/lib/systemd/systemd --user
55815 55814 0::/user.slice/user-1004.sl 55814 55814 unconfined
1004 \_ (sd-pam)
[root@beroal test-autologin]# systemctl stop testa
[root@beroal test-autologin]# ps --forest -e -o
pid,ppid,cgroup,pgid,sid,label,uid,command | grep 1004
55828 55651 0::/user.slice/user-1002.sl 55827 11243 unconfined
0 \_ grep 1004
55814 1 0::/user.slice/user-1004.sl 55814 55814 unconfined
1004 /usr/lib/systemd/systemd --user
55815 55814 0::/user.slice/user-1004.sl 55814 55814 unconfined
1004 \_ (sd-pam)
55822 1 0::/user.slice/user-1004.sl 55812 55812 unconfined
0 sleep 600
[root@beroal test-autologin]# systemctl kill --kill-who=all --signal=SIGTERM
user-1004.slice
[root@beroal test-autologin]# ps --forest -e -o
pid,ppid,cgroup,pgid,sid,label,uid,command | grep 1004
55832 55651 0::/user.slice/user-1002.sl 55831 11243 unconfined
0 \_ grep 1004
```
The child `sleep 600` process wasn't killed by stopping the service, but was
killed by stopping the slice.
Is this the intended behavior? Do I handle user authentication wrongly? Is
there a way to kill a service fully?
Arch Linux
systemd version: 249.7-2
`autologin`:
```c
#define _GNU_SOURCE
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
static int check_errno(char *operation, int error) {
if (error != -1)
return error;
fprintf(stderr, "%s failed: %s (%d)\n", operation, strerror(errno), errno);
exit(EXIT_FAILURE);
}
static int check_pam(struct pam_handle *handle, char *operation, int error) {
if (error == PAM_SUCCESS)
return 0;
fprintf(stderr, "%s failed: %s\n", operation, pam_strerror(handle, error));
if (handle != NULL)
pam_end(handle, error);
exit(EXIT_FAILURE);
}
static int pam_null_conv(int num_msg, const struct pam_message** msg, struct
pam_response** resp, void* appdata_ptr) {
(void)msg;
(void)appdata_ptr;
*resp = calloc(num_msg, sizeof (struct pam_response));
return *resp == NULL ? PAM_BUF_ERR : PAM_SUCCESS;
}
static int pam_putenv_tuple(struct pam_handle* handle, char* key, char* value) {
char buf[256];
snprintf(buf, sizeof buf, "%s=%s", key, value);
return pam_putenv(handle, buf);
}
static char *getenv_or(char *key, char *or) {
char *var = getenv(key);
return var ? var : or;
}
int main(void) {
char *user_cmd[] = { "sleep", "600", NULL };
struct pam_conv conv = { pam_null_conv, NULL };
struct pam_handle* handle = NULL;
check_pam(handle, "pam_start", pam_start("autologin", "test", &conv, &handle));
check_pam(handle, "pam_acct_mgmt", pam_acct_mgmt(handle, PAM_SILENT));
check_pam(handle, "pam_setcred", pam_setcred(handle, PAM_ESTABLISH_CRED));
struct passwd* pwd = getpwnam("test");
if (pwd == NULL) {
fprintf(stderr, "getpwnam failed\n");
return 1;
}
check_pam(handle, "pam_putenv", pam_putenv_tuple(handle, "XDG_SEAT",
"seat-guest"));
check_pam(handle, "pam_putenv", pam_putenv(handle, "XDG_SESSION_CLASS=user"));
check_pam(handle, "pam_putenv", pam_putenv_tuple(handle, "HOME", pwd->pw_dir));
check_pam(handle, "pam_putenv", pam_putenv_tuple(handle, "PWD", pwd->