diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cerberus.c | 44 | ||||
-rw-r--r-- | src/cerberus.h | 4 | ||||
-rw-r--r-- | src/pam.c | 123 | ||||
-rw-r--r-- | src/pam.h | 10 | ||||
-rw-r--r-- | src/passphrase.c | 1 |
5 files changed, 167 insertions, 15 deletions
diff --git a/src/cerberus.c b/src/cerberus.c index 06b83df..d18b690 100644 --- a/src/cerberus.c +++ b/src/cerberus.c @@ -22,13 +22,26 @@ #ifdef USE_TTY_GROUP +/** + * The group ID for the `tty` group + */ static gid_t tty_group = 0; #endif + +/** + * The user's entry in the password file + */ static struct passwd* entry; -static pid_t child_pid; +/** + * The process ID of the child process, 0 if none + */ +pid_t child_pid = 0; -void do_login(int argc, char** argv); +/** + * The passphrase + */ +char* passphrase = NULL; /** @@ -70,7 +83,6 @@ void do_login(int argc, char** argv) { char* username = NULL; char* hostname = NULL; - char* passphrase = NULL; char preserve_env = 0; char skip_auth = 0; int ret; @@ -202,18 +214,15 @@ void do_login(int argc, char** argv) username = entry->pw_name; - /* Get the passphrase, if -f has not been used */ - if (skip_auth == 0) - { - passphrase = get_passphrase(); - printf("\n"); - } + + /* Verify passphrase or other token, if -f has not been used */ + initialise_pam(hostname, username, read_passphrase); + if ((skip_auth == 0) && authenticate_pam()) + printf("(auto-authenticated)\n"); /* Passphrase entered, turn off timeout */ alarm(0); - /* TODO verify passphrase */ - /* Wipe and free the passphrase from the memory */ if ((skip_auth == 0) && passphrase) { @@ -223,7 +232,6 @@ void do_login(int argc, char** argv) free(passphrase); } - /* Reset terminal settings */ reenable_echo(); @@ -282,3 +290,15 @@ void do_login(int argc, char** argv) exec_shell(entry); } + +/** + * Read passphrase from the terminal + * + * @return The entered passphrase + */ +char* read_passphrase(void) +{ + passphrase = get_passphrase(); + return passphrase; +} + diff --git a/src/cerberus.h b/src/cerberus.h index 38d9acb..5c5a240 100644 --- a/src/cerberus.h +++ b/src/cerberus.h @@ -47,5 +47,9 @@ #endif +void do_login(int argc, char** argv); +char* read_passphrase(void); + + #endif @@ -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; +} + @@ -25,8 +25,9 @@ * * @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)); /** * Verify that the account may be used @@ -43,6 +44,13 @@ void open_session_pam(void); */ void close_session_pam(void); +/** + * Perform token authentication + * + * @return Whether the user got automatically authenticated + */ +char authenticate_pam(void); + #endif diff --git a/src/passphrase.c b/src/passphrase.c index c508b85..599d5ff 100644 --- a/src/passphrase.c +++ b/src/passphrase.c @@ -82,6 +82,7 @@ char* get_passphrase(void) /* NUL-terminate passphrase */ *(rc + len) = 0; + printf("\n"); return rc; } |