diff -r -u portslave-1.16.orig/README.ian portslave-1.16/README.ian --- portslave-1.16.orig/README.ian Tue Nov 17 13:50:24 1998 +++ portslave-1.16/README.ian Sun Aug 9 20:13:23 1998 @@ -0,0 +1,100 @@ +This file documents some additions that I (Ivan Nejgebauer) have made +to portslave to make it usable in my setup. Maybe you'll never need +these extra capabilities, and maybe you'll never read this file, in +which case you won't even know they existed. Heh. + + +1. Command line parsing + +I prefer to use mgetty for controlling the modem ports because it gives +me finer control over various modem settings, and is quite good at +dealing with crappy hardware. To make portslave usable in this kind +of setup, I made it recognize '+' as an indicator that it should read +stdin instead of trying to deal with the port by itself. If the first +command-line argument is '+', portslave will also check for one more +argument, and treat it as login name if present. Thus it can be nicely +integrated with mgetty's login.config; all you need is something like + +* - - /usr/sbin/portslave + @ + +You can also use mgetty's AutoPPP feature and put the line + +/AutoPPP/ - - /usr/sbin/portslave + + +in the login.config file. Portslave will perform its own PPP +autodetection, and everything will work as expected. + +If you use mgetty with portslave, be sure to not define conf.lockdir +in /etc/portslave.conf. Mgetty already does locking. + + +2. Passthrough accounts + +At our site, the same modem pool is used for access to hosts which are +not under our direct administrative control, so we have to provide the +way to reach those hosts by telnet/rlogin/ssh. Portslave now has a +notion of passthrough accounts of the form user@host; when it sees such +account it will plug in the magic value "*PASSTHROUGH*" in the Password +value-pair of the Authentication-Request packet. RADIUS server is +expected to recognize this special case and return an Accept packet +with appropriate service parameters. The @host part is stripped from +the login name before the service is invoked. + +Passthrough hostnames are specified in /etc/portslave.conf thusly: + +all.passthrough @host1 @host2 @host3 [...] + +A port-specific definition can be used to override this one. + +Having a fixed and known password value is probably not the best idea +security-wise. Maybe I'll fix that in some future version. + + +3. Realms + +Portslave now provides a relatively crude, but workable realm support. +Realms give you the ability to recognize user@host login names and +to use the @host part to specify different authentication and/or +accounting hosts. In /etc/portslave.conf, + +all.realm >-@host1 authhost1 accthost1 authhost2 accthost2 +all.realm >-@host2 authhostx accthosty "" "" + +will tell portslave to use authhost1/authhost2 for authentication and +accthost1/accthost2 for accounting when it sees user@host1 in a login +name. All four names/addresses must be given; if you want a specific +address to be undefined, use an empty pair of double quotes (""). '>' +denotes that the @host1 part is a suffix, and '-' means that the suffix +will be stripped from the login name IF some kind of login service is +provided. Stripping can be avoided if '+' is used instead. You can +use '<' for prefix strings, so what was attainable with UUCPHACK can +now be done with an "<+U" realm. Since realm support makes UUCPHACK +unnecessary, I've removed it from the source. + +Realms will work with AutoPPP; passthrough, of course, will not. + +You can define more than one realm; subsequent definitions will not +replace the previous ones. + + +4. Secure shell support + +Portslave now supports a (non-standard) Login-Service = SSH, with +the value of 1000. Update your RADIUS dictionary if you want to +provide this service. + + +5. Session timeout support + +Portslave and pppd will recognize and honor the Session-Timeout +value-pair passed back by the RADIUS server. Pppd now has the +session-timeout option. + + +6. Periodic modem checking + +If [port].checktime is greater than zero, portslave will check if the +modem is alive after that many minutes of inactivity on the port. + +-- +Ivan Nejgebauer diff -r -u portslave-1.16.orig/libpsr/libpsr.c portslave-1.16/libpsr/libpsr.c --- portslave-1.16.orig/libpsr/libpsr.c Tue Jan 13 14:25:32 1998 +++ portslave-1.16/libpsr/libpsr.c Sun Aug 9 20:13:23 1998 @@ -156,6 +156,10 @@ } if (thisauth.idletime > 0) idle_time_limit = thisauth.idletime; + if (thisauth.sessiontime > 0) { + session_limit = thisauth.sessiontime; + timeout(close_on_timeout, 0, session_limit); + } syslog(LOG_INFO, "user %s logged in", user); setenv("LOGNAME", user, 1); diff -r -u portslave-1.16.orig/libpsr/pppd.h portslave-1.16/libpsr/pppd.h --- portslave-1.16.orig/libpsr/pppd.h Tue Oct 28 17:06:34 1997 +++ portslave-1.16/libpsr/pppd.h Sun Aug 9 20:13:23 1998 @@ -41,7 +41,9 @@ extern u_int32_t netmask; extern int logged_in; extern int idle_time_limit; +extern int session_limit; +extern int close_on_timeout(int sig); extern int setipaddr(char *arg); extern void (*ppp_openlog)(); diff -r -u portslave-1.16.orig/ppp-2.2.0f-radius/pppd/main.c portslave-1.16/ppp-2.2.0f-radius/pppd/main.c --- portslave-1.16.orig/ppp-2.2.0f-radius/pppd/main.c Mon Nov 3 16:40:01 1997 +++ portslave-1.16/ppp-2.2.0f-radius/pppd/main.c Sun Aug 9 20:13:23 1998 @@ -99,6 +99,7 @@ char *no_ppp_msg = "Sorry - this system lacks PPP kernel support\n"; /* prototypes */ +void close_on_timeout __P((int)); static void hup __P((int)); static void term __P((int)); static void chld __P((int)); @@ -355,6 +356,10 @@ hungup = 0; kill_link = 0; + /* set session timeout */ + if (session_limit > 0) + TIMEOUT(close_on_timeout, 0, session_limit); + /* run connection script */ if (connector && connector[0]) { MAINDEBUG((LOG_INFO, "Connecting with <%s>", connector)); @@ -585,6 +590,21 @@ cleanup(0, NULL); syslog(LOG_INFO, "Exit."); exit(status); +} + +/* + * close_on_timeout - drop the connection on reaching session timeout + */ +void +close_on_timeout(sig) + int sig; +{ + syslog(LOG_INFO, "Session limit reached"); + + phase = PHASE_DEAD; + hungup = 1; + persist = 0; + lcp_close(0); } /* diff -r -u portslave-1.16.orig/ppp-2.2.0f-radius/pppd/options.c portslave-1.16/ppp-2.2.0f-radius/pppd/options.c --- portslave-1.16.orig/ppp-2.2.0f-radius/pppd/options.c Tue Nov 11 16:09:24 1997 +++ portslave-1.16/ppp-2.2.0f-radius/pppd/options.c Sun Aug 9 20:13:24 1998 @@ -106,7 +106,9 @@ #ifdef _linux_ int idle_time_limit = 0; +int session_limit = 0; static int setidle __P((char **)); +static int settmout __P((char **)); #endif /* @@ -328,6 +330,7 @@ #endif /* IPX_CHANGE */ #ifdef _linux_ + {"session-timeout", 1, settmout}, /* seconds for timeout disconnect */ {"idle-disconnect", 1, setidle}, /* seconds for disconnect of idle IP */ #endif @@ -1844,6 +1847,12 @@ char **argv; { return int_option(*argv, &idle_time_limit); +} + +static int settmout (argv) + char **argv; +{ + return abs(int_option(*argv, &session_limit)); } #endif diff -r -u portslave-1.16.orig/ppp-2.2.0f-radius/pppd/pppd.h portslave-1.16/ppp-2.2.0f-radius/pppd/pppd.h --- portslave-1.16.orig/ppp-2.2.0f-radius/pppd/pppd.h Tue Jan 13 14:39:57 1998 +++ portslave-1.16/ppp-2.2.0f-radius/pppd/pppd.h Sun Aug 9 20:13:24 1998 @@ -54,6 +54,7 @@ extern int phase; /* Current state of link - see values below */ extern int baud_rate; /* Current link speed in bits/sec */ extern char *progname; /* Name of this program */ +extern int session_limit; /* Session timeout */ /* * Variables set by command-line options. diff -r -u portslave-1.16.orig/src/auth.h portslave-1.16/src/auth.h --- portslave-1.16.orig/src/auth.h Thu Jan 22 14:03:23 1998 +++ portslave-1.16/src/auth.h Sun Aug 9 20:13:24 1998 @@ -23,6 +23,7 @@ #define P_TCPLOGIN 'U' #define P_CONSOLE '!' #define P_SHELL 'X' +#define P_SSH 'H' /* * Authentication info. This struct @@ -45,6 +46,7 @@ unsigned int netmask; int mtu; int mru; + int sessiontime; int idletime; int porttype; int sent_bytes; @@ -57,3 +59,4 @@ int rad_init(int port, struct auth *ai, char *tty); int rad_portno(char *tty); char *dotted(unsigned int ipno); +struct realm_def *ckrealm(char *login, int port); diff -r -u portslave-1.16.orig/src/ctlportslave.c portslave-1.16/src/ctlportslave.c --- portslave-1.16.orig/src/ctlportslave.c Sat Nov 22 22:01:54 1997 +++ portslave-1.16/src/ctlportslave.c Sun Aug 9 20:13:24 1998 @@ -86,6 +86,7 @@ if (t == 'S') return("SLIP"); if (t == 'P') return("PPP"); if (t == 'A') return("PPP"); + if (t == 'H') return("SSH"); return ("unknown"); } diff -r -u portslave-1.16.orig/src/getty.c portslave-1.16/src/getty.c --- portslave-1.16.orig/src/getty.c Tue Jan 13 14:33:03 1998 +++ portslave-1.16/src/getty.c Fri Nov 6 22:18:02 1998 @@ -26,6 +26,20 @@ #include "server.h" /* + * Reset the terminal to a reasonably sane state. + */ +void maketermsane(void) +{ + struct termios tty; + + tcgetattr(0, &tty); + tty.c_iflag &= ~IGNCR; + tty.c_oflag |= OPOST|ONLCR; + tty.c_lflag |= ISIG|IEXTEN|ICANON|ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE; + tcsetattr(0, TCSANOW, &tty); +} + +/* * Turn CR translation on or off. */ static void crtrans(int inon, int outon) @@ -351,6 +365,8 @@ * First wait for something to happen on * our input, then check for a lockfile. */ + int slct; + struct timeval timeout, *tptr; waitfor_loop: nsyslog(LOG_INFO, "waiting for %s", lc->waitfor); usleep(250000); @@ -358,13 +374,39 @@ FD_ZERO(&readfds); FD_SET(0, &readfds); unlock(mainconf.lockdir, lc->tty); - while(select(1, &readfds, NULL, NULL, NULL) < 0 && + if (lc->checktime > 0) { + timeout.tv_sec = lc->checktime * 60; + timeout.tv_usec = 0; + tptr = &timeout; + } else + tptr = NULL; + while((slct = select(1, &readfds, NULL, NULL, tptr)) < 0 && errno == EINTR) ; if (dolock(mainconf.lockdir, lc->tty) == 1) { sleep(5); continue; } + if (tptr && slct == 0) { /* time to prod the modem */ + chat_timeout = 10; + if (chat(1, lc->checkchat, NULL) == 0) { + nsyslog(LOG_INFO, "modem check OK"); + goto waitfor_loop; + } + chat_timeout = 10; + if (chat(1, lc->checkchat, NULL) == 0) { + nsyslog(LOG_WARNING, + "modem check OK on second attempt"); + goto waitfor_loop; + } + /* + * Bummer, the modem is not responding. + * Complain and bail out. + */ + nsyslog(LOG_WARNING, "modem check: %m"); + unlock(mainconf.lockdir, lc->tty); + return -1; + } chat_timeout = 20; if (chat_expect(0, lc->waitfor, NULL) < 0) { if (errno == ETIMEDOUT) { @@ -538,11 +580,13 @@ alarm(to); crtrans(0, 1); - do { - r = get_line(1, s, 1, login, 64); - } while(login[0] == 0 && r == 0); + r = login[0] ? 0 : get_line(1, s, 1, login, 64); alarm(0); crtrans(1, 1); + if (s) free(s); + + if (r == 0 && login[0] == 0) + return 1; if (r == 1) { strcpy(login, "AutoPPP"); @@ -556,8 +600,10 @@ if (r == 1) return 0; - if (mainconf.locallogins && login[0] == '!') { - if (s) free(s); + if (mainconf.locallogins && login[0] == '!') + return 0; + if (ckpassthrough(login, port)) { + strcpy(pass, "*PASSTHROUGH*"); return 0; } @@ -573,8 +619,32 @@ } alarm(0); crtrans(1, 1); - if (s) free(s); return r; } +/* + * Check for passthrough usernames. + */ +int ckpassthrough(char *login, int port) +{ + char *s = NULL, *t, *p; + int r = 1; + + if (!(p = lineconf[port].passthrough)) + return 0; + if ((t = strchr(login, '@')) == NULL || *++t == '\0') + return 0; + + for ( ; (p = strchr(p, '@')) != NULL && *++p; ) { + for (s = p; *s && !isspace(*s); s++) + ; + if (*s) *s = '\0'; else s = NULL; + if ((r = strcmp(p, t)) == 0) + break; + if (s) *s = ' '; + } + if (s) *s = ' '; + + return !r; +} diff -r -u portslave-1.16.orig/src/lib.c portslave-1.16/src/lib.c --- portslave-1.16.orig/src/lib.c Tue Jan 13 14:33:25 1998 +++ portslave-1.16/src/lib.c Sun Aug 9 20:13:24 1998 @@ -192,6 +192,8 @@ * %m: netmask * %t: MTU * %r: MRU + * %I: idle timeout + * %T: session timeout */ char *percent(int port, struct auth *ai, char *in) { @@ -243,6 +245,9 @@ break; case 'I': if (ai) t = num(ai->idletime); + break; + case 'T': + if (ai) t = num(ai->sessiontime); break; case 'h': t = mainconf.hostname; diff -r -u portslave-1.16.orig/src/main.c portslave-1.16/src/main.c --- portslave-1.16.orig/src/main.c Wed Nov 12 15:03:54 1997 +++ portslave-1.16/src/main.c Sun Aug 9 20:13:24 1998 @@ -18,7 +18,6 @@ #include "server.h" - /* * Change argv[0] te reflect what we're doing. */ @@ -57,13 +56,13 @@ /* * Check the syntax. */ - if (argc < 2 || (argv[1][0] != '-' && + if (argc < 2 || (argv[1][0] != '-' && argv[1][0] != '+' && (thisport = atoi(argv[1])) == 0 && argv[1][0] != '0')) { nsyslog(LOG_ERR, "Usage: portslave \n"); exit(1); } - if (argv[1][0] == '-') { + if (argv[1][0] == '-' || argv[1][0] == '+') { thisport = -2; tty = ttyname(0); if (tty == NULL) { @@ -73,6 +72,12 @@ } } + if (argv[2] && argv[1][0] == '+') { + strncpy(namebuf, argv[2], sizeof namebuf); + namebuf[sizeof namebuf - 1] = '\0'; + } else + namebuf[0] = '\0'; + /* * Read the config file. */ @@ -101,8 +106,12 @@ */ if (lineconf[thisport].authtype) { for(i = 0; i < 3; i++) { - if (do_login(thisport, name, pass) < 0) + int r; + + if ((r = do_login(thisport, name, pass)) < 0) exit(1); + if (r == 1) + continue; do_acct = 0; @@ -129,7 +138,8 @@ if (ai.message[0]) printf("%s\n", ai.message); else - printf("Login incorrect.\n"); + printf("Authentication failure\n\n"); + *name = '\0'; fflush(stdout); } else break; @@ -139,7 +149,9 @@ /* * 3 login failures - exit! */ + printf("Authentication failure\n"); fflush(stdout); + maketermsane(); usleep(250000); exit(1); } diff -r -u portslave-1.16.orig/src/radclient.c portslave-1.16/src/radclient.c --- portslave-1.16.orig/src/radclient.c Mon Nov 24 18:49:55 1997 +++ portslave-1.16/src/radclient.c Sun Aug 9 20:13:24 1998 @@ -527,6 +527,11 @@ i = PW_RLOGIN; h = ai->address; break; + case P_SSH: + s = PW_LOGIN_USER; + i = PW_SSH; + h = ai->address; + break; case P_TCPCLEAR: case P_TCPLOGIN: s = PW_LOGIN_USER; @@ -708,6 +713,8 @@ char recvbuf[4096]; char *ptr = recvbuf, *maxptr; int oldproto; + unsigned int ah1, ah2; + struct realm_def *r; /* * Set the message to some error in case we fail. @@ -724,20 +731,15 @@ /* * Now connect to the server. */ -#ifdef UUCPHACK - if (ai->login[0] == 'U') { - if (lineconf[port].uauthhost1 == 0) - lineconf[port].uauthhost1 = lineconf[port].authhost1; - if (lineconf[port].uauthhost2 == 0) - lineconf[port].uauthhost2 = lineconf[port].authhost2; - len = rad_send(PW_AUTH_UDP_PORT, lineconf[port].uauthhost1, - lineconf[port].uauthhost2, - recvbuf, sizeof(recvbuf), req,0); - } else -#endif - len = rad_send(PW_AUTH_UDP_PORT, lineconf[port].authhost1, - lineconf[port].authhost2, - recvbuf, sizeof(recvbuf), req,0); + if ((r = ckrealm(ai->login, port)) != NULL) { + ah1 = r->authhost1; + ah2 = r->authhost2; + } else { + ah1 = lineconf[port].authhost1; + ah2 = lineconf[port].authhost2; + } + len = rad_send(PW_AUTH_UDP_PORT, ah1, ah2, recvbuf, + sizeof(recvbuf), req, 0); rad_attrfree(req->list); free(req); @@ -798,6 +800,9 @@ case PW_RLOGIN: ai->proto = P_RLOGIN; break; + case PW_SSH: + ai->proto = P_SSH; + break; case PW_TCP_CLEAR: ai->proto = P_TCPCLEAR; break; @@ -826,6 +831,9 @@ case PW_FRAMED_MTU: ai->mtu = value; break; + case PW_SESSION_TIMEOUT: + ai->sessiontime = value; + break; case PW_IDLE_TIMEOUT: ai->idletime = value; break; @@ -882,11 +890,15 @@ RADPKT *req; char recvbuf[4096]; char *ptr = recvbuf; + unsigned int ah1, ah2; + struct realm_def *r; /* * HACK/FIXME: this should not be here, but it's easier.. + * (skip for local logins, they'll do their own updating --ian) */ - update_utmp(port, ai, islogin); + if (ai->proto != P_SHELL) + update_utmp(port, ai, islogin); /* * First, build the request. @@ -897,20 +909,15 @@ /* * Now connect to the server. */ -#ifdef UUCPHACK - if (ai->login[0] == 'U') { - if (lineconf[port].uaccthost1 == 0) - lineconf[port].uaccthost1 = lineconf[port].accthost1; - if (lineconf[port].uaccthost2 == 0) - lineconf[port].uaccthost2 = lineconf[port].accthost2; - len = rad_send(PW_ACCT_UDP_PORT, lineconf[port].uaccthost1, - lineconf[port].uaccthost2, - recvbuf, sizeof(recvbuf), req,1); - } else -#endif - len = rad_send(PW_ACCT_UDP_PORT, lineconf[port].accthost1, - lineconf[port].accthost2, - recvbuf, sizeof(recvbuf), req,1); + if ((r = ckrealm(ai->login, port)) != NULL) { + ah1 = r->accthost1; + ah2 = r->accthost2; + } else { + ah1 = lineconf[port].accthost1; + ah2 = lineconf[port].accthost2; + } + len = rad_send(PW_ACCT_UDP_PORT, ah1, ah2, recvbuf, + sizeof(recvbuf), req, 1); rad_attrfree(req->list); free(req); @@ -923,4 +930,27 @@ #endif return 0; +} + +/* + * Check for realm in the login name. + */ +struct realm_def *ckrealm(char *login, int port) +{ + struct realm_def *r; + int l, n; + + l = strlen(login); + for (r = lineconf[port].realm ; r != NULL; r = r->next) { + n = strlen(r->name); + if (r->prefix && strncmp(login, r->name, n) == 0) + break; + else if (!r->prefix) { + if (l < n) + continue; + if (strcmp(login + l - n, r->name) == 0) + break; + } + } + return r; } diff -r -u portslave-1.16.orig/src/radius.h portslave-1.16/src/radius.h --- portslave-1.16.orig/src/radius.h Sun Jun 29 21:50:31 1997 +++ portslave-1.16/src/radius.h Sun Aug 9 20:13:24 1998 @@ -92,6 +92,7 @@ #define PW_FRAMED_ROUTE 22 #define PW_FRAMED_IPXNET 23 #define PW_STATE 24 +#define PW_SESSION_TIMEOUT 27 #define PW_IDLE_TIMEOUT 28 #define PW_ACCT_STATUS_TYPE 40 @@ -140,6 +141,7 @@ #define PW_RLOGIN 1 #define PW_TCP_CLEAR 2 #define PW_PORTMASTER 3 +#define PW_SSH 1000 /* AUTHENTICATION LEVEL */ diff -r -u portslave-1.16.orig/src/rwconf.c portslave-1.16/src/rwconf.c --- portslave-1.16.orig/src/rwconf.c Thu Jan 22 14:04:34 1998 +++ portslave-1.16/src/rwconf.c Sun Aug 9 20:13:24 1998 @@ -26,6 +26,7 @@ #define C_IPNO 5 #define C_IPDY 6 #define C_CHAT 7 +#define C_REALM 8 /* * For option lists. @@ -70,12 +71,14 @@ static struct lst prlst[] = { { "login", P_LOCAL }, { "rlogin", P_RLOGIN }, + { "telnet", P_TELNET }, { "slip", P_SLIP }, { "cslip", P_CSLIP }, { "ppp", P_PPP }, { "tcpclear", P_TCPCLEAR }, { "tcplogin", P_TCPLOGIN }, { "console", P_CONSOLE }, + { "ssh", P_SSH }, { NULL, 0 }, }; @@ -89,6 +92,7 @@ { "rlogin", C_STR, NULL, offsetof(struct main_cfg, rlogin) }, { "telnet", C_STR, NULL, offsetof(struct main_cfg, telnet) }, { "pppd", C_STR, NULL, offsetof(struct main_cfg, pppd) }, + { "ssh", C_STR, NULL, offsetof(struct main_cfg, ssh) }, { "locallogins", C_STR, NULL, offsetof(struct main_cfg, locallogins) }, { "syslog", C_HOST, NULL, offsetof(struct main_cfg, syslog) }, { "facility", C_INT, NULL, offsetof(struct main_cfg, facility) }, @@ -110,12 +114,6 @@ { "authhost2", C_HOST, NULL, offsetof(struct line_cfg, authhost2) }, { "accthost1", C_HOST, NULL, offsetof(struct line_cfg, accthost1) }, { "accthost2", C_HOST, NULL, offsetof(struct line_cfg, accthost2) }, -#ifdef UUCPHACK - { "uauthhost1", C_HOST, NULL, offsetof(struct line_cfg, uauthhost1) }, - { "uauthhost2", C_HOST, NULL, offsetof(struct line_cfg, uauthhost2) }, - { "uaccthost1", C_HOST, NULL, offsetof(struct line_cfg, uaccthost1) }, - { "uaccthost2", C_HOST, NULL, offsetof(struct line_cfg, uaccthost2) }, -#endif { "protocol", C_LIST, prlst, offsetof(struct line_cfg, protocol) }, { "secret", C_STR, NULL, offsetof(struct line_cfg, secret) }, { "host", C_HOST, NULL, offsetof(struct line_cfg, host) }, @@ -139,6 +137,8 @@ { "initchat", C_CHAT, NULL, offsetof(struct line_cfg, initchat) }, { "waitfor", C_CHAT, NULL, offsetof(struct line_cfg, waitfor) }, { "answer", C_CHAT, NULL, offsetof(struct line_cfg, answer) }, + { "passthrough", C_STR, NULL, offsetof(struct line_cfg, passthrough) }, + { "realm", C_REALM,NULL, offsetof(struct line_cfg, realm) }, { NULL, }, }; @@ -267,6 +267,111 @@ } /* + * Put a realm structure in a linked list. + * + * A few helper macros first... + */ +#define findend(s1) \ + do {\ + for (s = s1; *s && !isspace(*s); s++);\ + if (*s) *s = '\0'; else s = NULL;\ + if (strlen(s1) == 0) goto realm_error;\ + } while (0) + +#define ckshortline(s1) \ + do {\ + if (s) {\ + *s = ' ';\ + s1 = s + 1;\ + } else goto realm_error;\ + } while (0) + +#define addaddr(a1) \ + do {\ + if (strcmp(t, "\"\"") == 0) {\ + r->a1 = 0;\ + break;\ + }\ + if (sethost((char *) r, t, offsetof(struct realm_def, a1)) < 0)\ + goto realm_error;\ + } while(0) + +static int setrealm(char *ptr, char *val, int offs) +{ + struct realm_def **rl; + struct realm_def *r, *nr; + char *s = NULL, *t; + int i; + + if ((r = (struct realm_def *) malloc(sizeof(struct realm_def))) == NULL) + return -1; + + r->name = NULL; + findend(val); + switch (*(t = val)) { + case '>': + r->prefix = 0; + break; + case '<': + r->prefix = 1; + break; + default: + goto realm_error; + } + switch (*++t) { + case '-': + r->strip = 1; + break; + case '+': + r->strip = 0; + break; + default: + goto realm_error; + } + if (!*++t) + goto realm_error; + r->name = strdup(t); + + ckshortline(t); + findend(t); + addaddr(authhost1); + + ckshortline(t); + findend(t); + addaddr(accthost1); + + ckshortline(t); + findend(t); + addaddr(authhost2); + + ckshortline(t); + findend(t); + addaddr(accthost2); + + if (ptr == (char *)&allconf) { + for(i = 0; i < MAXLINES; i++) { + rl = (struct realm_def **)((char *)&lineconf[i] + offs); + nr = (struct realm_def *) malloc(sizeof(struct realm_def)); + if (!nr) + return -1; + *nr = *r; + if (*rl) nr->next = *rl; + *rl = nr; + } + } + rl = (struct realm_def **)((char *)ptr + offs); + if (*rl) r->next = *rl; + *rl = r; + + return 0; + +realm_error: + if (r->name) free(r->name); + free(r); + return -1; +} + +/* * Set an integer, from a list of string values. */ static int setlist(char *ptr, char *val, struct lst *lst, int offs) @@ -370,6 +475,9 @@ break; case C_IPDY: n = setipdy((char *)ptr, a, x->offs, n); + break; + case C_REALM: + n = setrealm((char *)ptr, a, x->offs); break; default: n = -1; diff -r -u portslave-1.16.orig/src/rwconf.h portslave-1.16/src/rwconf.h --- portslave-1.16.orig/src/rwconf.h Thu Jan 22 14:03:43 1998 +++ portslave-1.16/src/rwconf.h Sun Aug 9 20:13:24 1998 @@ -20,6 +20,7 @@ char *rlogin; char *telnet; char *pppd; + char *ssh; int locallogins; unsigned int syslog; int facility; @@ -28,6 +29,20 @@ EXTERN struct main_cfg mainconf; /* + * Realm structure. + */ +struct realm_def { + char *name; + int prefix; + int strip; + unsigned int authhost1; + unsigned int authhost2; + unsigned int accthost1; + unsigned int accthost2; + struct realm_def *next; +}; + +/* * Configuration, per line. */ struct line_cfg { @@ -37,12 +52,6 @@ unsigned int authhost2; unsigned int accthost1; unsigned int accthost2; -#ifdef UUCPHACK - unsigned int uauthhost1; - unsigned int uauthhost2; - unsigned int uaccthost1; - unsigned int uaccthost2; -#endif char *secret; int protocol; int host; @@ -70,6 +79,8 @@ char *initchat; char *waitfor; char *answer; + char *passthrough; + struct realm_def *realm; int aa; }; EXTERN struct line_cfg lineconf[MAXLINES]; diff -r -u portslave-1.16.orig/src/server.cfg portslave-1.16/src/server.cfg --- portslave-1.16.orig/src/server.cfg Thu Jan 22 14:13:27 1998 +++ portslave-1.16/src/server.cfg Sun Aug 9 20:13:24 1998 @@ -30,6 +30,10 @@ # conf.telnet /usr/bin/telnet # +# Where to find ssh. +# +conf.ssh /usr/bin/ssh +# # If you set this to "1", you can always login locally by putting a '!' # before your loginname. Useful for emergencies when the RADIUS server is down. # @@ -89,6 +93,33 @@ all.protocol rlogin all.host shellhost.someisp.com # +# Passthrough hosts. Portslave will detect user@host login names and +# automatically use "*PASSTHROUGH*" as a password for those; it's up +# to your RADIUS server to recognize this and provide service parameters. +# The @host part will be stripped before the service is called. +# DON'T use this with PPP! +# +#all.passthrough @host1 @host2 +# +# Realms. Again, user@host login names are recognized, but the @host +# part is used to select different authentication/accounting hosts. +# In the first example, all four hosts are actually defined; in the +# second, there is only one authentication and one accounting host. +# Undefined hosts must be represented by empty strings. The order +# is @realm authhost1 accthost1 authhost2 accthost2. +# +#all.realm >-@flintstone fred wilma barney zelda +#all.realm >-@duck donald louie "" "" +#all.realm <+U uucpauth uucpacct "" "" +# +# '>' means that the @host part is a suffix, and '-' tells the program +# to strip the suffix if providing a login service. '<' and '+' are +# counterparts to '>' and '-', as shown in the third example, which +# does what UUCPHACK has existed for. +# +# Realm definitions are special because subsequent definitions don't +# replace the previous ones, but add to them. +# # Default IP stuff. If you end the "ipno" with a "+", the portnumber will # be added to the IP number. The IP number of a port is used when the RADIUS # server doesn't send an IP number, or if it tells us to use a dynamic ipno. @@ -156,10 +187,10 @@ all.aa 0 # # You can use this chatstring to regulary check if the modem is still alive. -# NOT IMPLEMENTED YET. +# Time is in minutes. # all.checktime 60 -all.checkchat "" AT OK\r\n +all.checkchat "" AT OK # # Flow control on this serial port: # hard - hardware, rts/cts @@ -183,9 +214,10 @@ # # PPP options - used if we have already authenticated a user # and service type is PPP. +# (session-timeout is new. --ian) # all.pppopt proxyarp modem asyncmap 0 %i:%j \ - noipx noccp \ + noipx noccp session-timeout %T \ mtu %t mru %t netmask %m idle-disconnect %I \ uselib /usr/local/portslave/lib/libpsr.so diff -r -u portslave-1.16.orig/src/server.h portslave-1.16/src/server.h --- portslave-1.16.orig/src/server.h Tue Jan 13 14:33:30 1998 +++ portslave-1.16/src/server.h Sun Aug 9 20:13:24 1998 @@ -28,7 +28,9 @@ char *dotted(unsigned int); int getty(int port, char *conn_info); int emumodem(int port, char *conn_info); +void maketermsane(void); int do_login(int port, char *login, char *pass); +int ckpassthrough(char *login, int port); int spawnit(int port, struct auth *ai); char *percent(int port, struct auth *ai, char *in); int do_slip(int port, struct auth *ai); diff -r -u portslave-1.16.orig/src/slip.c portslave-1.16/src/slip.c --- portslave-1.16.orig/src/slip.c Thu Nov 13 12:59:06 1997 +++ portslave-1.16/src/slip.c Sun Aug 9 20:13:24 1998 @@ -39,6 +39,7 @@ static void hup_handler(int sig) { got_hup = 1; + alarm(0); } /* @@ -172,6 +173,11 @@ sigaction(SIGHUP, &sa, NULL); sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); + if (ai->sessiontime > 0) { + alarm(ai->sessiontime); + sigaction(SIGALRM, &sa, NULL); + unblock(SIGALRM); + } unblock(SIGHUP); unblock(SIGINT); diff -r -u portslave-1.16.orig/src/spawnit.c portslave-1.16/src/spawnit.c --- portslave-1.16.orig/src/spawnit.c Wed Nov 12 15:04:03 1997 +++ portslave-1.16/src/spawnit.c Sun Aug 9 20:13:24 1998 @@ -51,8 +51,10 @@ signal(sig, SIG_IGN); unblock(sig); + if (sig == SIGALRM) + alarm(0); - if (pgrp > 0) kill(-pgrp, sig); + if (pgrp > 0) kill(-pgrp, sig == SIGALRM ? SIGTERM : sig); sa.sa_handler = got_hup; sa.sa_flags = SA_RESTART; @@ -60,6 +62,26 @@ } /* + * Strip the realm/passthrough from the login name, if any. + */ +static void striprealm(int port, struct auth *ai) +{ + struct realm_def *r; + char *s; + + if (ckpassthrough(ai->login, port)) { + *(s = strchr(ai->login, '@')) = '\0'; + return; + } + if ((r = ckrealm(ai->login, port)) == NULL || !r->strip) + return; + if (r->prefix) + strcpy(ai->login, ai->login + strlen(r->name)); + else + *(s = ai->login + strlen(ai->login) - strlen(r->name)) = '\0'; +} + +/* * Execute but split command line args first. */ static int doexec(char *cmd, char *argv0, char *args) @@ -85,6 +107,7 @@ { char *host = dotted(ai->address); + maketermsane(); execl(mainconf.rlogin, "rlogin", "-E", "-i", ai->login, "-l", ai->login, host, NULL); nsyslog(LOG_ERR, "%s: %m", mainconf.rlogin); @@ -92,14 +115,30 @@ } /* + * Execute a secure shell session. + */ +static int do_ssh(int port, struct auth *ai) +{ + char *host = dotted(ai->address); + + maketermsane(); + execl(mainconf.ssh, "ssh", "-e", "none", "-l", ai->login, host, NULL); + nsyslog(LOG_ERR, "%s: %m", mainconf.ssh); + return -1; +} + +/* * Execute a telnet session. * Added 1997-03-19 by Stephan Austermuehle */ static int do_telnet(int port, struct auth *ai) { char *host = dotted(ai->address); + char tcpport[10]; - execl(mainconf.telnet, "telnet", "-8", "-E", host, NULL); + maketermsane(); + sprintf(tcpport, "%u", ai->port ? ai->port : 23); + execl(mainconf.telnet, "telnet", "-E", "-l", ai->login, host, tcpport, NULL); nsyslog(LOG_ERR, "%s: %m", mainconf.telnet); return -1; } @@ -129,6 +168,7 @@ { struct utmp ut, *u; char *tty; + char lhost[UT_HOSTSIZE]; /* * Prevent hacking. @@ -166,16 +206,27 @@ if (parent) ut.ut_pid = getpid(); setutent(); pututline(&ut); + if (parent) + if (ai->address) { + char *p = dotted(ai->address); + int i = 0; + + while(*p && i < 2) + if (*p++ == '.') i++; + + sprintf(lhost, "%03d:%c.%s", port, ai->proto, p); + } else + sprintf(lhost, "%03d:", port); - /* XXXX - ugly to use external stty */ - system("exec stty sane"); + striprealm(port, ai); + maketermsane(); /* * If we are forked it also means we are already authenticated - * so don't ask for a password. */ if (parent) - execl("/bin/login", "login", "-f", ai->login, NULL); + execl("/bin/login", "login", "-f", ai->login, "-h", lhost, NULL); else execl("/bin/login", "login", ai->login, NULL); @@ -224,6 +275,11 @@ unblock(SIGHUP); unblock(SIGTERM); unblock(SIGINT); + if (ai->sessiontime > 0) { + alarm(ai->sessiontime); + sigaction(SIGALRM, &sa, NULL); + unblock(SIGALRM); + } /* * Wait for the child to exit. @@ -271,6 +327,7 @@ */ switch(ai->proto) { case P_TELNET: + striprealm(port, ai); do_telnet(port, ai); break; case P_TCPCLEAR: @@ -291,7 +348,12 @@ do_ppp(port, ai); break; case P_RLOGIN: + striprealm(port, ai); do_rlogin(port, ai); + break; + case P_SSH: + striprealm(port, ai); + do_ssh(port, ai); break; case P_LOCAL: case P_SHELL: diff -r -u portslave-1.16.orig/src/utmp.c portslave-1.16/src/utmp.c --- portslave-1.16.orig/src/utmp.c Thu Jan 22 14:14:30 1998 +++ portslave-1.16/src/utmp.c Sun Aug 9 20:13:24 1998 @@ -69,7 +69,7 @@ sprintf(tmp.ut_host, "%03d:%c.%s", port, ai->proto, p); } else - strncpy(tmp.ut_host, "%03d:", port); + sprintf(tmp.ut_host, "%03d:", port); #ifdef __linux__ tmp.ut_addr = ai->address; #endif