From 55dfb26a7c5c4db0d8c23189c838b1a4b992c657 Mon Sep 17 00:00:00 2001 From: Philip Prindeville Date: Thu, 8 Dec 2016 18:17:56 -0700 Subject: [PATCH] Add support for multiplexed sessions Add method for setting whether session is multiplexed or not; mark packet header flags appropriately; reset timeouts on connection when we have received a response (since our request has been answered, no more data will be read or written for now). --- libtac/include/libtac.h | 3 +++ libtac/lib/acct_s.c | 3 ++- libtac/lib/authen_s.c | 5 ++-- libtac/lib/author_s.c | 3 ++- libtac/lib/cont_s.c | 5 ++-- libtac/lib/header.c | 3 ++- libtac/lib/session.c | 8 +++++- libtac/lib/wrappers.c | 42 ++++++++++++++++++++++++++--- tacc.c | 58 ++++++++++------------------------------- 9 files changed, 73 insertions(+), 57 deletions(-) diff --git a/libtac/include/libtac.h b/libtac/include/libtac.h index 925357f1..8f2c9fbb 100644 --- a/libtac/include/libtac.h +++ b/libtac/include/libtac.h @@ -160,6 +160,7 @@ struct tac_session { const char *tac_secret; uint32_t tac_session_id; bool tac_encryption; + bool tac_multiplex; uint8_t tac_priv_lvl; uint8_t tac_authen_method; uint8_t tac_authen_service; @@ -183,6 +184,8 @@ struct tac_session *tac_session_alloc_extra(unsigned); void tac_session_set_authen_type(struct tac_session *, uint8_t); void tac_session_set_secret(struct tac_session *, const char *); void tac_session_set_timeout(struct tac_session *, unsigned); +void tac_session_set_multiplex(struct tac_session *, bool); +void tac_session_reset_timeouts(struct tac_session *, bool); void tac_session_set_response(struct tac_session *, response_cb_t); void tac_session_set_oob(struct tac_session *, oob_cb_t); struct cb_ctx *tac_session_get_context(struct tac_session *); diff --git a/libtac/lib/acct_s.c b/libtac/lib/acct_s.c index d7e88877..5bc6e511 100644 --- a/libtac/lib/acct_s.c +++ b/libtac/lib/acct_s.c @@ -83,7 +83,8 @@ void tac_acct_send_pkt(struct tac_session *sess, u_char type, th->version = TAC_PLUS_VER_0; th->type = TAC_PLUS_ACCT; th->seq_no = ++sess->seq_no; - th->encryption = sess->tac_encryption ? TAC_PLUS_ENCRYPTED_FLAG : TAC_PLUS_UNENCRYPTED_FLAG; + th->encryption = sess->tac_encryption ? TAC_PLUS_ENCRYPTED_FLAG : TAC_PLUS_UNENCRYPTED_FLAG + | (sess->tac_multiplex ? TAC_PLUS_SINGLE_CONNECT_FLAG : 0); th->session_id = htonl(sess->tac_session_id); th->datalength = htonl(pkt_total - TAC_PLUS_HDR_SIZE); diff --git a/libtac/lib/authen_s.c b/libtac/lib/authen_s.c index 8214a4fd..e4f9042a 100644 --- a/libtac/lib/authen_s.c +++ b/libtac/lib/authen_s.c @@ -152,9 +152,8 @@ void tac_authen_send_pkt(struct tac_session *sess, } th->type = TAC_PLUS_AUTHEN; th->seq_no = ++sess->seq_no; - th->encryption = - sess->tac_encryption ? - TAC_PLUS_ENCRYPTED_FLAG : TAC_PLUS_UNENCRYPTED_FLAG; + th->encryption = (sess->tac_encryption ? TAC_PLUS_ENCRYPTED_FLAG : TAC_PLUS_UNENCRYPTED_FLAG) + | (sess->tac_multiplex ? TAC_PLUS_SINGLE_CONNECT_FLAG : 0); th->session_id = htonl(sess->tac_session_id); th->datalength = htonl(pkt_total - TAC_PLUS_HDR_SIZE); diff --git a/libtac/lib/author_s.c b/libtac/lib/author_s.c index 81c3e776..4109a8ec 100644 --- a/libtac/lib/author_s.c +++ b/libtac/lib/author_s.c @@ -67,7 +67,8 @@ void tac_author_send_pkt(struct tac_session *sess, th->version = TAC_PLUS_VER_0; th->type = TAC_PLUS_AUTHOR; th->seq_no = ++sess->seq_no; - th->encryption = sess->tac_encryption ? TAC_PLUS_ENCRYPTED_FLAG : TAC_PLUS_UNENCRYPTED_FLAG; + th->encryption = (sess->tac_encryption ? TAC_PLUS_ENCRYPTED_FLAG : TAC_PLUS_UNENCRYPTED_FLAG) + | (sess->tac_multiplex ? TAC_PLUS_SINGLE_CONNECT_FLAG : 0); th->session_id = htonl(sess->tac_session_id); th->datalength = htonl(pkt_total - TAC_PLUS_HDR_SIZE); diff --git a/libtac/lib/cont_s.c b/libtac/lib/cont_s.c index a685ff7c..89e1f317 100644 --- a/libtac/lib/cont_s.c +++ b/libtac/lib/cont_s.c @@ -56,9 +56,8 @@ void tac_cont_send_pkt(struct tac_session *sess, const char *pass, th->version = TAC_PLUS_VER_0; th->type = TAC_PLUS_AUTHEN; th->seq_no = ++sess->seq_no; - th->encryption = - sess->tac_encryption ? - TAC_PLUS_ENCRYPTED_FLAG : TAC_PLUS_UNENCRYPTED_FLAG; + th->encryption = (sess->tac_encryption ? TAC_PLUS_ENCRYPTED_FLAG : TAC_PLUS_UNENCRYPTED_FLAG) + | (sess->tac_multiplex ? TAC_PLUS_SINGLE_CONNECT_FLAG : 0); th->session_id = htonl(sess->tac_session_id); th->datalength = htonl(pkt_total - TAC_PLUS_HDR_SIZE); diff --git a/libtac/lib/header.c b/libtac/lib/header.c index 343a6a09..89c71e79 100644 --- a/libtac/lib/header.c +++ b/libtac/lib/header.c @@ -47,7 +47,8 @@ HDR *_tac_req_header(struct tac_session *sess, u_char type, bool cont_session) { /* preset some packet options in header */ th->type=type; th->seq_no=++sess->seq_no; - th->encryption=TAC_PLUS_ENCRYPTED_FLAG; + th->encryption=(sess->tac_encryption ? TAC_PLUS_ENCRYPTED_FLAG : TAC_PLUS_UNENCRYPTED_FLAG) + | (sess->tac_multiplex ? TAC_PLUS_SINGLE_CONNECT_FLAG : 0); /* make session_id from pseudo-random number */ if (!cont_session) { diff --git a/libtac/lib/session.c b/libtac/lib/session.c index 9cb5945b..fb316ccd 100644 --- a/libtac/lib/session.c +++ b/libtac/lib/session.c @@ -36,7 +36,7 @@ tac_session_alloc_extra(unsigned n) sess->tac_timeout = 5; sess->tac_secret = NULL; sess->tac_session_id = magic(); - sess->tac_encryption = false; + sess->tac_encryption = sess->tac_multiplex = false; sess->tac_priv_lvl = TAC_PLUS_PRIV_LVL_MIN; sess->tac_authen_service = TAC_PLUS_AUTHEN_SVC_PPP; sess->tac_authen_method = TAC_PLUS_AUTHEN_METH_TACACSPLUS; @@ -80,6 +80,12 @@ tac_session_set_timeout(struct tac_session *sess, unsigned timeout) sess->tac_timeout = timeout; } +void +tac_session_set_multiplex(struct tac_session *sess, bool multiplex) +{ + sess->tac_multiplex = multiplex; +} + void tac_session_set_response(struct tac_session *sess, response_cb_t cb) { diff --git a/libtac/lib/wrappers.c b/libtac/lib/wrappers.c index 65ce8df8..fb21d63d 100644 --- a/libtac/lib/wrappers.c +++ b/libtac/lib/wrappers.c @@ -99,6 +99,25 @@ tac_event_loop_global_shutdown(void) #endif } +void tac_session_reset_timeouts(struct tac_session *sess, bool on) +{ + struct timeval tv = { sess->tac_timeout, 0 }; + + TACDEBUG(LOG_DEBUG, "session %p reset_timeouts %u %s", sess, sess->tac_timeout, (on ? "on" : "off")); + + if (!sess->bufev) + return; + + /* nothing will be enabled if we haven't yet connected... */ + if (bufferevent_get_enabled(sess->bufev) == 0) + return; + + if (on) + bufferevent_set_timeouts(sess->bufev, &tv, &tv); + else + bufferevent_set_timeouts(sess->bufev, NULL, NULL); +} + static void eventcb(struct bufferevent *bev, short events, void *ptr) { struct cb_ctx *ctx = (struct cb_ctx *)ptr; @@ -125,6 +144,8 @@ static void eventcb(struct bufferevent *bev, short events, void *ptr) if (sess->oob_cb) { if (events & BEV_EVENT_CONNECTED) { TACDEBUG(LOG_DEBUG, "session %p connected", sess); + /* change for setup timeout to read/write timeout values */ + tac_session_reset_timeouts(sess, true); (sess->oob_cb)(sess, &sess->context, CONNECTED); } if (events & BEV_EVENT_ERROR) { @@ -214,10 +235,13 @@ static void readcb(struct bufferevent *bev, void *ptr) /* copy out... */ i = evbuffer_remove(evbuf, pkt, length); - if (i < 0 || (unsigned) i != n) - TACDEBUG(LOG_DEBUG, "%s: evbuffer_remove want %ld got %d", __FUNCTION__, n, i); + if (i < 0 || (unsigned) i != length) + TACDEBUG(LOG_DEBUG, "%s: evbuffer_remove want %u got %d", __FUNCTION__, length, i); - tac_parse_pkt(ctx->sess, ctx, pkt, length); + /* turn off timeouts */ + tac_session_reset_timeouts(sess, false); + + tac_parse_pkt(sess, ctx, pkt, ((i > 0) ? i : 0)); free(pkt); } @@ -292,6 +316,9 @@ tac_authen_send_ev(struct tac_session *sess, /* generate the packet */ tac_authen_send_pkt(sess, user, pass, tty, r_addr, action, &pkt, &pkt_total); + /* if reusing connection, reset timeouts */ + tac_session_reset_timeouts(sess, true); + /* * make evbuffer wrap around our packet, and call cleanup (free) * when done @@ -328,6 +355,9 @@ tac_author_send_ev(struct tac_session *sess, /* generate the packet */ tac_author_send_pkt(sess, user, tty, r_addr, attr, &pkt, &pkt_total); + /* if reusing connection, reset timeouts */ + tac_session_reset_timeouts(sess, true); + /* * make evbuffer wrap around our packet, and call cleanup (free) * when done @@ -364,6 +394,9 @@ tac_acct_send_ev(struct tac_session *sess, /* generate the packet */ tac_acct_send_pkt(sess, type, user, tty, r_addr, attr, &pkt, &pkt_total); + /* if reusing connection, reset timeouts */ + tac_session_reset_timeouts(sess, true); + /* * make evbuffer wrap around our packet, and call cleanup (free) * when done @@ -397,6 +430,9 @@ tac_cont_send_ev(struct tac_session *sess, const char *pass) { /* generate the packet */ tac_cont_send_pkt(sess, pass, &pkt, &pkt_total); + /* if reusing connection, reset timeouts */ + tac_session_reset_timeouts(sess, true); + /* * make evbuffer wrap around our packet, and call cleanup (free) * when done diff --git a/tacc.c b/tacc.c index 1f714767..b57770a8 100644 --- a/tacc.c +++ b/tacc.c @@ -280,29 +280,31 @@ int main(int argc, char **argv) { sess = tac_session_alloc(); + ret = tac_connect_single(sess, tac_server, NULL, 60); + if (ret < 0) { + if (!quiet) + printf("Error connecting to TACACS+ server: %m\n"); + exit(EXIT_ERR); + } + + tac_session_set_secret(sess, tac_secret); tac_session_set_authen_type(sess, tac_get_authen_type(tac_login)); + tac_session_set_multiplex(sess, true); + if (do_authen) authenticate(tac_server, tac_secret, user, pass, tty, remote_addr); + /* we no longer need the password in our address space */ + bzero(pass, strlen(pass)); + pass = NULL; + if (do_author) { /* authorize user */ struct tac_attrib *attr = NULL; tac_add_attrib(&attr, "service", service); tac_add_attrib(&attr, "protocol", protocol); - tac_session_new_session_id(sess); - tac_session_reset_seq(sess); - - ret = tac_connect_single(sess, tac_server, NULL, 60); - if (ret < 0) { - if (!quiet) - printf("Error connecting to TACACS+ server: %m\n"); - exit(EXIT_ERR); - } - - tac_session_set_secret(sess, tac_secret); - tac_author_send(sess, user, tty, remote_addr, attr); tac_author_read(sess, &arep); @@ -319,10 +321,6 @@ int main(int argc, char **argv) { tac_free_attrib(&attr); } - /* we no longer need the password in our address space */ - bzero(pass, strlen(pass)); - pass = NULL; - if (do_account) { /* start accounting */ struct tac_attrib *attr = NULL; @@ -334,18 +332,6 @@ int main(int argc, char **argv) { tac_add_attrib(&attr, "service", service); tac_add_attrib(&attr, "protocol", protocol); - tac_session_new_session_id(sess); - tac_session_reset_seq(sess); - - ret = tac_connect_single(sess, tac_server, NULL, 60); - if (ret < 0) { - if (!quiet) - printf("Error connecting to TACACS+ server: %m\n"); - exit(EXIT_ERR); - } - - tac_session_set_secret(sess, tac_secret); - tac_acct_send(sess, TAC_PLUS_ACCT_FLAG_START, user, tty, remote_addr, attr); @@ -425,18 +411,6 @@ int main(int argc, char **argv) { sprintf(buf, "%hu", task_id); tac_add_attrib(&attr, "task_id", buf); - tac_session_new_session_id(sess); - tac_session_reset_seq(sess); - - ret = tac_connect_single(sess, tac_server, NULL, 60); - if (ret < 0) { - if (!quiet) - printf("Error connecting to TACACS+ server: %m\n"); - exit(EXIT_ERR); - } - - tac_session_set_secret(sess, tac_secret); - tac_acct_send(sess, TAC_PLUS_ACCT_FLAG_STOP, user, tty, remote_addr, attr); ret = tac_acct_read(sess, &arep); @@ -447,8 +421,6 @@ int main(int argc, char **argv) { } else if (!login_mode && !quiet) printf("Accounting: STOP OK\n"); - tac_close(sess); - tac_free_attrib(&attr); } @@ -519,8 +491,6 @@ void authenticate(const struct addrinfo *tac_server, const char *tac_secret, if (!quiet) printf("Authentication OK\n"); syslog(LOG_INFO, "authentication OK for %s", user); - - tac_close(sess); } void showusage(char *progname) {