diff options
Diffstat (limited to 'src/openrc-pam/openrc-pam.c')
-rw-r--r-- | src/openrc-pam/openrc-pam.c | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/src/openrc-pam/openrc-pam.c b/src/openrc-pam/openrc-pam.c new file mode 100644 index 00000000..5b480836 --- /dev/null +++ b/src/openrc-pam/openrc-pam.c @@ -0,0 +1,72 @@ +#include <stdio.h> +#include <pwd.h> +#include <security/pam_modules.h> +#include <unistd.h> +#include <librc.h> +#include <stdbool.h> +#include <syslog.h> +#ifdef __FreeBSD__ +#include <security/pam_appl.h> +#endif + +static bool exec_openrc(pam_handle_t *pamh, const char *runlevel) { + char *cmd = NULL; + const char *username; + struct passwd *pw = NULL; + + if (pam_get_user(pamh, &username, "username:") != PAM_SUCCESS) + return false; + pw = getpwnam(username); + if (!pw) + return false; + + xasprintf(&cmd, "openrc --user %s", runlevel); + switch (fork()) { + case 0: + setgid(pw->pw_gid); + setuid(pw->pw_uid); + + execl(pw->pw_shell, "-", "-c", cmd, NULL); + + free(cmd); + return false; + break; + case -1: + free(cmd); + return false; + break; + } + wait(NULL); + free(cmd); + return true; +} + +PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv) { + (void)flags; + (void)argc; + (void)argv; + + setenv("RC_PAM_STARTING", "YES", true); + if (exec_openrc(pamh, "default")) { + unsetenv("RC_PAM_STARTING"); + return PAM_SUCCESS; + } else { + unsetenv("RC_PAM_STARTING"); + return PAM_SESSION_ERR; + } +} + +PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv) { + (void)flags; + (void)argc; + (void)argv; + + setenv("RC_PAM_STOPPING", "YES", true); + if (exec_openrc(pamh, "none")) { + unsetenv("RC_PAM_STOPPING"); + return PAM_SUCCESS; + } else { + unsetenv("RC_PAM_STOPPING"); + return PAM_SESSION_ERR; + } +} |