diff options
author | Anna (navi) Figueiredo Gomes <navi@vlhl.dev> | 2024-07-12 18:10:11 +0200 |
---|---|---|
committer | Anna (navi) Figueiredo Gomes <navi@vlhl.dev> | 2024-07-20 03:15:17 +0200 |
commit | ad169aa7edc88091ff7bba3b66040873c28f6d81 (patch) | |
tree | e5e2bcd2902d598021ce5372301162684822e89e /src | |
parent | fd961d2ea0eea2cc60f4af1aca6b6e7711d43995 (diff) |
openrc-pam: auto-launch user services via pam
Signed-off-by: Anna (navi) Figueiredo Gomes <navi@vlhl.dev>
Diffstat (limited to 'src')
-rw-r--r-- | src/meson.build | 1 | ||||
-rw-r--r-- | src/openrc-pam/meson.build | 11 | ||||
-rw-r--r-- | src/openrc-pam/openrc-pam.c | 106 |
3 files changed, 118 insertions, 0 deletions
diff --git a/src/meson.build b/src/meson.build index cee6cb6c..d865379f 100644 --- a/src/meson.build +++ b/src/meson.build @@ -18,6 +18,7 @@ subdir('openrc') subdir('openrc-init') subdir('openrc-run') subdir('openrc-shutdown') +subdir('openrc-pam') subdir('poweroff') subdir('rc-abort') subdir('rc-depend') diff --git a/src/openrc-pam/meson.build b/src/openrc-pam/meson.build new file mode 100644 index 00000000..fa9de471 --- /dev/null +++ b/src/openrc-pam/meson.build @@ -0,0 +1,11 @@ +if get_option('pam') and pam_dep.found() + shared_library('pam_openrc', + ['openrc-pam.c', misc_c, version_h], + c_args : [cc_branding_flags], + dependencies : [pam_dep], + name_prefix : '', + link_with : [libeinfo, librc], + include_directories : [incdir, einfo_incdir, rc_incdir], + install : true, + install_dir : libdir / 'security') +endif diff --git a/src/openrc-pam/openrc-pam.c b/src/openrc-pam/openrc-pam.c new file mode 100644 index 00000000..241b123d --- /dev/null +++ b/src/openrc-pam/openrc-pam.c @@ -0,0 +1,106 @@ +#include <pwd.h> +#include <grp.h> +#include <security/pam_modules.h> +#include <security/pam_appl.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <sys/file.h> +#include <syslog.h> +#include <unistd.h> + +#include "librc.h" +#include "einfo.h" + +static int +exec_openrc(pam_handle_t *pamh, bool opening) +{ + char *svc_name = NULL; + char *pam_lock = NULL; + char *logins, *rundir; + const char *username; + struct passwd *pw; + int count = 0, fd = -1; + int pid = -1, status; + int ret = PAM_SUCCESS; + RC_SERVICE service_status; + + if (pam_get_user(pamh, &username, "username:") != PAM_SUCCESS) + return PAM_SESSION_ERR; + + pw = getpwnam(username); + if (!pw) + return PAM_SESSION_ERR; + + if (pw->pw_uid == 0) + return PAM_SUCCESS; + + xasprintf(&svc_name, "user.%s", pw->pw_name); + service_status = rc_service_state(svc_name); + if (service_status & RC_SERVICE_STARTED && !(service_status & RC_SERVICE_HOTPLUGGED)) + goto out; + + xasprintf(&pam_lock, "openrc-pam.%s", pw->pw_name); + fd = svc_lock(pam_lock, false); + + if (fd == -1) { + ret = PAM_SESSION_ERR; + goto out; + } + + logins = rc_service_value_get(svc_name, "logins"); + if (logins) + sscanf(logins, "%d", &count); + free(logins); + + if (opening && count == 0) { + pid = service_start(svc_name); + rc_service_mark(svc_name, RC_SERVICE_HOTPLUGGED); + count++; + } else if (count > 0) { + pid = service_stop(svc_name); + count--; + } + + if (pid > 0) { + waitpid(pid, &status, 0); + if (status != 0) + ret = PAM_SESSION_ERR; + } + + xasprintf(&logins, "%d", count); + rc_service_value_set(svc_name, "logins", logins); + free(logins); + + rundir = rc_service_value_get(svc_name, "xdg_runtime_dir"); + if (rundir) { + char *rundir_env; + xasprintf(&rundir_env, "XDG_RUNTIME_DIR=%s", rundir); + pam_putenv(pamh, rundir_env); + free(rundir_env); + free(rundir); + } + + svc_unlock(pam_lock, fd); + +out: + free(pam_lock); + free(svc_name); + return ret; +} + +PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv) { + (void) argc; + (void) argv; + (void) flags; + + return exec_openrc(pamh, true); +} + +PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv) { + (void) argc; + (void) argv; + (void) flags; + + return exec_openrc(pamh, false); +} |