diff options
Diffstat (limited to 'src/pam.c')
-rw-r--r-- | src/pam.c | 123 |
1 files changed, 121 insertions, 2 deletions
@@ -18,6 +18,8 @@ */ #include <stdio.h> #include <unistd.h> +#include <signal.h> +#include <string.h> #include <security/pam_appl.h> #include <security/pam_misc.h> @@ -29,6 +31,26 @@ #define __failed(RC) ((RC) != PAM_SUCCESS) +void quit_pam(int sig); + +int conv_pam(int num_msg, const struct pam_message** msg, struct pam_response** resp, void* appdata_ptr); + + +/** + * Old signal action for SIGHUP + */ +struct sigaction signal_action_hup; + +/** + * Old signal action for SIGTERM + */ +struct sigaction signal_action_term; + +/** + * The process ID of the child process, 0 if none + */ +extern pid_t child_pid; + /** * The PAM handle */ @@ -37,7 +59,17 @@ static pam_handle_t* handle = NULL; /** * The PAM convention */ -static struct pam_conv conv = { misc_conv, NULL }; +static struct pam_conv conv = { conv_pam, NULL }; + +/** + * Whether the user was auto-authenticated + */ +static char auto_authenticated = 1; + +/** + * Function that can be used to read a passphrase from the terminal + */ +static char* (*passphrase_reader)(void) = NULL; /** @@ -64,9 +96,12 @@ static void do_pam(int rc) * * @param remote The remote computer, {@code NULL} for local login * @param username The username of the user to log in to + * @param reader Function that can be used to read a passphrase from the terminal */ -void initialise_pam(char* remote, char* username) +void initialise_pam(char* remote, char* username, char* (*reader)(void)) { + passphrase_reader = reader; + if (pam_start(remote ? "remote" : "local", username, &conv, &handle) != PAM_SUCCESS) { fprintf(stderr, "Cannot initialise PAM\n"); @@ -97,6 +132,8 @@ void verify_account_pam(void) void open_session_pam(void) { int rc; + struct sigaction signal_action; + do_pam(pam_setcred(handle, PAM_ESTABLISH_CRED)); if (__failed(rc = pam_open_session(handle, 0))) @@ -110,6 +147,14 @@ void open_session_pam(void) pam_close_session(handle, 0); do_pam(rc); } + + memset(&signal_action, 0, sizeof(signal_action)); + signal_action.sa_handler = SIG_IGN; + sigaction(SIGINT, &signal_action, NULL); + sigaction(SIGHUP, &signal_action, &signal_action_hup); + signal_action.sa_handler = quit_pam; + sigaction(SIGHUP, &signal_action, NULL); + sigaction(SIGTERM, &signal_action, &signal_action_term); } @@ -118,7 +163,81 @@ void open_session_pam(void) */ void close_session_pam(void) { + sigaction(SIGHUP, &signal_action_hup, NULL); + sigaction(SIGTERM, &signal_action_term, NULL); + pam_setcred(handle, PAM_DELETE_CRED); pam_end(handle, pam_close_session(handle, 0)); } + +/** + * Signal handler for cleanly exit PAM session + * + * @param sig The received signal + */ +void quit_pam(int sig) +{ + if (child_pid) + kill(-child_pid, sig); + if (sig == SIGTERM) + kill(-child_pid, SIGHUP); + + pam_setcred(handle, PAM_DELETE_CRED); + pam_end(handle, pam_close_session(handle, 0)); + + _exit(sig); +} + + +/** + * Perform token authentication + * + * @return Whether the user got automatically authenticated + */ +char authenticate_pam(void) +{ + int rc; + + if (__failed(rc = pam_authenticate(handle, 0))) + { + printf("Incorrect passphrase\n"); + pam_end(handle, rc); + sleep(FAILURE_SLEEP); + _exit(1); + } + + return auto_authenticated; +} + + +/** + * Callback function for converation between PAM this application + * + * @param num_msg Number of pointers in the array `msg` + * @param msg Message from PAM + * @param resp Responses to PAM for by index corresponding messages + * @param appdata_ptr (Not used) + * @return `PAM_SUCCESS`, `PAM_CONV_ERR` or `PAM_BUF_ERR` + */ +int conv_pam(int num_msg, const struct pam_message** msg, struct pam_response** resp, void* appdata_ptr) +{ + int i; + + (void) appdata_ptr; + + for (i = 0; i < num_msg; i++) + { + ((*resp) + i)->resp = NULL; + ((*resp) + i)->resp_retcode = 0; + + if ((**(msg + i)).msg_style == PAM_PROMPT_ECHO_OFF) + { + (*resp + i)->resp = passphrase_reader(); + auto_authenticated = 0; + } + } + + return PAM_SUCCESS; +} + |