From 9947bd3dbaed3777c16227c80bde5c4698934630 Mon Sep 17 00:00:00 2001 From: Anthony DeRobertis Date: Mon, 8 Jun 2020 13:11:18 -0400 Subject: [PATCH] Move pam session start to after VPN up PAM session start needs only if, and only once, the VPN is fully up. Want to only have started sessions when it has fully worked. Add another state to the pam_conv sort-of state machine for makeing the xauth success callback, before starting to wait for VPN up to start the PAM session. Remember that st_xauth is on the phase1 state, not phase2. Next commit will handle downing the VPN if pam session start fails. --- programs/pluto/ikev1_quick.c | 15 ++++++++ programs/pluto/pam_conv.c | 69 +++++++++++++++++++++--------------- programs/pluto/pam_conv.h | 13 ++++--- programs/pluto/xauth.c | 1 + 4 files changed, 64 insertions(+), 34 deletions(-) diff --git a/programs/pluto/ikev1_quick.c b/programs/pluto/ikev1_quick.c index 7bb4a278d54..e043c027347 100644 --- a/programs/pluto/ikev1_quick.c +++ b/programs/pluto/ikev1_quick.c @@ -83,6 +83,8 @@ #include "alg_info.h" #include "ip_address.h" +#include "pam_conv.h" /* needs struct xauth */ + #include /* accept_PFS_KE @@ -1987,5 +1989,18 @@ stf_status quick_inI2(struct state *st, struct msg_digest *md) } } + /* + * Tell the xauth thread it's finally time to start the session for + * e.g., billing. We need to find the phase1 state, though, since + * that's where the xauth is. + */ + struct state *p1st = state_with_serialno(st->st_clonedfrom); + if (!p1st || !p1st->st_xauth) { + delete_ipsec_sa(st); + return STF_FAIL; + + } + atomic_flag_clear(&p1st->st_xauth->vpn_still_starting); + return STF_OK; } diff --git a/programs/pluto/pam_conv.c b/programs/pluto/pam_conv.c index 1108e2c2a4c..5900c3caa39 100644 --- a/programs/pluto/pam_conv.c +++ b/programs/pluto/pam_conv.c @@ -43,7 +43,7 @@ static char *pam_state_enum[] = { - "PAM_AUTH","PAM_SESSION_START", "PAM_SESSION_END", "PAM_TERM", "PAM_STATE_UNKNOWN", "PAM_DO_NOTHING" + "PAM_AUTH", "PAM_CALLBACK", "PAM_SESSION_START", "PAM_SESSION_END", "PAM_TERM", "PAM_STATE_UNKNOWN", "PAM_DO_NOTHING" }; static char *pam_result_state_enum[] = { "PAM_AUTH_SUCCESS", "PAM_AUTH_FAIL", "PAM_SESSION_START_SUCCESS", "PAM_SESSION_START_FAIL", "PAM_SESSION_END_SUCCESS", "PAM_SESSION_END_FAIL", "PAM_TERM_SUCCESS", "PAM_TERM_FAIL", "PAM_RESULT_UNKNOWN" @@ -223,7 +223,7 @@ void *pam_thread(void *parg) if (retval == PAM_SUCCESS) { /* do promotion to session start */ ptr_xauth->ptarg.pam_state = PAM_AUTH_SUCCESS; - ptr_xauth->ptarg.pam_do_state = PAM_SESSION_START; + ptr_xauth->ptarg.pam_do_state = PAM_CALLBACK; break; // break out of pam_acct_mgmt loop @@ -255,41 +255,52 @@ void *pam_thread(void *parg) } } + } else if(ptr_xauth->ptarg.pam_do_state == PAM_CALLBACK) { + log_pam_step((struct pam_thread_arg *)&ptr_xauth->ptarg, "making xauth callback"); - } else if(ptr_xauth->ptarg.pam_do_state == PAM_SESSION_START) { - - for (int i = 0; i < 5; i++) { - what = "pam_open_session"; - retval = pam_open_session(pamh, PAM_SILENT); - log_pam_step((struct pam_thread_arg *)&ptr_xauth->ptarg, what); - if (retval == PAM_SUCCESS) { + struct state *st = state_with_serialno(ptr_xauth->serialno); + if(st != NULL) { + so_serial_t old_state = push_cur_state(st); - bool success = TRUE; - struct state *st = state_with_serialno(ptr_xauth->serialno); - //passert(st != NULL); - if(st != NULL) { - so_serial_t old_state = push_cur_state(st); + libreswan_log("XAUTH: #%lu: completed for user '%s' (waiting for VPN up for session_start)", + ptr_xauth->ptarg.st_serialno, ptr_xauth->ptarg.name); - libreswan_log("XAUTH: #%lu: completed for user '%s' with status %s ::: pam_open_session", - ptr_xauth->ptarg.st_serialno, ptr_xauth->ptarg.name, - success ? "SUCCESSS" : "FAILURE"); + ptr_xauth->callback(st, ptr_xauth->ptarg.name, TRUE); + pop_cur_state(old_state); + } + ptr_xauth->ptarg.pam_do_state = PAM_SESSION_START; + } else if(ptr_xauth->ptarg.pam_do_state == PAM_SESSION_START) { + if (atomic_flag_test_and_set(&ptr_xauth->vpn_still_starting)) { + log_pam_step(&ptr_xauth->ptarg, "waiting for VPN up"); + } else { + for (int i = 0; i < 5; i++) { + what = "pam_open_session"; + retval = pam_open_session(pamh, PAM_SILENT); + log_pam_step((struct pam_thread_arg *)&ptr_xauth->ptarg, what); + if (retval == PAM_SUCCESS) { + + bool success = TRUE; + struct state *st = state_with_serialno(ptr_xauth->serialno); + //passert(st != NULL); + if(st != NULL) { + libreswan_log("XAUTH: #%lu: completed for user '%s' with status %s ::: pam_open_session", + ptr_xauth->ptarg.st_serialno, ptr_xauth->ptarg.name, + success ? "SUCCESSS" : "FAILURE"); - ptr_xauth->callback(st, ptr_xauth->ptarg.name, success); - pop_cur_state(old_state); - } + } - ptr_xauth->ptarg.pam_state = PAM_SESSION_START_SUCCESS; - ptr_xauth->ptarg.pam_do_state = PAM_DO_NOTHING; + ptr_xauth->ptarg.pam_state = PAM_SESSION_START_SUCCESS; + ptr_xauth->ptarg.pam_do_state = PAM_DO_NOTHING; - break; - } else { - ptr_xauth->ptarg.pam_state = PAM_SESSION_START_FAIL; - ptr_xauth->ptarg.pam_do_state = PAM_TERM; + break; + } else { + ptr_xauth->ptarg.pam_state = PAM_SESSION_START_FAIL; + ptr_xauth->ptarg.pam_do_state = PAM_TERM; + /* FIXME: Need to kill the VPN here */ + } } + /* Failed pam_open_session */ } - /* Failed pam_open_session */ - - } else if(ptr_xauth->ptarg.pam_do_state == PAM_SESSION_END) { for (int i = 0; i < 5; i++) { diff --git a/programs/pluto/pam_conv.h b/programs/pluto/pam_conv.h index 7ca240b2a10..452bd5d59f2 100644 --- a/programs/pluto/pam_conv.h +++ b/programs/pluto/pam_conv.h @@ -19,6 +19,7 @@ //#include "xauth.h" #include "constants.h" +#include struct state; typedef void xauth_callback_t( @@ -30,11 +31,12 @@ struct app_pam_data { const char* password; }; enum pam_state_t { PAM_AUTH = 0, - PAM_SESSION_START = 1, - PAM_SESSION_END = 2, - PAM_TERM = 3, - PAM_STATE_UNKNOWN = 4, - PAM_DO_NOTHING = 5 + PAM_CALLBACK = 1, + PAM_SESSION_START = 2, + PAM_SESSION_END = 3, + PAM_TERM = 4, + PAM_STATE_UNKNOWN = 5, + PAM_DO_NOTHING = 6 }; @@ -75,6 +77,7 @@ struct xauth { xauth_callback_t *callback; bool abort; pid_t child; + atomic_flag vpn_still_starting; }; extern bool do_pam_authentication(struct pam_thread_arg *arg); diff --git a/programs/pluto/xauth.c b/programs/pluto/xauth.c index 235fd81bf85..24dbd3dcb28 100644 --- a/programs/pluto/xauth.c +++ b/programs/pluto/xauth.c @@ -52,6 +52,7 @@ void xauth_start_pam_thread(struct state *st, xauth->callback = callback; xauth->serialno = serialno; + atomic_flag_test_and_set(&xauth->vpn_still_starting); gettimeofday(&xauth->tv0, NULL); /* fill in pam_thread_arg with info for the child process */