/* * Copyright (c) 1996-2007, OpenFWTK Development Group * All rights reserved. See LICENSE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "firewall.h" #include "firewall2.h" #define UNIX_PATH_MAX 100 #define MAX_STR_LEN 500 #define PWD_LEN 7 #define ESC_SEQ_REQ "\033[5n" #define ESC_SEQ_BAD "\033[1n" #define ESC_SEQ_LEN sizeof(ESC_SEQ_REQ) - 1 #define SOCK_REQ -1 #define AUTH_INITIAL_TIMEOUT 50 #define AUTH_NEXT_TIMEOUT 50 #define RESEND_TIMEOUT 1 #define LOCK_TIMEOUT 1 #define PROMPT_STR "auth console>" #define AUTH_CONS_NAME "authcons" #define AUTH_KEEPALIVE 0 #define AUTH_ASK 1 #define AUTH_PWD 2 #define MAX_AUTH_HISTORY 30 #include "../auth.h" extern size_t strlcat(char*,const char*,size_t); extern size_t strlcpy(char*,const char*,size_t); typedef struct { char req_str[BUFSIZ + 1]; char accepted; int auth_type; char pwd[BUFSIZ + 1]; } t_auth_rec; t_auth_rec *auth_rec[MAX_AUTH_HISTORY + 1]; struct sockaddr_un sn; int auth_req_flag = 0; int auth_sock; int auth_type = AUTH_KEEPALIVE; int nauth = 0, nauth_accepted = 0, nauth_rejected = 0; int curr_auth = 0, start_history_index = 0; WINDOW *authframewin = NULL, *conswin = NULL, *authwin = NULL; WINDOW *statusline = NULL; void *authsrv_comm_f(void * arg); int gets_sock(char *buf, int maxlen, int s); void showstatistic(); void showsettings(); extern void* xmalloc(size_t); int makeup_sockname(char sockname[], int max_name_len, char *auth_dir, char *host_addr, char *user_name); int auth_checked(char [], char [], int); void set_auth_req_occured(int value); int auth_req_occured(); int authreq_dlg(char req_details[]); int create_windows(); void deletewindows(); int console_command(char buf[]); int socket_request(int s); void timeout_sig(int signum); int gets_signalled(char *buf, int maxlen); void auth_req_sig(int sugnum); int auth_console(char host_addr[], char user_name[]); void makeup_auth_resp(char buf[], int auth_type, char pwd_buf[]); void generate_pwd(char buf[]); void showusage(char *usage); void deletehistory(); int enargv(char *,char **,int,char *,int); static int f_help(); static int f_quit(); static int f_auth(); static int f_history(); typedef struct { char *cnam; char *help; int (*cfun)(); } Cmd; static Cmd ctab[] = { {"quit", "quit\n", f_quit, }, {"exit", "exit\n", f_quit, }, {"help", "help\n", f_help, }, {"auth", "auth [password]\n", f_auth, }, {"history", "history\n", f_history, }, {"?", "?\n", f_help, }, {0, 0, 0 }, }; static Cmd * find_command(); int should_exit = 0; sig_atomic_t continue_timer = 0; int auth_console(char host_addr[], char user_name[]) { char *auth_dir = AUTHSRV_SOCK_PATH; char buf[BUFSIZ + 1] = ""; int seed; int i; int ret_val; seed = (int)time(NULL); srand(seed); for(i=0; i 0) { if((ret_val = sogets(auth_fd, buf, sizeof(buf) - 1)) > 0) { buf[ret_val] = '\0'; req_num++; if(!strncmp(buf, "auth", 4)) { auth_rec[curr_auth] = (t_auth_rec *)xmalloc(sizeof(t_auth_rec)); *(auth_rec[curr_auth]->pwd) = '\0'; auth_rec[curr_auth]->auth_type = auth_type; if(auth_checked(buf, auth_rec[curr_auth]->req_str, sizeof(auth_rec[curr_auth]->req_str))) { nauth_accepted++; auth_rec[curr_auth]->accepted = 'y'; if(auth_type & AUTH_PWD) { if (!*pwd_buf) { generate_pwd(pwd_buf); strlcpy(auth_rec[curr_auth]->pwd, pwd_buf, BUFSIZ); } strlcpy(buf, " Session pwd: ", BUFSIZ); strlcat(buf, pwd_buf, BUFSIZ); waddstr(authwin, buf); } else waddstr(authwin, " Accepted."); makeup_auth_resp(buf, auth_type, pwd_buf); syslog(LOG_NOTICE, "authcons: auth request has been accepted."); } else { nauth_rejected++; auth_rec[curr_auth]->accepted = 'n'; waddstr(authwin, " Rejected."); syslog(LOG_NOTICE, "authcons: auth request has been rejected."); strlcpy(buf, "reject", sizeof(buf)); } nauth++; if(++curr_auth >= MAX_AUTH_HISTORY) curr_auth = 0; if(auth_rec[curr_auth]) { free(auth_rec[curr_auth]); auth_rec[curr_auth]=NULL; } if(curr_auth == start_history_index) start_history_index++; if(start_history_index >= MAX_AUTH_HISTORY) start_history_index = 0; if(sosay(auth_fd, buf)) { waddstr(authwin, "error while writing to the socket"); perror("write (socket)"); syslog(LOG_ERR, "fwtksyserr: error while writing to the socket: %s", strerror(errno)); } } else { waddstr(authwin, "Incorrect request from the auth server\n") ; syslog(LOG_ERR, "fwtksyserr: incorrect request from the auth server: %s", buf) ; } wrefresh(authwin); } else if(ret_val < 0) { perror("read (socket)"); syslog(LOG_ERR, "fwtksyserr: error while reading from the socket: %s", strerror(errno)); } } else if(auth_fd < 0) { perror("accept"); syslog(LOG_ERR, "fwtksyserr: error while accepting a connection to the socket: %s", strerror(errno)); } close(auth_fd); return req_num; } int auth_checked(char req[], char req_info[], int max_len) { char buf[ESC_SEQ_LEN + 1]; int i; int c; int ret_val; char req_details[BUFSIZ]; char proxy_name[BUFSIZ] = ""; char ciaddr[BUFSIZ] = ""; char *user_name; char *usercomment; char *p; char *timestamp[MAX_STR_LEN]; time_t time_val; int tmp_y, tmp_x; if((user_name = index(req, ' '))) { strtrm(++user_name); usercomment = index(user_name, ' '); strncpy(req_info, user_name, max_len); if(usercomment) { *usercomment++ = '\0'; strtrm(usercomment); if((usercomment = index(usercomment, '\''))) if(index(++usercomment, '\'')) *(index(usercomment, '\'')) = '\0'; if(!usercomment) waddstr(authwin, "\nAuth req format error"); else { strtrm(usercomment); if ((p = rindex(usercomment,'/')) != (char *)0) strlcpy(ciaddr,p+1,sizeof(ciaddr)); else { strlcpy(ciaddr,"unknown",sizeof(ciaddr)); waddstr(authwin, "\nAuth req format error"); } strlcpy(proxy_name,usercomment,sizeof(proxy_name)); if ((p = index(proxy_name,' ')) != (char *)0) *p= '\0'; } } else { strlcpy(proxy_name,"unknown",sizeof(proxy_name)); strlcpy(ciaddr,"unknown",sizeof(ciaddr)); waddstr(authwin, "\nAuth req format error"); } } else { waddstr(authwin, "\nAuth req format error"); } if(strlen(user_name) == 0 || strlen(ciaddr) == 0) { waddstr(authwin, "\nAuth req format error"); } time(&time_val); strftime((char *)timestamp, sizeof(timestamp), "%m.%d.%Y", localtime(&time_val)); snprintf(req_details,sizeof(req_details),"%s: Auth req for: %s@%s (via %s).", (char *)timestamp, user_name, ciaddr, proxy_name); waddstr(authwin, "\n"); waddstr(authwin, req_details); wrefresh(authwin); /* savetty(); */ flushinp(); if(auth_type & AUTH_ASK) { ret_val = authreq_dlg(req_details); touchwin(authframewin); wrefresh(authframewin); touchwin(conswin); wrefresh(conswin); /* resetty(); */ return ret_val; } getyx(authwin, tmp_y, tmp_x); move(tmp_y + 1, tmp_x + 1); noecho(); putp(ESC_SEQ_REQ); /* refresh(); */ ret_val=0; if(ret_val < 0) { perror("write (terminal)"); syslog(LOG_ERR, "authconserr: error while writing ESC-sequence requesting terminal status: %s", strerror(errno)); /* resetty(); */ return 0; } i = 0; halfdelay(AUTH_INITIAL_TIMEOUT); buf[0] = getch(); halfdelay(AUTH_NEXT_TIMEOUT); if(buf[0] != ERR) for(i=1; i < ESC_SEQ_LEN && (c = getch()) != ERR; buf[i++] = c ) ; else { /* resetty(); */ return 0; /* timeout */ } buf[i] = '\0'; /* resetty(); */ if(!strncmp(buf, ESC_SEQ_BAD, ESC_SEQ_LEN)) return 0; /* bad terminal status */ return 1; } static Cmd * find_command(Cmd * ctab, char * cmd) { Cmd *cp, *match; int nl; nl = strlen(cmd); match = 0; for (cp = ctab; cp->cnam != (char *)0; cp++) { if (!strcmp(cp->cnam, cmd)) return cp; else if (!strncasecmp(cp->cnam, cmd, nl)) { if (match && cp->cfun != match->cfun) return 0; /* ambiguous */ match = cp; } } return match ? match : cp; } static int f_quit(ac,av,orig, usage) int ac; char *av[]; char *orig; char *usage; { should_exit = 1; return 0; } static int f_auth(ac,av,orig, usage) int ac; char *av[]; char *orig; char *usage; { int tmp_auth_type = 0; if(ac < 2 || ac > 3) { showusage(usage); return 0; } if(!strncmp(av[1], "ask", strlen(av[1]))) { tmp_auth_type |= AUTH_ASK; } else if(!strncmp(av[1], "keepalive", strlen(av[1]))) {} else { showusage(usage); return 0; } if( ac >= 3 ) { if(!strncmp(av[2], "password", strlen(av[2]))) { tmp_auth_type |= AUTH_PWD; } else { showusage(usage); return 0; } } auth_type = tmp_auth_type; return 0; } static int f_help(ac,av,orig,usage) int ac; char *av[]; char *orig; char *usage; { Cmd *cp; waddstr(conswin, "Command List:\n"); waddstr(conswin, "(Commands may be invoked with unique leading abbreviation)\n"); for(cp = ctab; cp->cnam != (char *)0; cp++) if(cp->help != (char *)0) waddstr(conswin, cp->help); return(0); } static int f_history(ac,av,orig, usage) int ac; char *av[]; char *orig; char *usage; { static int curr_history_index = -1; int wnd_lines = 0, wnd_cols = 0; static int page_lines = 2; int curr_y, curr_x; int ret_val; fd_set rfds, efds; noecho(); cbreak(); if(curr_history_index == -1) { curr_history_index = start_history_index; /* That is displaying should not be continued since the previous * function call, but entries should be output from the begining */ wprintw(conswin, " authreq y/n type pwd \n"); wprintw(conswin, "---------------------------------- --- ------- -------\n"); page_lines = 2; } else if(!auth_rec[curr_history_index]) { wprintw(conswin, "Shown history records have been overwritten as a result of wrapping\n"); } while(auth_rec[curr_history_index]) { getmaxyx(conswin, wnd_lines, wnd_cols); if(page_lines >= wnd_lines - 1) { getyx(conswin, curr_y, curr_x); mvwprintw(conswin, curr_y, 0, "--MORE--"); wrefresh(conswin); wmove(conswin, curr_y, 0); curs_set(0); do { FD_ZERO(&rfds); FD_SET(0, &rfds); FD_SET(auth_sock, &rfds); FD_ZERO(&efds); FD_SET(auth_sock, &efds); ret_val = select(auth_sock+1, &rfds, NULL, &efds, NULL); if (ret_val > 0) { if(FD_ISSET(auth_sock, &rfds) || FD_ISSET(auth_sock, &efds)) { /* socket request */ return SOCK_REQ; } } else { /* error */ } } while(!FD_ISSET(0, &rfds)); wgetch(conswin); curs_set(1); page_lines = 0; } page_lines++; wprintw(conswin, "%-34s %c %3s %3s %7s\n", auth_rec[curr_history_index]->req_str, auth_rec[curr_history_index]->accepted, (auth_rec[curr_history_index]->auth_type & AUTH_ASK) ? "ASK" : "KLV", (auth_rec[curr_history_index]->auth_type & AUTH_PWD) ? "PWD" : "", (auth_rec[curr_history_index]->auth_type & AUTH_PWD) ? auth_rec[curr_history_index]->pwd : ""); if(++curr_history_index >= MAX_AUTH_HISTORY) curr_history_index=0; } curr_history_index = -1; /* History has been shown completely and next time entries should be displayed * from the begining */ wrefresh(conswin); return 0; } int makeup_sockname(char sockname[], int max_name_len, char *auth_dir, char *host_addr, char *user_name) { strlcpy(sockname, auth_dir, max_name_len); strlcat(sockname, host_addr, max_name_len); strlcat(sockname, ".", max_name_len); strlcat(sockname, user_name, max_name_len); if(strlen(sockname) + strlen(".sock") > max_name_len) return -1; strlcat(sockname, ".sock", max_name_len); return strlen(sockname); } int console_command(char buf[]) { Cmd *cp; char *xa[128]; char xb[BUFSIZ + 1]; int xc; xc = enargv(buf,xa,sizeof(xa)/sizeof(char *),xb,sizeof(xb)); if(xc < 0) { waddstr(conswin, "Too many command parameters.\n"); return 0; } if(xc == 0) return 0; cp = find_command(ctab, xa[0]); if (!cp) { char xuf[BUFSIZ]; snprintf(xuf,sizeof(xuf),"Command \"%.200s\" is ambiguous.\n",xa[0]); waddstr(conswin, xuf); return 0; } if(cp->cnam == (char *)0) { char xuf[BUFSIZ]; snprintf(xuf,sizeof(xuf),"Command \"%.200s\" unrecognized.\n",xa[0]); waddstr(conswin, xuf); return 0; } return (*cp->cfun)(xc,xa,buf,cp->help); } void showusage(char *usage) { char buf[BUFSIZ] = "Usage: "; strlcat(buf, usage, sizeof(buf)); strlcat(buf, "\n", sizeof(buf)); waddstr(conswin, buf); wrefresh(conswin); } void makeup_auth_resp(char buf[], int auth_type, char pwd_buf[]) { strlcpy(buf, "auth", BUFSIZ); if(auth_type & AUTH_PWD) { strlcat(buf, " ", BUFSIZ); strlcat(buf, pwd_buf, BUFSIZ); } strlcat(buf, "\n", BUFSIZ); } void generate_pwd(char buf[]) { int i; char char_code; for(i=0; i 0) { if(FD_ISSET(s, &rfds)) /* socket request */ { ret_val = SOCK_REQ; break; } else if(FD_ISSET(s, &efds)) { ret_val = -1; break; } else if(FD_ISSET(0, &rfds)) { c=wgetch(conswin); if(c == '\n') { buf[i] = '\0'; waddstr(conswin, "\n"); wrefresh(conswin); break; } else if(c == '\b' || c == KEY_BACKSPACE) { if(i > 0) { i--; wechochar(conswin, '\b'); wdelch(conswin); wrefresh(conswin); } } else if(c != ERR) { buf[i++] = c; buf[i] = '\0'; wechochar(conswin, c); } else { /* error */ ret_val = errno; break; } } } else { /* error */ ret_val = errno; break; } } buf[maxlen] = '\0'; return ret_val; } int create_windows() { conswin = newwin(LINES/2, COLS,LINES - LINES/2 - 1, 0); wbkgd(conswin, COLOR_PAIR(1)); scrollok(conswin, 1); authframewin = newwin(LINES - LINES/2 - 1,COLS, 0, 0); wbkgd(authframewin, COLOR_PAIR(1)); box(authframewin, 0, 0); mvwaddstr(authframewin, 0, 2, " Auth req: "); wrefresh(authframewin); authwin = derwin(authframewin, LINES - LINES/2 - 3, COLS - 2, 1, 1); scrollok(authwin, 1); statusline = newwin(1,COLS, LINES - 1, 0); wbkgd(statusline, COLOR_PAIR(2)); mvwaddstr(statusline, 0, 1, "Auth settings:"); wrefresh(statusline); wrefresh(authwin); wrefresh(conswin); return 1; } int authreq_dlg(char req_details[]) { WINDOW *my_form_win, *my_form_win_frame; int ch; int allow_auth = 1; noecho(); curs_set(0); my_form_win_frame = newwin(13, 60, 5, 10); wbkgd(my_form_win_frame, COLOR_PAIR(1)); box(my_form_win_frame, 0, 0); wrefresh(my_form_win_frame); my_form_win = derwin(my_form_win_frame,10, 54, 2, 3); keypad(my_form_win, TRUE); /* wcolor_set(my_form_win, 2, NULL); */ mvwaddstr(my_form_win, 0, 0, req_details); mvwaddstr(my_form_win, 5, 23, "Allow it?"); wstandout(my_form_win); mvwaddstr(my_form_win, 8, 24, "Yes"); wstandend(my_form_win); mvwaddstr(my_form_win, 8, 29, "No"); wmove(my_form_win, 8, 24 + (1 - allow_auth)*5); wrefresh(my_form_win); /* Loop through to get user requests */ while((ch = tolower(wgetch(my_form_win))) != ' ' && ch != '\n' && ch != 'y' && ch != 'n') { allow_auth = 1 - allow_auth; wmove(my_form_win, 8, 24 + (1 - allow_auth)*5); wstandout(my_form_win); waddstr(my_form_win, allow_auth ? "Yes" : "No"); wstandend(my_form_win); wmove(my_form_win, 8, 24 + allow_auth*5); waddstr(my_form_win, (1 - allow_auth) ? "Yes" : "No"); touchline(my_form_win, 8, 1); wrefresh(my_form_win); } if(ch == 'y') allow_auth = 1; else if(ch == 'n') allow_auth = 0; delwin(my_form_win); delwin(my_form_win_frame); curs_set(1); return allow_auth; } void showsettings() { if(auth_type & AUTH_ASK) mvwaddstr(statusline, 0, 16, "ASK "); else mvwaddstr(statusline, 0, 16, "KEEPALIVE"); if(auth_type & AUTH_PWD) mvwaddstr(statusline, 0, 26, "PWD"); else mvwaddstr(statusline, 0, 26, " "); mvwaddstr(statusline, 0, 30, "|"); wrefresh(statusline); } void showstatistic() { mvwprintw(statusline, 0, 33, "Auth requested: %d (accepted: %d; rejected: %d)", nauth, nauth_accepted, nauth_rejected); wrefresh(statusline); } void deletewindows() { if(conswin) delwin(conswin); if(authframewin) delwin(authframewin); if(authwin) delwin(authwin); if(statusline) delwin(statusline); conswin = authframewin = authwin = statusline = NULL; } void deletehistory() { int i; for(i=0; i <= MAX_AUTH_HISTORY; i++) if(auth_rec[i]) { free(auth_rec[i]); auth_rec[i] = NULL; } }