From 8c1be86c0ba27f1683fb326fb709d1c4e894bb89 Mon Sep 17 00:00:00 2001 From: Matt Addison Date: Mon, 13 May 2019 16:47:05 -0400 Subject: [PATCH] support enable pre authorization check --- tacacs-F4.0.4.28/config.c | 30 +++++++++++++++++-- tacacs-F4.0.4.28/enable.c | 24 +++++++++++++++ tacacs-F4.0.4.28/parse.h | 3 ++ tacacs-F4.0.4.28/programs.c | 59 +++++++++++++++++++++++++++++++++++++ tacacs-F4.0.4.28/tac_plus.h | 1 + 5 files changed, 115 insertions(+), 2 deletions(-) diff --git a/tacacs-F4.0.4.28/config.c b/tacacs-F4.0.4.28/config.c index b67daec..663cb0a 100644 --- a/tacacs-F4.0.4.28/config.c +++ b/tacacs-F4.0.4.28/config.c @@ -102,9 +102,10 @@ #endif opap = cleartext | global = cleartext | - msg = + msg = | before authorization = | - after authorization = + after authorization = | + before enable = := | @@ -186,6 +187,7 @@ typedef struct user { char *enable; /* user enable pwd */ int noenablepwd; /* user requires no enable password */ char *enableacl; /* hosts (NASs) to allow/deny enabling */ + char *before_enable; /* command to run before enabling */ # endif #endif char *global; /* password to use if none set */ @@ -1124,10 +1126,31 @@ parse_user(void) case S_before: sym_get(); +#ifdef UENABLE + switch (sym_code) { + case S_authorization: + sym_get(); + if (user->before_author) + free(user->before_author); + user->before_author = tac_strdup(sym_buf); + break; + case S_enable: + sym_get(); + if (user->before_enable) + free(user->before_enable); + user->before_enable = tac_strdup(sym_buf); + break; + default: + parse_error("expecting '%s' or '%s' but found '%s' on line %d", + codestring(S_authorization), codestring(S_enable), sym_buf, sym_line); + return(1); + } +#else // UENABLE parse(S_authorization); if (user->before_author) free(user->before_author); user->before_author = tac_strdup(sym_buf); +#endif // UENABLE sym_get(); continue; @@ -1784,6 +1807,9 @@ get_value(USER *user, int field) case S_enableacl: v.pval = user->enableacl; break; + case S_beforeenable: + v.pval = user->before_enable; + break; # endif #endif diff --git a/tacacs-F4.0.4.28/enable.c b/tacacs-F4.0.4.28/enable.c index ae9d8ff..7325194 100644 --- a/tacacs-F4.0.4.28/enable.c +++ b/tacacs-F4.0.4.28/enable.c @@ -124,6 +124,9 @@ enable_fn(struct authen_data *data) char *passwd; struct private_data *p; int pwlen; +#ifdef UENABLE + char *cmd; +#endif p = (struct private_data *)data->method_data; @@ -180,6 +183,27 @@ enable_fn(struct authen_data *data) data->status = TAC_PLUS_AUTHEN_STATUS_PASS; break; } + cmd = cfg_get_pvalue(data->NAS_id->username, TAC_IS_USER, + S_beforeenable, TAC_PLUS_RECURSE); + if (cmd) { + // check CMD + int status; + char error_str[255]; + int error_len = 255; + status = call_pre_enable(cmd, data, error_str, error_len); + switch (status) { + case 0: /* Permit */ + case 2: /* Use replacement AV pairs from program as final result */ + break; + case 1: /* Deny */ + case 3: /* deny, but return attributes and server-msg to NAS */ + default: + report(LOG_INFO, "setting authen_status_fail %d", status); + data->server_msg = tac_strdup("Denied due to enable authentication."); + data->status = TAC_PLUS_AUTHEN_STATUS_FAIL; + return(0); + } + } #endif /* Request a password */ data->flags = TAC_PLUS_AUTHEN_FLAG_NOECHO; diff --git a/tacacs-F4.0.4.28/parse.h b/tacacs-F4.0.4.28/parse.h index b3a164f..1a17b1f 100644 --- a/tacacs-F4.0.4.28/parse.h +++ b/tacacs-F4.0.4.28/parse.h @@ -98,3 +98,6 @@ #define S_writetimeout 55 #define S_accepttimeout 56 #define S_logauthor 57 +#ifdef UENABLE +#define S_beforeenable 58 +#endif diff --git a/tacacs-F4.0.4.28/programs.c b/tacacs-F4.0.4.28/programs.c index 1e9e8b4..dbac33d 100644 --- a/tacacs-F4.0.4.28/programs.c +++ b/tacacs-F4.0.4.28/programs.c @@ -397,6 +397,65 @@ read_args(int n, int fd) return(out); } +/* + * Do variable interpolation on a string, then invoke it as a shell command. + * Write a faked set of AV pairs to standard input of the command and + * disregard its standard output. Return the commands final status + * when it terminates + */ +int +call_pre_enable(char *string, struct authen_data *authen_data, char *error, int err_len) +{ + /*char **new_args;*/ + int readfd, writefd, errorfd; + int status;/*, i;*/ + char *cmd = NULL; + char fakeoutput[] = "service=shell\ncmd=enable\ncmd-arg=\n"; + struct author_data data; +#if HAVE_PID_T + pid_t pid; +#else + int pid; +#endif + data.id = authen_data->NAS_id; + data.authen_method = AUTHEN_METH_ENABLE; + data.authen_type = authen_data->type; + data.service = authen_data->service; + data.status = authen_data->status; + + cmd = substitute(string, &data); + pid = my_popen(cmd, &readfd, &writefd, &errorfd); + memset(error, '\0', err_len); + free(cmd); + + if (pid < 0) { + close_fds(readfd, writefd, errorfd); + return(1); /* deny */ + } + + /* write a fake enable input */ + write(writefd, fakeoutput, sizeof(fakeoutput) - 1); + close(writefd); + writefd = -1; + + /*new_args = read_args(0, readfd);*/ + + read_string(errorfd, error, err_len); + if (error[0] != '\0') { + report(LOG_ERR, "Error from program (%d): \"%s\" ", + strlen(error), error); + } + + /* count the args */ + /*for (i = 0; new_args[i]; i++)*/ + /* NULL stmt */ ; + + status = waitfor(pid); + close_fds(readfd, writefd, errorfd); + return(status); +} + + /* * Do variable interpolation on a string, then invoke it as a shell command. * Write an appropriate set of AV pairs to standard input of the command and diff --git a/tacacs-F4.0.4.28/tac_plus.h b/tacacs-F4.0.4.28/tac_plus.h index afe1b05..9b1527e 100644 --- a/tacacs-F4.0.4.28/tac_plus.h +++ b/tacacs-F4.0.4.28/tac_plus.h @@ -464,6 +464,7 @@ int keycode(char *); void parser_init(void); /* programs.c */ +int call_pre_enable(char *, struct authen_data *, char *, int); int call_pre_process(char *, struct author_data *, char ***, int *, char *, int); int call_post_process(char *, struct author_data *, char ***, int *);