aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/meson.build1
-rw-r--r--src/openrc-pam/meson.build11
-rw-r--r--src/openrc-pam/openrc-pam.c106
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);
+}