/* * Copyright (c) 1996-2007, OpenFWTK Development Group * All rights reserved. See LICENSE. * * Copyright 1989 - 1994, Julianne Frances Haugh * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Julianne F. Haugh nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include "auth.h" #include "firewall.h" #include "firewall2.h" #include "prototypes.h" #include #include #include #include #include #include #include #include #include #include #define MAX_STR_LEN 500 #define AUTH_SUCCESS 1 #define AUTH_READ_MORE 2 #define REQUEST_UNAME 3 #define REQ_PWD 4 #define AUTH_DENY 5 #define AUTH_ERR 6 #define TXT_NAME 0 #define TXT_PWD 1 #define CNTL_NUM 2 #define STRFCPY(A,B) \ (strncpy((A), (B), sizeof(A) - 1), (A)[sizeof(A) - 1] = '\0') int curses_initialized = 0; void lostconn(); int login_dlg(char who[], int buf_len); int send_pwd(char pwd[]); int send_uname(char uname[]); int process_authresp(); int auth_console(char host_addr[], char user_name[]); int auth_login(char hostaddr[]); char *hostaddr = ""; struct passwd pwent; #if HAVE_UTMPX_H struct utmpx utxent, failent; struct utmp utent; #else struct utmp utent, failent; #endif /* * Global variables. */ static int amroot; static int timeout_alarm; #define WLCM_MSG_ROW 1 #define WLCM_MSG_COL 1 char welcome_msg[MAX_STR_LEN] = ""; /* * External identifiers. */ extern char **newenvp; extern size_t newenvc; extern int optind; extern char *optarg; extern char **environ; extern int login_access(const char *, const char *); extern void login_fbtab(const char *, uid_t, gid_t); int auth_user(char *authsrv_host, unsigned short int authsrv_port, char username[]); int process_resp(char *resp, char *req); int extract_username(char *raw, char username[]); void ShowUsage(); #ifndef ALARM #define ALARM 1000 #endif #ifndef RETRIES #define RETRIES 3 #endif #define NO_SHADOW "no shadow password for `%s'%s\n" #define BAD_PASSWD "invalid password for `%s'%s\n" #define BAD_DIALUP "invalid dialup password for `%s' on `%s'\n" #define BAD_TIME "invalid login time for `%s'%s\n" #define BAD_ROOT_LOGIN "ILLEGAL ROOT LOGIN%s\n" #define ROOT_LOGIN "ROOT LOGIN%s\n" #define FAILURE_CNT "exceeded failure limit for `%s'%s\n" #define REG_LOGIN "`%s' logged in%s\n" #define LOGIN_REFUSED "LOGIN `%s' REFUSED%s\n" #define REENABLED2 \ "login `%s' re-enabled after temporary lockout (%d failures).\n" #define MANY_FAILS "REPEATED login failures%s\n" /* local function prototypes */ static void init_env(void); static void alarm_handler(int); static void init_env(void) { char* tmp; if ((tmp = getenv("COLUMNS"))) { addenv("COLUMNS", tmp); } if ((tmp = getenv("LINES"))) { addenv("LINES", tmp); } if ((tmp = getenv("TERM"))) { addenv("TERM", tmp); } if ((tmp = getenv("LANG"))) { addenv("LANG", tmp); } /* * Add the timezone environmental variable so that time functions * work correctly. */ if ((tmp = getenv("TZ"))) { addenv("TZ", tmp); } } static void alarm_handler(int sig) { } int auth_login(char hostaddr[]) { char username[MAX_STR_LEN + 1]; char tty[BUFSIZ]; int delay; int retries; char *tmp; char buf[550]; int y, x; /* * Some quick initialization. */ initenv(); init_env(); environ = newenvp; /* make new environment active */ username[0] = '\0'; amroot = (getuid() == 0); /* MYCHANGE: Look at it later if (!isatty(0) || !isatty(1) || !isatty(2)) exit(1); */ /* must be a terminal */ STRFCPY(tty, utent.ut_line); (void) alarm (0); /* turn off alarm clock */ signal(SIGQUIT, SIG_DFL); /* default quit signal */ signal(SIGTERM, SIG_DFL); /* default terminate signal */ signal(SIGALRM, SIG_DFL); /* default alarm signal */ signal(SIGHUP, SIG_DFL); /* added this. --marekm */ signal(SIGINT, SIG_DFL); /* default interrupt signal */ umask(077); sosetline(SO_LLF); /* this uses confp to get server/port numbers */ if(auth_open(proxy_confp)) { fprintf(stderr,"Cannot open auth service\n"); exit(1); } if(auth_recv(buf,sizeof(buf))) lostconn(); if(strncmp(buf,"Authsrv ready",13)) { fprintf(stderr,"Cannot connect to server, response: %s\n",buf); exit(1); } fprintf(stderr, "Connected to server\n"); initscr(); /* */ kill(0, SIGWINCH); /* Hack to get a real window size when */ cbreak(); halfdelay(1); getch(); /* connecting from xterm: */ endwin(); /* just pretend that the window has been */ /* resized (SIGWINCH), getch - for KEY_RESIZE (as far as I understand). */ /* But there could be no chars to read, so getch is in nonblocking mode */ /* (max wait for 0.1 sec) */ /* Then re-init ncurses. */ /* */ initscr(); curses_initialized = 1; move(10, 15); /* Check whether the terminal can move a cursor */ refresh(); getyx(stdscr, y, x); if(y != 10 || x != 15) { endwin(); fprintf(stderr, "Your terminal is unable to change a cursor position\n"); syslog(LOG_ERR, "Your terminal is unable to change a cursor position\n"); exit(1); } scrollok(stdscr, 1); start_color(); init_pair(1, COLOR_GREEN, COLOR_BLACK); init_pair(2, COLOR_BLACK, COLOR_WHITE); /* only allow ALARM sec. for login */ signal(SIGALRM, alarm_handler); timeout_alarm = ALARM; if (timeout_alarm > 0) alarm(timeout_alarm); delay = 1; retries = RETRIES; if((tmp = proxy_conf_string(proxy_confp, "welcome-msg"))) { strncpy(welcome_msg, tmp, sizeof(welcome_msg) - 1); welcome_msg[sizeof(welcome_msg) - 1] = '\0'; } if(login_dlg(username, MAX_STR_LEN) == -1) { endwin(); exit(1); } /* Could be here if authenticated successfully only */ auth_close(); auth_console(hostaddr, username); return 0; } int extract_username(char *raw, char username[]) { char *startp, *endp; if((startp = strstr(raw, " "))) { (void)((endp = strstr(++startp, " ")) || (endp = strstr(startp, "\n")) || (endp = &raw[strlen(raw)])); if(MAX_STR_LEN < (endp - startp)) return 0; strncpy(username, startp, endp - startp); username[endp - startp] = '\0'; return 1; } return 0; } int login_dlg(char who[], int buf_len) { WINDOW *login_win, *login_frame_win, *note_win; int ch, rows, cols; int allow_auth = 1; FIELD *field[3]; FORM *login_form; int curr_cntl; int resp = 0; FILE *fp; int c; if(strlen(welcome_msg) > 0 && (fp = fopen(welcome_msg, "r"))) { wmove(stdscr, WLCM_MSG_ROW, WLCM_MSG_COL); while((c = fgetc(fp)) != EOF) { addch(c); } fclose(fp); wrefresh(stdscr); } noecho(); login_frame_win = newwin(13, 64, 5, 8); wbkgd(login_frame_win, COLOR_PAIR(1)); login_win = derwin(login_frame_win,7, 62, 1, 1); note_win = derwin(login_frame_win,2, 56, 10, 3); keypad(login_win, TRUE); field[0] = new_field(1, 46, 2, 13, 0, 1); /* Username */ field[1] = new_field(1, 46, 5, 13, 0, 1); /* Password */ field[2] = NULL; set_field_back(field[0], A_UNDERLINE | COLOR_PAIR(1)); set_field_fore(field[0], COLOR_PAIR(1)); field_opts_off(field[0], O_AUTOSKIP); set_field_back(field[1], A_UNDERLINE | COLOR_PAIR(1)); set_field_fore(field[1], COLOR_PAIR(1)); field_opts_off(field[1], O_AUTOSKIP); login_form = new_form(field); form_opts_off(login_form, O_BS_OVERLOAD); scale_form(login_form, &rows, &cols); set_form_win(login_form, login_frame_win); set_form_sub(login_form, login_win); box(login_frame_win,0, 0); mvwprintw(login_frame_win, 0, 2, " Login auth console "); post_form(login_form); wrefresh(login_frame_win); mvwprintw(login_win, 2, 3, "Username:"); mvwprintw(login_win, 5, 3, "Response:"); wmove (login_win, 2,13); wrefresh (login_win); curr_cntl = TXT_NAME; pos_form_cursor(login_form); do { if((ch = wgetch(login_win)) == -1 && 0) { allow_auth = -1; goto cleanout; } switch(ch) { case KEY_DOWN: case KEY_UP : case '\t' : case '\n' : case '\r' : form_driver(login_form, REQ_NEXT_FIELD); if(curr_cntl == TXT_NAME) { /* if(field_status(field[0])) { */ werase(note_win); wrefresh(note_win); send_uname(field_buffer(field[0],0)); /* } */ } else if(curr_cntl == TXT_PWD) { send_pwd(field_buffer(field[1], 0)); } curs_set(0); mvwaddstr(login_win,6, 3, "(Just a minute, please...)\n"); wrefresh(login_win); if((resp = process_authresp(login_form, note_win))== AUTH_SUCCESS) { break; /* SUCCESS. fall out from the "switch" and then from the "while" */ } else if(resp == REQ_PWD) { curr_cntl = TXT_PWD - 1; /* don't change currect control */ } else if(resp == AUTH_DENY) { /* Failed to login. Starting over again from username */ } ++curr_cntl; curr_cntl %= CNTL_NUM; set_field_buffer(field[1], 0, ""); /* Empty password field whenever switch currect field */ curs_set(1); form_driver(login_form, REQ_END_LINE); wrefresh(login_win); break; case KEY_BACKSPACE: form_driver(login_form, REQ_DEL_PREV); break; case KEY_DC: form_driver(login_form, REQ_DEL_CHAR); break; case KEY_LEFT: form_driver(login_form, REQ_LEFT_CHAR); break; case KEY_RIGHT: form_driver(login_form, REQ_RIGHT_CHAR); break; default: form_driver(login_form, ch); break; } } while(resp != AUTH_SUCCESS); strncpy(who, field_buffer(field[0],0), buf_len); strtrm(who); cleanout: werase(note_win); wrefresh(note_win); delwin(note_win); unpost_form(login_form); free_form(login_form); free_field(field[0]); free_field(field[1]); delwin(login_win); delwin(login_frame_win); curs_set(1); refresh(); return allow_auth; } int process_authresp(FORM *login_form, WINDOW *note_win) { int ret_val = REQ_PWD; char rbuf[1024]; while (1) { if(auth_recv(rbuf,sizeof(rbuf))) lostconn(); /* if(wgetch(note_win) == 'd') strlcpy(rbuf, "display your password will expire in 15 days (bla bla bla)\n", sizeof(rbuf)); */ strtrm(rbuf); if(!strncmp(rbuf,"ok",2)) { mvwprintw(form_sub(login_form),6, 3, "(OK)\n"); ret_val = AUTH_SUCCESS; break; } if(!strncmp(rbuf,"display ",8)) { wprintw(note_win,"%s",&rbuf[8]); wrefresh(note_win); strlcpy(rbuf,"response dummy",sizeof(rbuf)); if(auth_send(rbuf)) lostconn(); continue; } if(!strncmp(rbuf,"challenge ",10)) { if(rindex(rbuf, ':')) *(rindex(rbuf, ':')) = '\0'; mvwprintw(form_sub(login_form),6, 3, "(%s)\n", &rbuf[10]); form_driver(login_form, REQ_NEXT_FIELD); /* It's impossible to change */ field_opts_on(form_fields(login_form)[1], O_PUBLIC); /* an option of the current field. */ form_driver(login_form, REQ_PREV_FIELD); /* Don't know why. * Workaround - temporarily change * current field and then restore it. */ break; } else if(!strncmp(rbuf,"chalnecho ",10)) { if(rindex(rbuf, ':')) *(rindex(rbuf, ':')) = '\0'; mvwprintw(form_sub(login_form),6, 3, "(%s)\n", &rbuf[10]); form_driver(login_form, REQ_NEXT_FIELD); /* It's impossible to change */ field_opts_off(form_fields(login_form)[1], O_PUBLIC); /* an option of the current field. */ form_driver(login_form, REQ_PREV_FIELD); /* Don't know why. * Workaround - temporarily change * current field and then restore it. */ break; } else if(!strncmp(rbuf,"password",8)) { mvwaddstr(form_sub(login_form),6, 3, "(Password)\n"); form_driver(login_form, REQ_NEXT_FIELD); /* It's impossible to change */ field_opts_off(form_fields(login_form)[1], O_PUBLIC); /* an option of the current field. */ form_driver(login_form, REQ_PREV_FIELD); /* Don't know why. * Workaround - temporarily change * current field and then restore it. */ post_form(login_form); break; } else if(!strncmp(rbuf,"Permission Denied.",18)) { mvwaddstr(form_sub(login_form),6, 3, "(Permission Denied)\n"); return AUTH_ERR; } else { mvwprintw(form_sub(login_form),6, 3, "(Unrecognized authsrv response: %s)\n", rbuf); return AUTH_ERR; } return AUTH_DENY; } wrefresh(form_sub(login_form)); return ret_val; } int send_uname(char uname[]) { char rbuf[1024]; char myhostname[512]; struct hostent *hp; char buf[1024]; strlcpy(buf, uname, sizeof(buf) ); strtrm(buf); if(gethostname(myhostname,sizeof(myhostname))) strlcpy(myhostname,"amnesiac",sizeof(myhostname)); else if ((hp = gethostbyname(myhostname)) != (struct hostent *)0) strlcpy(myhostname,hp->h_name,sizeof(myhostname)); snprintf(rbuf,sizeof(rbuf),"authorize %.32s 'authcons %.128s/%.128s'",buf,proxy_stats.rladdr,proxy_stats.riaddr); if(auth_send(rbuf)) lostconn(); return 1; } int send_pwd(char pwd[]) { char rbuf[1024]; char buf[1024]; strlcpy(buf, pwd, sizeof(buf) - 13); strtrm(buf); snprintf(rbuf, sizeof(rbuf), "response '%s'", buf); if(auth_send(rbuf)) lostconn(); return 1; } void lostconn() { if(curses_initialized) endwin(); fprintf(stderr,"Lost connection to auth service\n"); auth_close(); exit(1); }