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;  } | 
