122347Spst/* opielogin.c: The infamous /bin/login 222347Spst 329964Sache%%% portions-copyright-cmetz-96 492906SmarkmPortions of this software are Copyright 1996-1999 by Craig Metz, All Rights 522347SpstReserved. The Inner Net License Version 2 applies to these portions of 622347Spstthe software. 722347SpstYou should have received a copy of the license with this software. If 822347Spstyou didn't get a copy, you may request one from <license@inner.net>. 922347Spst 1022347SpstPortions of this software are Copyright 1995 by Randall Atkinson and Dan 1122347SpstMcDonald, All Rights Reserved. All Rights under this copyright are assigned 1222347Spstto the U.S. Naval Research Laboratory (NRL). The NRL Copyright Notice and 1322347SpstLicense Agreement applies to this software. 1422347Spst 1522347Spst History: 1622347Spst 1792906Smarkm Modified by cmetz for OPIE 2.4. Omit "/dev/" in lastlog entry. 1892906Smarkm Don't chdir for invalid users. Fixed bug where getloginname() 1992906Smarkm didn't actually change spaces to underscores. Use struct 2092906Smarkm opie_key for key blocks. Do the home directory chdir() after 2192906Smarkm doing the setuid() in case we're on superuser-mapped NFS. 2292906Smarkm Initialize some variables explicitly. Call opieverify() if 2392906Smarkm login times out. Use opiestrncpy(). 2459118Skris Modified by cmetz for OPIE 2.32. Partially handle environment 2559118Skris variables on the command line (a better implementation is 2659118Skris coming soon). Handle failure to issue a challenge more 2759118Skris gracefully. 2829964Sache Modified by cmetz for OPIE 2.31. Use _PATH_NOLOGIN. Move Solaris 2929964Sache drain bamage kluge after rflag check; it breaks rlogin. 3029964Sache Use TCSAFLUSH instead of TCSANOW (except where it flushes 3129964Sache data we need). Sleep before kluging for Solaris. 3222347Spst Modified by cmetz for OPIE 2.3. Process login environment files. 3322347Spst Made logindevperm/fbtab handling more generic. Kluge around 3422347Spst Solaris drain bamage differently (maybe better?). Maybe 3522347Spst allow cleartext logins even when opiechallenge() fails. 3622347Spst Changed the conditions on when time.h and sys/time.h are 3722347Spst included. Send debug info to syslog. Use opielogin() instead 3822347Spst of dealing with utmp/setlogin() here. 3922347Spst Modified by cmetz for OPIE 2.22. Call setlogin(). Decreased default 4022347Spst timeout to two minutes. Use opiereadpass() flags to get 4122347Spst around Solaris drain bamage. 4222347Spst Modified by cmetz for OPIE 2.21. Took the sizeof() the wrong thing. 4322347Spst Modified by cmetz for OPIE 2.2. Changed prompts to ask for OTP 4422347Spst response where appropriate. Simple though small speed-up. 4522347Spst Don't allow cleartext if echo on. Don't try to clear 4622347Spst non-blocking I/O. Use opiereadpass(). Don't mess with 4722347Spst termios (as much, at least) -- that's opiereadpass()'s 4822347Spst job. Change opiereadpass() calls to add echo arg. Fixed 4922347Spst CONTROL macro. Don't modify argv (at least, unless 5022347Spst we have a reason to). Allow user in if ruserok() says 5122347Spst so. Removed useless strings (I don't think that 5222347Spst removing the ucb copyright one is a problem -- please 5322347Spst let me know if I'm wrong). Use FUNCTION declaration et 5422347Spst al. Moved definition of TRUE here. Ifdef around more 5522347Spst headers. Make everything static. Removed support for 5622347Spst omitting domain name if same domain -- it generally 5722347Spst didn't work and it would be a big portability problem. 5822347Spst Use opiereadpass() in getloginname() and then post- 5922347Spst process. Added code to grab hpux time zone from 6022347Spst /etc/src.sh. Renamed MAIL_DIR to PATH_MAIL. Removed 6122347Spst dupe catchexit and extraneous closelog. openlog() as 6222347Spst soon as possible because SunOS syslog is broken. 6322347Spst Don't print an extra blank line before a new Response 6422347Spst prompt. 6522347Spst Modified at NRL for OPIE 2.2. Changed strip_crlf to stripcrlf. 6622347Spst Do opiebackspace() on entries. 6722347Spst Modified at NRL for OPIE 2.1. Since we don't seem to use the 6822347Spst result of opiechallenge() anymore, discard it. Changed 6922347Spst BSD4_3 to HAVE_GETTTYNAM. Other symbol changes for 7022347Spst autoconf. Removed obselete usage comment. Removed 7122347Spst des_crypt.h. File renamed to opielogin.c. Added bletch 7222347Spst for setpriority. Added slash between MAIL_DIR and name. 7322347Spst Modified at NRL for OPIE 2.02. Flush stdio after printing login 7422347Spst prompt. Fixed Solaris shadow password problem introduced 7522347Spst in OPIE 2.01 (the shadow password structure is spwd, not 7622347Spst spasswd). 7722347Spst Modified at NRL for OPIE 2.01. Changed password lookup handling 7822347Spst to use a static structure to avoid problems with drain- 7922347Spst bamaged shadow password packages. Make sure to close 8022347Spst syslog by function to avoid problems with drain bamaged 8122347Spst syslog implementations. Log a few interesting errors. 8222347Spst Modified at NRL for OPIE 2.0. 8322347Spst Modified at Bellcore for the Bellcore S/Key Version 1 software 8422347Spst distribution. 8522347Spst Originally from BSD. 8622347Spst*/ 8722347Spst/* 8822347Spst * Portions of this software are 8922347Spst * Copyright (c) 1980,1987 Regents of the University of California. 9022347Spst * All rights reserved. The Berkeley software License Agreement 9122347Spst * specifies the terms and conditions for redistribution. 9222347Spst */ 9322347Spst 9422347Spst#include "opie_cfg.h" /* OPIE: defines symbols for filenames & pathnames */ 9522347Spst#if HAVE_SYS_PARAM_H 9622347Spst#include <sys/param.h> 9722347Spst#endif /* HAVE_SYS_PARAM_H */ 9822347Spst#include <sys/stat.h> 9922347Spst#include <sys/types.h> 10022347Spst 10122347Spst#if HAVE_SETPRIORITY && HAVE_SYS_RESOURCE_H 10222347Spst#include <sys/resource.h> 10322347Spst#endif /* HAVE_SETPRIORITY && HAVE_SYS_RESOURCE_H */ 10422347Spst 10522347Spst#if TIME_WITH_SYS_TIME 10622347Spst# include <sys/time.h> 10722347Spst# include <time.h> 10822347Spst#else /* TIME_WITH_SYS_TIME */ 10922347Spst#if HAVE_SYS_TIME_H 11022347Spst#include <sys/time.h> 11122347Spst#else /* HAVE_SYS_TIME_H */ 11222347Spst#include <time.h> 11322347Spst#endif /* HAVE_SYS_TIME_H */ 11422347Spst#endif /* TIME_WITH_SYS_TIME */ 11522347Spst 11622347Spst#if HAVE_SYS_FILE_H 11722347Spst#include <sys/file.h> 11822347Spst#endif /* HAVE_SYS_FILE_H */ 11922347Spst#include <signal.h> 12022347Spst#if HAVE_PWD_H 12122347Spst#include <pwd.h> /* POSIX Password routines */ 12222347Spst#endif /* HAVE_PWD_H */ 12322347Spst#include <stdio.h> 12422347Spst#include <errno.h> 12522347Spst#if HAVE_UNISTD_H 12622347Spst#include <unistd.h> /* Basic POSIX macros and functions */ 12722347Spst#endif /* HAVE_UNISTD_H */ 12822347Spst#include <termios.h> /* POSIX terminal I/O */ 12922347Spst#if HAVE_STRING_H 13022347Spst#include <string.h> /* ANSI C string functions */ 13122347Spst#endif /* HAVE_STRING_H */ 13222347Spst#include <fcntl.h> /* File I/O functions */ 13322347Spst#include <syslog.h> 13422347Spst#include <grp.h> 13522347Spst#include <netdb.h> 13622347Spst#include <netinet/in.h> /* contains types needed for next include file */ 13722347Spst#include <arpa/inet.h> /* Inet addr<-->ascii functions */ 13822347Spst#if HAVE_STDLIB_H 13922347Spst#include <stdlib.h> 14022347Spst#endif /* HAVE_STDLIB_H */ 14129964Sache#if HAVE_SYS_SELECT_H 14229964Sache#include <sys/select.h> 14329964Sache#endif /* HAVE_SYS_SELECT_H */ 14422347Spst 14522347Spst#ifdef QUOTA 14622347Spst#include <sys/quota.h> 14722347Spst#endif 14822347Spst 14922347Spst#if HAVE_GETTTYNAM 15022347Spst#include <sys/ioctl.h> /* non-portable routines used only a few places */ 15122347Spst#include <ttyent.h> 15222347Spst#endif /* HAVE_GETTTYNAM */ 15322347Spst 15422347Spst#include "opie.h" 15522347Spst 15622347Spst#define TTYGID(gid) tty_gid(gid) /* gid that owns all ttys */ 15722347Spst 15822347Spst#define NMAX 32 15922347Spst#define HMAX 256 16022347Spst 16122347Spst#if HAVE_LASTLOG_H 16222347Spst#include <lastlog.h> 16322347Spst#endif /* HAVE_LASTLOG_H */ 16422347Spst 16522347Spststatic int rflag = 0; 16622347Spststatic int usererr = -1; 16792906Smarkmstatic int stopmotd = 0; 16822347Spststatic char rusername[NMAX + 1]; 16922347Spststatic char name[NMAX + 1] = ""; 17022347Spststatic char minusnam[16] = "-"; 17122347Spststatic char *envinit[1]; /* now set by setenv calls */ 17292906Smarkmstatic char term[64] = ""; /* important to initialise to a NULL string */ 17392906Smarkmstatic char host[HMAX + 1] = ""; 17422347Spststatic struct passwd nouser; 17522347Spststatic struct passwd thisuser; 17622347Spst 17722347Spst#if HAVE_SHADOW_H 17822347Spst#include <shadow.h> 17922347Spst#endif /* HAVE_SHADOW_H */ 18022347Spst 18122347Spststatic char *ttyprompt; 18222347Spst 18322347Spst#ifdef PERMSFILE 18422347Spstextern char *home; 18522347Spst#endif /* PERMSFILE */ 18622347Spst 18722347Spststatic struct termios attr; 18822347Spst 18922347Spstextern int errno; 19022347Spst 19122347Spststatic int ouroptind; 19222347Spststatic char *ouroptarg; 19322347Spst 19422347Spst#if HAVE_LASTLOG_H 19522347Spst#ifndef _PATH_LASTLOG 19622347Spst#define _PATH_LASTLOG "/var/adm/lastlog" 19722347Spst#endif /* _PATH_LASTLOG */ 19822347Spst 19922347Spststatic char lastlog[] = _PATH_LASTLOG; 20022347Spst#endif /* HAVE_LASTLOG_H */ 20122347Spst 20222347Spst/* 20322347Spst * The "timeout" variable bounds the time given to login. 20422347Spst * We initialize it here for safety and so that it can be 20522347Spst * patched on machines where the default value is not appropriate. 20622347Spst */ 20722347Spststatic int timeout = 120; 20822347Spst 20922347Spststatic void getstr __P((char *, int, char *)); 21022347Spst 21122347Spst#if HAVE_CRYPT_H 21222347Spst#include <crypt.h> 21322347Spst#endif /* HAVE_CRYPT_H */ 21422347Spst 21522347Spst#undef TRUE 21622347Spst#define TRUE -1 21722347Spst 21892906Smarkmstatic int need_opieverify = 0; 21992906Smarkmstatic struct opie opie; 22092906Smarkm 22122347Spst#ifdef TIOCSWINSZ 22222347Spst/* Windowing variable relating to JWINSIZE/TIOCSWINSZ/TIOCGWINSZ. This is 22322347Spstavailable on BSDish systems and at least Solaris 2.x, but portability to 22422347Spstother systems is questionable. Use within this source code module is 22522347Spstprotected by suitable defines. 22622347Spst 22722347SpstI'd be interested in hearing about a more portable approach. rja */ 22822347Spst 22922347Spststatic struct winsize win = {0, 0, 0, 0}; 23022347Spst#endif 23122347Spst 23222347Spst 23322347Spst/*------------------ BEGIN REAL CODE --------------------------------*/ 23422347Spst 23522347Spst/* We allow the malloc()s to potentially leak data out because we can 23622347Spstonly call this routine about four times in the lifetime of this process 23722347Spstand the kernel will free all heap memory when we exit or exec. */ 23822347Spststatic int lookupuser FUNCTION_NOARGS 23922347Spst{ 24022347Spst struct passwd *pwd; 24122347Spst#if HAVE_SHADOW 24222347Spst struct spwd *spwd; 24322347Spst#endif /* HAVE_SHADOW */ 24422347Spst 24522347Spst memcpy(&thisuser, &nouser, sizeof(thisuser)); 24622347Spst 24722347Spst if (!(pwd = getpwnam(name))) 24822347Spst return -1; 24922347Spst 25022347Spst thisuser.pw_uid = pwd->pw_uid; 25122347Spst thisuser.pw_gid = pwd->pw_gid; 25222347Spst 25322347Spst if (!(thisuser.pw_name = malloc(strlen(pwd->pw_name) + 1))) 25422347Spst goto lookupuserbad; 25522347Spst strcpy(thisuser.pw_name, pwd->pw_name); 25622347Spst 25722347Spst if (!(thisuser.pw_dir = malloc(strlen(pwd->pw_dir) + 1))) 25822347Spst goto lookupuserbad; 25922347Spst strcpy(thisuser.pw_dir, pwd->pw_dir); 26022347Spst 26122347Spst if (!(thisuser.pw_shell = malloc(strlen(pwd->pw_shell) + 1))) 26222347Spst goto lookupuserbad; 26322347Spst strcpy(thisuser.pw_shell, pwd->pw_shell); 26422347Spst 26522347Spst#if HAVE_SHADOW 26622347Spst if (!(spwd = getspnam(name))) 26722347Spst goto lookupuserbad; 26822347Spst 26922347Spst pwd->pw_passwd = spwd->sp_pwdp; 27022347Spst 27122347Spst endspent(); 27222347Spst#endif /* HAVE_SHADOW */ 27322347Spst 27422347Spst if (!(thisuser.pw_passwd = malloc(strlen(pwd->pw_passwd) + 1))) 27522347Spst goto lookupuserbad; 27622347Spst strcpy(thisuser.pw_passwd, pwd->pw_passwd); 27722347Spst 27822347Spst endpwent(); 27922347Spst 28022347Spst return ((thisuser.pw_passwd[0] == '*') || (thisuser.pw_passwd[0] == '#')); 28122347Spst 28222347Spstlookupuserbad: 28322347Spst memcpy(&thisuser, &nouser, sizeof(thisuser)); 28422347Spst return -1; 28522347Spst} 28622347Spst 28722347Spststatic VOIDRET getloginname FUNCTION_NOARGS 28822347Spst{ 28992906Smarkm char *namep, d; 29022347Spst int flags; 29122347Spst static int first = 1; 29222347Spst 29322347Spst memset(name, 0, sizeof(name)); 29422347Spst 29522347Spst d = 0; 29622347Spst while (name[0] == '\0') { 29722347Spst flags = 1; 29822347Spst if (ttyprompt) { 29922347Spst if (first) { 30022347Spst flags = 4; 30122347Spst first--; 30222347Spst } else 30392906Smarkm printf(ttyprompt); 30422347Spst } else 30522347Spst printf("login: "); 30622347Spst fflush(stdout); 30722347Spst if (++d == 3) 30822347Spst exit(0); 30922347Spst if (!opiereadpass(name, sizeof(name)-1, flags)) { 31022347Spst syslog(LOG_CRIT, "End-of-file (or other error?) on stdin!"); 31122347Spst exit(0); 31222347Spst } 31322347Spst for (namep = name; *namep; namep++) { 31492906Smarkm if (*namep == ' ') 31592906Smarkm *namep = '_'; 31622347Spst } 31722347Spst } 31822347Spst} 31922347Spst 32022347Spststatic VOIDRET timedout FUNCTION((i), int i) 32122347Spst{ 32222347Spst /* input variable declared just to keep the compiler quiet */ 32322347Spst printf("Login timed out after %d seconds\n", timeout); 32422347Spst syslog(LOG_CRIT, "Login timed out after %d seconds!", timeout); 32592906Smarkm 32692906Smarkm if (need_opieverify) 32792906Smarkm opieverify(&opie, NULL); 32892906Smarkm 32922347Spst exit(0); 33022347Spst} 33122347Spst 33222347Spst#if !HAVE_MOTD_IN_PROFILE 33322347Spststatic VOIDRET catch FUNCTION((i), int i) 33422347Spst{ 33522347Spst /* the input variable is declared to keep the compiler quiet */ 33622347Spst signal(SIGINT, SIG_IGN); 33722347Spst stopmotd++; 33822347Spst} 33922347Spst#endif /* !HAVE_MOTD_IN_PROFILE */ 34022347Spst 34122347Spststatic VOIDRET catchexit FUNCTION_NOARGS 34222347Spst{ 34322347Spst int i; 34429964Sache tcsetattr(STDIN_FILENO, TCSAFLUSH, &attr); 34522347Spst putchar('\n'); 34622347Spst closelog(); 34722347Spst for (i = sysconf(_SC_OPEN_MAX); i > 2; i--) 34822347Spst close(i); 34922347Spst} 35022347Spst 35122347Spststatic int rootterm FUNCTION((ttyn), char *ttyn) 35222347Spst{ 35322347Spst#if HAVE_GETTTYNAM 35422347Spst/* The getttynam() call and the ttyent structure first appeared in 4.3 BSD and 35522347Spstare not portable to System V systems such as Solaris 2.x. or modern versions 35622347Spstof IRIX rja */ 35722347Spst register struct ttyent *t; 35822347Spst char *tty; 35922347Spst 36022347Spst tty = strrchr(ttyn, '/'); 36122347Spst 36222347Spst if (tty == NULL) 36322347Spst tty = ttyn; 36422347Spst else 36522347Spst tty++; 36622347Spst 36722347Spst if ((t = getttynam(tty)) != NULL) 36822347Spst return (t->ty_status & TTY_SECURE); 36922347Spst 37022347Spst return (1); /* when in doubt, allow root logins */ 37122347Spst 37222347Spst#elif HAVE_ETC_DEFAULT_LOGIN 37322347Spst 37422347Spst FILE *filno; 37522347Spst char line[128]; 37622347Spst char *next, *next2; 37722347Spst 37822347Spst/* SVR4 only permits two security modes for root logins: 1) only from CONSOLE, 37922347Spstif the string "CONSOLE=/dev/console" exists and is not commented out with "#" 38022347Spstcharacters, or 2) from anywhere. 38122347Spst 38222347SpstSo we open /etc/default/login file grab the file contents one line at a time 38322347Spstverify that the line being tested isn't commented out check for the substring 38422347Spst"CONSOLE" and decide whether to permit this attempted root login/su. */ 38522347Spst 38622347Spst if ((filno = fopen("/etc/default/login", "r")) != NULL) { 38722347Spst while (fgets(line, 128, filno) != NULL) { 38822347Spst next = line; 38922347Spst 39022347Spst if ((line[0] != '#') && (next = strstr(line, "CONSOLE"))) { 39122347Spst next += 7; /* get past the string "CONSOLE" */ 39222347Spst 39322347Spst while (*next && (*next == ' ') || (*next == '\t')) 39422347Spst next++; 39522347Spst 39622347Spst if (*(next++) != '=') 39722347Spst break; /* some weird character, get next line */ 39822347Spst 39922347Spst next2 = next; 40022347Spst while (*next2 && (*next2 != '\t') && (*next2 != ' ') && 40122347Spst (*next2 != '\n')) 40222347Spst next2++; 40322347Spst *next2 = 0; 40422347Spst 40522347Spst return !strcmp(ttyn, next); /* Allow the login if and only if the 40622347Spst user's terminal line matches the 40722347Spst setting for CONSOLE */ 40822347Spst } 40922347Spst } /* end while another line could be obtained */ 41022347Spst } /* end if could open file */ 41122347Spst return (1); /* when no CONSOLE line exists, root can login from anywhere */ 41222347Spst#elif HAVE_SECURETTY 41322347Spst { 41422347Spst FILE *f; 41522347Spst char buffer[1024], *c; 41622347Spst int rc = 0; 41722347Spst 41822347Spst if (!(f = fopen("/etc/securetty", "r"))) 41922347Spst return 1; 42022347Spst 42122347Spst if (c = strstr(ttyn, "/dev/")) 42222347Spst ttyn += 5; 42322347Spst 42422347Spst if (c = strrchr(ttyn, '/')) 42522347Spst ttyn = ++c; 42622347Spst 42722347Spst while (fgets(buffer, sizeof(buffer), f)) { 42822347Spst if (c = strrchr(buffer, '\n')) 42922347Spst *c = 0; 43022347Spst 43122347Spst if (!(c = strrchr(buffer, '/'))) 43222347Spst c = buffer; 43322347Spst else 43422347Spst c++; 43522347Spst 43622347Spst if (!strcmp(c, ttyn)) 43722347Spst rc = 1; 43822347Spst }; 43922347Spst 44022347Spst fclose(f); 44122347Spst return rc; 44222347Spst } 44322347Spst#else 44422347Spst return (1); /* when in doubt, allow root logins */ 44522347Spst#endif 44622347Spst} 44722347Spst 44822347Spststatic int doremotelogin FUNCTION((host), char *host) 44922347Spst{ 45022347Spst int rc; 45122347Spst 45222347Spst getstr(rusername, sizeof(rusername), "remuser"); 45322347Spst getstr(name, sizeof(name), "locuser"); 45422347Spst getstr(term, sizeof(term), "Terminal type"); 45522347Spst if (getuid()) { 45622347Spst memcpy(&thisuser, &nouser, sizeof(thisuser)); 45722347Spst syslog(LOG_ERR, "getuid() failed"); 45822347Spst return (-1); 45922347Spst } 46022347Spst if (lookupuser()) { 46122347Spst syslog(LOG_ERR, "lookup failed for user %s", name); 46222347Spst return (-1); 46322347Spst } 46422347Spst rc = ruserok(host, !thisuser.pw_uid, rusername, name); 46522347Spst if (rc == -1) { 46622347Spst syslog(LOG_ERR, 46722347Spst "ruserok failed, host=%s, uid=%d, remote username=%s, local username=%s", 46822347Spst host, thisuser.pw_uid, rusername, name); 46922347Spst } 47022347Spst return rc; 47122347Spst} 47222347Spst 47322347Spst 47422347Spststatic VOIDRET getstr FUNCTION((buf, cnt, err), char *buf AND int cnt AND char *err) 47522347Spst{ 47622347Spst char c; 47722347Spst 47822347Spst do { 47922347Spst if (read(0, &c, 1) != 1) 48022347Spst exit(1); 48122347Spst if (--cnt < 0) { 48222347Spst printf("%s too long\r\n", err); 48322347Spst syslog(LOG_CRIT, "%s too long", err); 48422347Spst exit(1); 48522347Spst } 48622347Spst *buf++ = c; 48722347Spst } 48822347Spst while ((c != 0) && (c != '~')); 48922347Spst} 49022347Spst 49122347Spststruct speed_xlat { 49222347Spst char *c; 49322347Spst int i; 49422347Spst} speeds[] = { 49522347Spst 49622347Spst#ifdef B0 49722347Spst { 49822347Spst "0", B0 49922347Spst }, 50022347Spst#endif /* B0 */ 50122347Spst#ifdef B50 50222347Spst { 50322347Spst "50", B50 50422347Spst }, 50522347Spst#endif /* B50 */ 50622347Spst#ifdef B75 50722347Spst { 50822347Spst "75", B75 50922347Spst }, 51022347Spst#endif /* B75 */ 51122347Spst#ifdef B110 51222347Spst { 51322347Spst "110", B110 51422347Spst }, 51522347Spst#endif /* B110 */ 51622347Spst#ifdef B134 51722347Spst { 51822347Spst "134", B134 51922347Spst }, 52022347Spst#endif /* B134 */ 52122347Spst#ifdef B150 52222347Spst { 52322347Spst "150", B150 52422347Spst }, 52522347Spst#endif /* B150 */ 52622347Spst#ifdef B200 52722347Spst { 52822347Spst "200", B200 52922347Spst }, 53022347Spst#endif /* B200 */ 53122347Spst#ifdef B300 53222347Spst { 53322347Spst "300", B300 53422347Spst }, 53522347Spst#endif /* B300 */ 53622347Spst#ifdef B600 53722347Spst { 53822347Spst "600", B600 53922347Spst }, 54022347Spst#endif /* B600 */ 54122347Spst#ifdef B1200 54222347Spst { 54322347Spst "1200", B1200 54422347Spst }, 54522347Spst#endif /* B1200 */ 54622347Spst#ifdef B1800 54722347Spst { 54822347Spst "1800", B1800 54922347Spst }, 55022347Spst#endif /* B1800 */ 55122347Spst#ifdef B2400 55222347Spst { 55322347Spst "2400", B2400 55422347Spst }, 55522347Spst#endif /* B2400 */ 55622347Spst#ifdef B4800 55722347Spst { 55822347Spst "4800", B4800 55922347Spst }, 56022347Spst#endif /* B4800 */ 56122347Spst#ifdef B7200 56222347Spst { 56322347Spst "7200", B7200 56422347Spst }, 56522347Spst#endif /* B7200 */ 56622347Spst#ifdef B9600 56722347Spst { 56822347Spst "9600", B9600 56922347Spst }, 57022347Spst#endif /* B9600 */ 57122347Spst#ifdef B14400 57222347Spst { 57322347Spst "14400", B14400 57422347Spst }, 57522347Spst#endif /* B14400 */ 57622347Spst#ifdef B19200 57722347Spst { 57822347Spst "19200", B19200 57922347Spst }, 58022347Spst#endif /* B19200 */ 58122347Spst#ifdef B28800 58222347Spst { 58322347Spst "28800", B28800 58422347Spst }, 58522347Spst#endif /* B28800 */ 58622347Spst#ifdef B38400 58722347Spst { 58822347Spst "38400", B38400 58922347Spst }, 59022347Spst#endif /* B38400 */ 59122347Spst#ifdef B57600 59222347Spst { 59322347Spst "57600", B57600 59422347Spst }, 59522347Spst#endif /* B57600 */ 59622347Spst#ifdef B115200 59722347Spst { 59822347Spst "115200", B115200 59922347Spst }, 60022347Spst#endif /* B115200 */ 60122347Spst#ifdef B230400 60222347Spst { 60322347Spst "230400", B230400 60422347Spst }, 60522347Spst#endif /* 230400 */ 60622347Spst { 60722347Spst NULL, 0 60822347Spst } 60922347Spst}; 61022347Spst 61122347Spststatic VOIDRET doremoteterm FUNCTION((term), char *term) 61222347Spst{ 61322347Spst register char *cp = strchr(term, '/'); 61422347Spst char *speed; 61522347Spst struct speed_xlat *x; 61622347Spst 61722347Spst if (cp) { 61822347Spst *cp++ = '\0'; 61922347Spst speed = cp; 62022347Spst cp = strchr(speed, '/'); 62122347Spst if (cp) 62222347Spst *cp++ = '\0'; 62322347Spst for (x = speeds; x->c != NULL; x++) 62422347Spst if (strcmp(x->c, speed) == 0) { 62522347Spst cfsetispeed(&attr, x->i); 62622347Spst cfsetospeed(&attr, x->i); 62722347Spst break; 62822347Spst } 62922347Spst } 63022347Spst} 63122347Spst 63222347Spststatic int tty_gid FUNCTION((default_gid), int default_gid) 63322347Spst{ 63422347Spst struct group *gr; 63522347Spst int gid = default_gid; 63622347Spst 63722347Spst gr = getgrnam(TTYGRPNAME); 63822347Spst if (gr != (struct group *) 0) 63922347Spst gid = gr->gr_gid; 64022347Spst endgrent(); 64122347Spst return (gid); 64222347Spst} 64322347Spst 64422347Spstint main FUNCTION((argc, argv), int argc AND char *argv[]) 64522347Spst{ 64622347Spst extern char **environ; 64722347Spst register char *namep; 64822347Spst 64922347Spst int invalid, quietlog; 65022347Spst FILE *nlfd; 65122347Spst char *tty, host[256]; 65222347Spst int pflag = 0, hflag = 0, fflag = 0; 65322347Spst int t, c; 65422347Spst int i; 65522347Spst char *p; 65622347Spst char opieprompt[OPIE_CHALLENGE_MAX + 1]; 65759118Skris int af_pwok; 65892906Smarkm int authsok = 0; 65922347Spst char *pp; 66022347Spst char buf[256]; 66122347Spst int uid; 66222347Spst int opiepassed; 66322347Spst 66422347Spst#ifndef DEBUG 66522347Spst if (geteuid()) { 66692906Smarkm fprintf(stderr, "This program requires super-user privileges.\n"); 66722347Spst exit(1); 66822347Spst } 66922347Spst#endif /* DEBUG */ 67022347Spst 67129964Sache for (t = sysconf(_SC_OPEN_MAX); t > 2; t--) 67229964Sache close(t); 67329964Sache 67422347Spst openlog("login", LOG_ODELAY, LOG_AUTH); 67522347Spst 67622347Spst /* initialisation */ 67722347Spst host[0] = '\0'; 67822347Spst opieprompt[0] = '\0'; 67922347Spst 68022347Spst if (p = getenv("TERM")) { 68122347Spst#ifdef DEBUG 68222347Spst syslog(LOG_DEBUG, "environment TERM=%s", p); 68322347Spst#endif /* DEBUG */ 68492906Smarkm opiestrncpy(term, p, sizeof(term)); 68522347Spst }; 68622347Spst 68722347Spst memset(&nouser, 0, sizeof(nouser)); 68822347Spst nouser.pw_uid = -1; 68922347Spst nouser.pw_gid = -1; 69022347Spst nouser.pw_passwd = "#nope"; 69122347Spst nouser.pw_name = nouser.pw_gecos = nouser.pw_dir = nouser.pw_shell = ""; 69222347Spst 69322347Spst#if HAVE_SETPRIORITY && HAVE_SYS_RESOURCE_H 69422347Spst setpriority(PRIO_PROCESS, 0, 0); 69522347Spst#endif /* HAVE_SETPRIORITY && HAVE_SYS_RESOURCE_H */ 69622347Spst 69722347Spst signal(SIGALRM, timedout); 69822347Spst alarm(timeout); 69922347Spst signal(SIGQUIT, SIG_IGN); 70022347Spst signal(SIGINT, SIG_IGN); 70122347Spst 70222347Spst#if DOTTYPROMPT 70322347Spst ttyprompt = (char *) getenv("TTYPROMPT"); 70422347Spst#endif /* TTYPROMPT */ 70522347Spst 70622347Spst#ifdef QUOTA 70722347Spst quota(Q_SETUID, 0, 0, 0); 70822347Spst#endif 70922347Spst 71022347Spst#ifdef DEBUG 71192906Smarkm syslog(LOG_DEBUG, "my args are: (argc=%d)", i = argc); 71292906Smarkm while (--i) 71392906Smarkm syslog(LOG_DEBUG, "%d: %s", i, argv[i]); 71422347Spst#endif /* DEBUG */ 71522347Spst 71622347Spst/* Implement our own getopt()-like functionality, but do so in a much more 71722347Spst strict manner to prevent security problems. */ 71822347Spst for (ouroptind = 1; ouroptind < argc; ouroptind++) { 71959118Skris if (!argv[ouroptind]) 72059118Skris continue; 72159118Skris 72259118Skris if (argv[ouroptind][0] == '-') { 72359118Skris char *c = argv[ouroptind] + 1; 72459118Skris 72559118Skris while(*c) { 72659118Skris switch(*(c++)) { 72759118Skris case 'd': 72859118Skris if (*c || (++ouroptind == argc)) 72959118Skris exit(1); 73059118Skris 73122347Spst/* The '-d' option is apparently a performance hack to get around 73222347Spst ttyname() being slow. The potential does exist for it to be used 73322347Spst for malice, and it does not seem to be strictly necessary, so we 73422347Spst will just eat it. */ 73559118Skris break; 73622347Spst 73759118Skris case 'r': 73859118Skris if (rflag || hflag || fflag) { 73959118Skris fprintf(stderr, "Other options not allowed with -r\n"); 74059118Skris exit(1); 74159118Skris } 74259118Skris 74359118Skris if (*c || (++ouroptind == argc)) 74459118Skris exit(1); 74559118Skris 74659118Skris if (!(ouroptarg = argv[ouroptind])) 74759118Skris exit(1); 74859118Skris 74959118Skris rflag = -1; 75059118Skris if (!doremotelogin(ouroptarg)) 75159118Skris rflag = 1; 75259118Skris 75392906Smarkm opiestrncpy(host, ouroptarg, sizeof(host)); 75459118Skris break; 75559118Skris 75659118Skris case 'h': 75759118Skris if (!getuid()) { 75822347Spst if (rflag || hflag || fflag) { 75959118Skris fprintf(stderr, "Other options not allowed with -h\n"); 76022347Spst exit(1); 76122347Spst } 76259118Skris hflag = 1; 76359118Skris 76459118Skris if (*c || (++ouroptind == argc)) 76522347Spst exit(1); 76622347Spst 76759118Skris if (!(ouroptarg = argv[ouroptind])) 76822347Spst exit(1); 76959118Skris 77092906Smarkm opiestrncpy(host, ouroptarg, sizeof(host)); 77159118Skris } 77259118Skris break; 77322347Spst 77459118Skris case 'f': 77559118Skris if (rflag) { 77659118Skris fprintf(stderr, "Only one of -r and -f allowed\n"); 77759118Skris exit(1); 77859118Skris } 77959118Skris fflag = 1; 78022347Spst 78159118Skris if (*c || (++ouroptind == argc)) 78259118Skris exit(1); 78322347Spst 78459118Skris if (!(ouroptarg = argv[ouroptind])) 78559118Skris exit(1); 78622347Spst 78792906Smarkm opiestrncpy(name, ouroptarg, sizeof(name)); 78859118Skris break; 78959118Skris case 'p': 79059118Skris pflag = 1; 79159118Skris break; 79259118Skris }; 79359118Skris }; 79459118Skris continue; 79559118Skris }; 79622347Spst 79759118Skris if (strchr(argv[ouroptind], '=')) { 79859118Skris if (!strncmp(argv[ouroptind], "TERM=", 5)) { 79992906Smarkm opiestrncpy(term, &(argv[ouroptind][5]), sizeof(term)); 80092906Smarkm 80159118Skris#ifdef DEBUG 80259118Skris syslog(LOG_DEBUG, "passed TERM=%s, ouroptind = %d", term, ouroptind); 80359118Skris#endif /* DEBUG */ 80459118Skris } else { 80559118Skris#ifdef DEBUG 80659118Skris syslog(LOG_DEBUG, "eating %s, ouroptind = %d", argv[ouroptind], ouroptind); 80759118Skris#endif /* DEBUG */ 80859118Skris }; 80959118Skris continue; 81059118Skris }; 81122347Spst 81292906Smarkm opiestrncpy(name, argv[ouroptind], sizeof(name)); 81359118Skris }; 81422347Spst 81522347Spst#ifdef TIOCNXCL 81622347Spst /* BSDism: not sure how to rewrite for POSIX. rja */ 81722347Spst ioctl(0, TIOCNXCL, 0); /* set non-exclusive use of tty */ 81822347Spst#endif 81922347Spst 82022347Spst /* get original termio attributes */ 82122347Spst if (tcgetattr(STDIN_FILENO, &attr) != 0) 82222347Spst return (-1); 82322347Spst 82422347Spst/* If talking to an rlogin process, propagate the terminal type and baud rate 82522347Spst across the network. */ 82622347Spst if (rflag) 82722347Spst doremoteterm(term); 82829964Sache else { 82929964Sache struct termios termios; 83029964Sache fd_set fds; 83129964Sache struct timeval timeval; 83229964Sache 83329964Sache memset(&timeval, 0, sizeof(struct timeval)); 83429964Sache 83529964Sache FD_ZERO(&fds); 83629964Sache FD_SET(0, &fds); 83722347Spst 83829964Sache#if HAVE_USLEEP 83929964Sache usleep(1); 84029964Sache#endif /* HAVE_USLEEP */ 84129964Sache 84229964Sache if (select(1, &fds, NULL, NULL, &timeval)) { 84329964Sache#ifdef DEBUG 84429964Sache syslog(LOG_DEBUG, "reading user name from tty buffer"); 84529964Sache#endif /* DEBUG */ 84629964Sache 84729964Sache if (tcgetattr(0, &termios)) { 84829964Sache#ifdef DEBUG 84929964Sache syslog(LOG_DEBUG, "tcgetattr(0, &termios) failed"); 85029964Sache#endif /* DEBUG */ 85129964Sache exit(1); 85229964Sache } 85329964Sache 85429964Sache termios.c_lflag &= ~ECHO; 85529964Sache 85629964Sache if (tcsetattr(0, TCSANOW, &termios)) { 85729964Sache#ifdef DEBUG 85829964Sache syslog(LOG_DEBUG, "tcsetattr(0, &termios) failed"); 85929964Sache#endif /* DEBUG */ 86029964Sache exit(1); 86129964Sache } 86229964Sache 86329964Sache if ((i = read(0, name, sizeof(name)-1)) > 0) 86429964Sache name[i] = 0; 86529964Sache if ((p = strchr(name, '\r'))) 86629964Sache *p = 0; 86729964Sache if ((p = strchr(name, '\n'))) 86829964Sache *p = 0; 86929964Sache } 87029964Sache } 87129964Sache 87222347Spst/* Force termios portable control characters to the system default values as 87322347Spstspecified in termios.h. This should help the one-time password login feel the 87422347Spstsame as the vendor-supplied login. Common extensions are also set for 87522347Spstcompleteness, but these are set within appropriate defines for portability. */ 87622347Spst 87722347Spst#define CONTROL(x) (x - 64) 87822347Spst 87922347Spst#ifdef VEOF 88022347Spst#ifdef CEOF 88122347Spst attr.c_cc[VEOF] = CEOF; 88222347Spst#else /* CEOF */ 88322347Spst attr.c_cc[VEOF] = CONTROL('D'); 88422347Spst#endif /* CEOF */ 88522347Spst#endif /* VEOF */ 88622347Spst#ifdef VEOL 88722347Spst#ifdef CEOL 88822347Spst attr.c_cc[VEOL] = CEOL; 88922347Spst#else /* CEOL */ 89022347Spst attr.c_cc[VEOL] = CONTROL('J'); 89122347Spst#endif /* CEOL */ 89222347Spst#endif /* VEOL */ 89322347Spst#ifdef VERASE 89422347Spst#ifdef CERASE 89522347Spst attr.c_cc[VERASE] = CERASE; 89622347Spst#else /* CERASE */ 89722347Spst attr.c_cc[VERASE] = CONTROL('H'); 89822347Spst#endif /* CERASE */ 89922347Spst#endif /* VERASE */ 90022347Spst#ifdef VINTR 90122347Spst#ifdef CINTR 90222347Spst attr.c_cc[VINTR] = CINTR; 90322347Spst#else /* CINTR */ 90422347Spst attr.c_cc[VINTR] = CONTROL('C'); 90522347Spst#endif /* CINTR */ 90622347Spst#endif /* VINTR */ 90722347Spst#ifdef VKILL 90822347Spst#ifdef CKILL 90922347Spst attr.c_cc[VKILL] = CKILL; 91022347Spst#else /* CKILL */ 91122347Spst attr.c_cc[VKILL] = CONTROL('U'); 91222347Spst#endif /* CKILL */ 91322347Spst#endif /* VKILL */ 91422347Spst#ifdef VQUIT 91522347Spst#ifdef CQUIT 91622347Spst attr.c_cc[VQUIT] = CQUIT; 91722347Spst#else /* CQUIT */ 91822347Spst attr.c_cc[VQUIT] = CONTROL('\\'); 91922347Spst#endif /* CQUIT */ 92022347Spst#endif /* VQUIT */ 92122347Spst#ifdef VSUSP 92222347Spst#ifdef CSUSP 92322347Spst attr.c_cc[VSUSP] = CSUSP; 92422347Spst#else /* CSUSP */ 92522347Spst attr.c_cc[VSUSP] = CONTROL('Z'); 92622347Spst#endif /* CSUSP */ 92722347Spst#endif /* VSUSP */ 92822347Spst#ifdef VSTOP 92922347Spst#ifdef CSTOP 93022347Spst attr.c_cc[VSTOP] = CSTOP; 93122347Spst#else /* CSTOP */ 93222347Spst attr.c_cc[VSTOP] = CONTROL('S'); 93322347Spst#endif /* CSTOP */ 93422347Spst#endif /* VSTOP */ 93522347Spst#ifdef VSTART 93622347Spst#ifdef CSTART 93722347Spst attr.c_cc[VSTART] = CSTART; 93822347Spst#else /* CSTART */ 93922347Spst attr.c_cc[VSTART] = CONTROL('Q'); 94022347Spst#endif /* CSTART */ 94122347Spst#endif /* VSTART */ 94222347Spst#ifdef VDSUSP 94322347Spst#ifdef CDSUSP 94422347Spst attr.c_cc[VDSUSP] = CDSUSP; 94522347Spst#else /* CDSUSP */ 94622347Spst attr.c_cc[VDSUSP] = 0; 94722347Spst#endif /* CDSUSP */ 94822347Spst#endif /* VDSUSP */ 94922347Spst#ifdef VEOL2 95022347Spst#ifdef CEOL2 95122347Spst attr.c_cc[VEOL2] = CEOL2; 95222347Spst#else /* CEOL2 */ 95322347Spst attr.c_cc[VEOL2] = 0; 95422347Spst#endif /* CEOL2 */ 95522347Spst#endif /* VEOL2 */ 95622347Spst#ifdef VREPRINT 95722347Spst#ifdef CRPRNT 95822347Spst attr.c_cc[VREPRINT] = CRPRNT; 95922347Spst#else /* CRPRNT */ 96022347Spst attr.c_cc[VREPRINT] = 0; 96122347Spst#endif /* CRPRNT */ 96222347Spst#endif /* VREPRINT */ 96322347Spst#ifdef VWERASE 96422347Spst#ifdef CWERASE 96522347Spst attr.c_cc[VWERASE] = CWERASE; 96622347Spst#else /* CWERASE */ 96722347Spst attr.c_cc[VWERASE] = 0; 96822347Spst#endif /* CWERASE */ 96922347Spst#endif /* VWERASE */ 97022347Spst#ifdef VLNEXT 97122347Spst#ifdef CLNEXT 97222347Spst attr.c_cc[VLNEXT] = CLNEXT; 97322347Spst#else /* CLNEXT */ 97422347Spst attr.c_cc[VLNEXT] = 0; 97522347Spst#endif /* CLNEXT */ 97622347Spst#endif /* VLNEXT */ 97722347Spst 97822347Spst attr.c_lflag |= ICANON; /* enable canonical input processing */ 97922347Spst attr.c_lflag &= ~ISIG; /* disable INTR, QUIT,& SUSP signals */ 98022347Spst attr.c_lflag |= (ECHO | ECHOE); /* enable echo and erase */ 98122347Spst#ifdef ONLCR 98222347Spst /* POSIX does not specify any output processing flags, but the usage below 98322347Spst is SVID compliant and is generally portable to modern versions of UNIX. */ 98422347Spst attr.c_oflag |= ONLCR; /* map CR to CRNL on output */ 98522347Spst#endif 98622347Spst#ifdef ICRNL 98722347Spst attr.c_iflag |= ICRNL; 98822347Spst#endif /* ICRNL */ 98922347Spst 99022347Spst attr.c_oflag |= OPOST; 99122347Spst attr.c_lflag |= ICANON; /* enable canonical input */ 99222347Spst attr.c_lflag |= ECHO; 99322347Spst attr.c_lflag |= ECHOE; /* enable ERASE character */ 99422347Spst attr.c_lflag |= ECHOK; /* enable KILL to delete line */ 99522347Spst attr.c_cflag |= HUPCL; /* hangup on close */ 99622347Spst 99722347Spst /* Set revised termio attributes */ 99829964Sache if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &attr)) 99922347Spst return (-1); 100022347Spst 100122347Spst atexit(catchexit); 100222347Spst 100322347Spst tty = ttyname(0); 100422347Spst 100522347Spst if (tty == (char *) 0 || *tty == '\0') 100622347Spst tty = "UNKNOWN"; /* was: "/dev/tty??" */ 100722347Spst 100822347Spst#if HAVE_SETVBUF && defined(_IONBF) 100922347Spst#if SETVBUF_REVERSED 101022347Spst setvbuf(stdout, _IONBF, NULL, 0); 101122347Spst setvbuf(stderr, _IONBF, NULL, 0); 101222347Spst#else /* SETVBUF_REVERSED */ 101322347Spst setvbuf(stdout, NULL, _IONBF, 0); 101422347Spst setvbuf(stderr, NULL, _IONBF, 0); 101522347Spst#endif /* SETVBUF_REVERSED */ 101622347Spst#endif /* HAVE_SETVBUF && defined(_IONBF) */ 101722347Spst 101822347Spst#ifdef DEBUG 101922347Spst syslog(LOG_DEBUG, "tty = %s", tty); 102022347Spst#endif /* DEBUG */ 102122347Spst 102222347Spst#ifdef HAVE_LOGIN_ENVFILE 102322347Spst { 102422347Spst FILE *f; 102522347Spst 102622347Spst if (f = fopen(HAVE_LOGIN_ENVFILE, "r")) { 102722347Spst char line[128], *c, *c2; 102822347Spst 102922347Spst while(fgets(line, sizeof(line)-1, f)) { 103022347Spst c = line; 103122347Spst while(*c && (isalnum(*c) || (*c == '_'))) c++; 103222347Spst if (*c == '=') { 103322347Spst *(c++) = 0; 103422347Spst if (c2 = strchr(c, ';')) 103522347Spst *c2 = 0; 103622347Spst if (c2 = strchr(c, '\n')) 103722347Spst *c2 = 0; 103822347Spst if (c2 = strchr(c, ' ')) 103922347Spst continue; 104022347Spst if (c2 = strchr(c, '\t')) 104122347Spst continue; 104222347Spst if (!strcmp(line, "TZ")) 104322347Spst continue; 104422347Spst if (setenv(line, c, 1) < 0) { 104522347Spst fprintf(stderr, "setenv() failed -- environment full?\n"); 104622347Spst break; 104722347Spst } 104822347Spst } 104922347Spst } 105022347Spst fclose(f); 105122347Spst } 105222347Spst } 105322347Spst#endif /* HAVE_LOGIN_ENVFILE */ 105422347Spst 105522347Spst t = 0; 105622347Spst invalid = TRUE; 105722347Spst af_pwok = opieaccessfile(host); 105822347Spst 105922347Spst if (name[0]) 106022347Spst if (name[0] == '-') { 106122347Spst fprintf(stderr, "User names can't start with '-'.\n"); 106222347Spst syslog(LOG_AUTH, "Attempt to use invalid username: %s.", name); 106322347Spst exit(1); 106422347Spst } else 106522347Spst invalid = lookupuser(); 106622347Spst 106722347Spst do { 106822347Spst /* If remote login take given name, otherwise prompt user for something. */ 106922347Spst if (invalid && !name[0]) { 107022347Spst getloginname(); 107122347Spst invalid = lookupuser(); 107259118Skris authsok = 0; 107322347Spst } 107422347Spst#ifdef DEBUG 107522347Spst syslog(LOG_DEBUG, "login name is +%s+, of length %d, [0] = %d", name, strlen(name), name[0]); 107622347Spst#endif /* DEBUG */ 107722347Spst 107822347Spst if (fflag) { 107922347Spst uid = getuid(); 108022347Spst 108122347Spst if (uid != 0 && uid != thisuser.pw_uid) 108222347Spst fflag = 0; 108322347Spst /* Disallow automatic login for root. */ 108422347Spst if (thisuser.pw_uid == 0) 108522347Spst fflag = 0; 108622347Spst } 108722347Spst if (feof(stdin)) 108822347Spst exit(0); 108922347Spst 109022347Spst /* If no remote login authentication and a password exists for this user, 109122347Spst prompt for and verify a password. */ 109222347Spst if (!fflag && (rflag < 1) && *thisuser.pw_passwd) { 109322347Spst#ifdef DEBUG 109422347Spst syslog(LOG_DEBUG, "login name is +%s+, of length %d, [0] = %d\n", name, strlen(name), name[0]); 109522347Spst#endif /* DEBUG */ 109622347Spst 109722347Spst /* Attempt a one-time password challenge */ 109822347Spst i = opiechallenge(&opie, name, opieprompt); 109992906Smarkm need_opieverify = TRUE; 110022347Spst 110122347Spst if ((i < 0) || (i > 1)) { 110222347Spst syslog(LOG_ERR, "error: opiechallenge() returned %d, errno=%d!\n", i, errno); 110322347Spst } else { 110422347Spst printf("%s\n", opieprompt); 110559118Skris authsok |= 1; 110622347Spst } 110722347Spst 110822347Spst if (!memcmp(&thisuser, &nouser, sizeof(thisuser))) 110922347Spst if (host[0]) 111022347Spst syslog(LOG_WARNING, "Invalid login attempt for %s on %s from %s.", 111122347Spst name, tty, host); 111222347Spst else 111322347Spst syslog(LOG_WARNING, "Invalid login attempt for %s on %s.", 111422347Spst name, tty); 111522347Spst 111659118Skris if (af_pwok && opiealways(thisuser.pw_dir)) 111759118Skris authsok |= 2; 111859118Skris 111922347Spst#if DEBUG 112059118Skris syslog(LOG_DEBUG, "af_pwok = %d, authsok = %d", af_pwok, authsok); 112122347Spst#endif /* DEBUG */ 112222347Spst 112359118Skris if (!authsok) 112459118Skris syslog(LOG_ERR, "no authentication methods are available for %s!", name); 112522347Spst 112622347Spst#if NEW_PROMPTS 112759118Skris if ((authsok & 1) || !authsok) 112822347Spst printf("Response"); 112959118Skris if (((authsok & 3) == 3) || !authsok) 113022347Spst printf(" or "); 113159118Skris if ((authsok & 2) || !authsok) 113222347Spst printf("Password"); 113322347Spst printf(": "); 113459118Skris fflush(stdout); 113559118Skris if (!opiereadpass(buf, sizeof(buf), !(authsok & 2))) 113622347Spst invalid = TRUE; 113722347Spst#else /* NEW_PROMPTS */ 113892906Smarkm if ((authsok & 3) == 1) 113922347Spst printf("(OTP response required)\n"); 114022347Spst printf("Password:"); 114122347Spst fflush(stdout); 114222347Spst if (!opiereadpass(buf, sizeof(buf), 0)) 114322347Spst invalid = TRUE; 114422347Spst#endif /* NEW_PROMPTS */ 114522347Spst 114659118Skris if (!buf[0] && (authsok & 1)) { 114759118Skris authsok &= ~2; 114822347Spst /* Null line entered, so display appropriate prompt & flush current 114922347Spst data. */ 115022347Spst#if NEW_PROMPTS 115122347Spst printf("Response: "); 115222347Spst#else /* NEW_PROMPTS */ 115322347Spst printf(" (echo on)\nPassword:"); 115422347Spst#endif /* NEW_PROMPTS */ 115522347Spst if (!opiereadpass(buf, sizeof(buf), 1)) 115622347Spst invalid = TRUE; 115722347Spst } 115822347Spst 115959118Skris if (authsok & 1) { 116022347Spst i = opiegetsequence(&opie); 116122347Spst opiepassed = !opieverify(&opie, buf); 116292906Smarkm need_opieverify = 0; 116322347Spst 116422347Spst#ifdef DEBUG 116522347Spst syslog(LOG_DEBUG, "opiepassed = %d", opiepassed); 116622347Spst#endif /* DEBUG */ 116722347Spst } 116822347Spst 116922347Spst if (!invalid) { 117059118Skris if ((authsok & 1) && opiepassed) { 117122347Spst if (i < 10) { 117222347Spst printf("Warning: Re-initialize your OTP information"); 117322347Spst if (i < 5) 117422347Spst printf(" NOW!"); 117522347Spst printf("\n"); 117622347Spst } 117722347Spst } else { 117859118Skris if (authsok & 2) { 117922347Spst pp = crypt(buf, thisuser.pw_passwd); 118022347Spst invalid = strcmp(pp, thisuser.pw_passwd); 118122347Spst } else 118222347Spst invalid = TRUE; 118322347Spst } 118422347Spst } 118522347Spst } 118622347Spst 118722347Spst /* If user not super-user, check for logins disabled. */ 118822347Spst if (thisuser.pw_uid) { 118929964Sache if (nlfd = fopen(_PATH_NOLOGIN, "r")) { 119022347Spst while ((c = getc(nlfd)) != EOF) 119122347Spst putchar(c); 119222347Spst fflush(stdout); 119322347Spst sleep(5); 119422347Spst exit(0); 119522347Spst } 119622347Spst } 119722347Spst /* If valid so far and root is logging in, see if root logins on this 119822347Spst terminal are permitted. */ 119922347Spst if (!invalid && !thisuser.pw_uid && !rootterm(tty)) { 120022347Spst if (host[0]) 120122347Spst syslog(LOG_CRIT, "ROOT LOGIN REFUSED ON %s FROM %.*s", 120222347Spst tty, HMAX, host); 120322347Spst else 120422347Spst syslog(LOG_CRIT, "ROOT LOGIN REFUSED ON %s", tty); 120522347Spst invalid = TRUE; 120622347Spst } 120722347Spst /* If invalid, then log failure attempt data to appropriate system 120822347Spst logfiles and close the connection. */ 120922347Spst if (invalid) { 121022347Spst printf("Login incorrect\n"); 121122347Spst if (host[0]) 121222347Spst syslog(LOG_ERR, "LOGIN FAILURE ON %s FROM %.*s, %.*s", 121322347Spst tty, HMAX, host, sizeof(name), name); 121422347Spst else 121522347Spst syslog(LOG_ERR, "LOGIN FAILURE ON %s, %.*s", 121622347Spst tty, sizeof(name), name); 121722347Spst if (++t >= 5) 121822347Spst exit(1); 121922347Spst } 122022347Spst if (*thisuser.pw_shell == '\0') 122122347Spst thisuser.pw_shell = "/bin/sh"; 122222347Spst /* Remote login invalid must have been because of a restriction of some 122322347Spst sort, no extra chances. */ 122422347Spst if (invalid) { 122522347Spst if (!usererr) 122622347Spst exit(1); 122722347Spst name[0] = 0; 122822347Spst } 122922347Spst } 123022347Spst while (invalid); 123122347Spst /* Committed to login -- turn off timeout */ 123222347Spst alarm(0); 123322347Spst 123422347Spst#ifdef QUOTA 123522347Spst if (quota(Q_SETUID, thisuser.pw_uid, 0, 0) < 0 && errno != EINVAL) { 123622347Spst if (errno == EUSERS) 123722347Spst printf("%s.\n%s.\n", "Too many users logged on already", 123822347Spst "Try again later"); 123922347Spst else 124022347Spst if (errno == EPROCLIM) 124122347Spst printf("You have too many processes running.\n"); 124222347Spst else 124322347Spst perror("quota (Q_SETUID)"); 124422347Spst sleep(5); 124522347Spst exit(0); 124622347Spst } 124722347Spst#endif 124822347Spst 124922347Spst if (opielogin(tty, name, host)) 125022347Spst syslog(LOG_ERR, "can't record login: tty %s, name %s, host %s", tty, name, host); 125122347Spst 125222347Spst quietlog = !access(QUIET_LOGIN_FILE, F_OK); 125322347Spst 125422347Spst#if HAVE_LASTLOG_H 125522347Spst { 125622347Spst int f; 125722347Spst 125822347Spst if ((f = open(lastlog, O_RDWR)) >= 0) { 125922347Spst struct lastlog ll; 126022347Spst 126122347Spst lseek(f, (long)thisuser.pw_uid * sizeof(struct lastlog), 0); 126222347Spst 126322347Spst if ((sizeof(ll) == read(f, (char *) &ll, sizeof(ll))) && 126422347Spst (ll.ll_time != 0) && (!quietlog)) { 126522347Spst printf("Last login: %.*s ", 126622347Spst 24 - 5, (char *) ctime(&ll.ll_time)); 126722347Spst if (*ll.ll_host != '\0') 126822347Spst printf("from %.*s\n", sizeof(ll.ll_host), ll.ll_host); 126922347Spst else 127022347Spst printf("on %.*s\n", sizeof(ll.ll_line), ll.ll_line); 127122347Spst } 127222347Spst lseek(f, (long)thisuser.pw_uid * sizeof(struct lastlog), 0); 127322347Spst 127422347Spst time(&ll.ll_time); 127592906Smarkm if (!strncmp(tty, "/dev/", 5)) 127692906Smarkm opiestrncpy(ll.ll_line, tty + 5, sizeof(ll.ll_line)); 127792906Smarkm else 127892906Smarkm opiestrncpy(ll.ll_line, tty, sizeof(ll.ll_line)); 127992906Smarkm opiestrncpy(ll.ll_host, host, sizeof(ll.ll_host)); 128022347Spst write(f, (char *) &ll, sizeof ll); 128122347Spst close(f); 128222347Spst } 128322347Spst } 128422347Spst#endif /* HAVE_LASTLOG_H */ 128522347Spst 128622347Spst chown(tty, thisuser.pw_uid, TTYGID(thisuser.pw_gid)); 128722347Spst 128822347Spst#ifdef TIOCSWINSZ 128922347Spst/* POSIX does not specify any interface to set/get window sizes, so this is 129022347Spstnot portable. It should work on most recent BSDish systems and the defines 129122347Spstshould protect it on older System Vish systems. It does work under Solaris 129222347Spst2.4, though it isn't clear how many other SVR4 systems support it. I'd be 129322347Spstinterested in hearing of a more portable approach. rja */ 129422347Spst if (!hflag && !rflag) 129522347Spst ioctl(0, TIOCSWINSZ, &win); /* set window size to 0,0,0,0 */ 129622347Spst#endif 129722347Spst 129822347Spst chmod(tty, 0622); 129922347Spst setgid(thisuser.pw_gid); 130022347Spst initgroups(name, thisuser.pw_gid); 130122347Spst 130222347Spst#ifdef QUOTA 130322347Spst quota(Q_DOWARN, thisuser.pw_uid, (dev_t) - 1, 0); 130422347Spst#endif 130522347Spst 130622347Spst#ifdef PERMSFILE 130722347Spst home = thisuser.pw_dir; 130822347Spst permsfile(name, tty, thisuser.pw_uid, thisuser.pw_gid); 130922347Spst fflush(stderr); 131022347Spst#endif /* PERMSFILE */ 131122347Spst 131222347Spst setuid(thisuser.pw_uid); 131322347Spst 131422347Spst /* destroy environment unless user has asked to preserve it */ 131522347Spst if (!pflag) 131622347Spst environ = envinit; 131722347Spst setenv("HOME", thisuser.pw_dir, 1); 131822347Spst setenv("SHELL", thisuser.pw_shell, 1); 131992906Smarkm 132092906Smarkm if (chdir(thisuser.pw_dir) < 0) { 132192906Smarkm#if DEBUG 132292906Smarkm syslog(LOG_DEBUG, "chdir(%s): %s(%d)", thisuser.pw_dir, strerror(errno), 132392906Smarkm errno); 132492906Smarkm#endif /* DEBUG */ 132592906Smarkm if (chdir("/") < 0) { 132692906Smarkm printf("No directory!\n"); 132792906Smarkm invalid = TRUE; 132892906Smarkm } else { 132992906Smarkm printf("No directory! %s\n", "Logging in with HOME=/"); 133092906Smarkm strcpy(thisuser.pw_dir, "/"); 133192906Smarkm } 133292906Smarkm } 133392906Smarkm 133422347Spst if (!term[0]) { 133522347Spst#if HAVE_GETTTYNAM 133622347Spst/* 133722347Spst * The getttynam() call and the ttyent structure first appeared in 4.3 BSD. 133822347Spst * They are not portable to System V systems such as Solaris 2.x. 133922347Spst * rja 134022347Spst */ 134122347Spst register struct ttyent *t; 134222347Spst register char *c; 134322347Spst 134422347Spst if (c = strrchr(tty, '/')) 134522347Spst c++; 134622347Spst else 134722347Spst c = tty; 134822347Spst 134922347Spst if (t = getttynam(c)) 135092906Smarkm opiestrncpy(term, t->ty_type, sizeof(term)); 135122347Spst else 135222347Spst#endif /* HAVE_GETTTYNAM */ 135322347Spst strcpy(term, "unknown"); 135422347Spst } 135522347Spst 135622347Spst setenv("USER", name, 1); 135722347Spst setenv("LOGNAME", name, 1); 135822347Spst setenv("PATH", DEFAULT_PATH, 0); 135922347Spst if (term[0]) { 136022347Spst#ifdef DEBUG 136122347Spst syslog(LOG_DEBUG, "setting TERM=%s", term); 136222347Spst#endif /* DEBUG */ 136322347Spst setenv("TERM", term, 1); 136422347Spst } 136522347Spst 136622347Spst#ifdef HAVE_LOGIN_ENVFILE 136722347Spst { 136822347Spst FILE *f; 136922347Spst 137022347Spst if (f = fopen(HAVE_LOGIN_ENVFILE, "r")) { 137122347Spst char line[128], *c, *c2; 137222347Spst 137322347Spst while(fgets(line, sizeof(line)-1, f)) { 137422347Spst c = line; 137522347Spst while(*c && (isalnum(*c) || (*c == '_'))) c++; 137622347Spst if (*c == '=') { 137722347Spst *(c++) = 0; 137822347Spst if (c2 = strchr(c, ';')) 137922347Spst *c2 = 0; 138022347Spst if (c2 = strchr(c, '\n')) 138122347Spst *c2 = 0; 138222347Spst if (c2 = strchr(c, ' ')) 138322347Spst continue; 138422347Spst if (c2 = strchr(c, '\t')) 138522347Spst continue; 138622347Spst if (setenv(line, c, 0) < 0) { 138722347Spst fprintf(stderr, "setenv() failed -- environment full?\n"); 138822347Spst break; 138922347Spst } 139022347Spst } 139122347Spst } 139222347Spst fclose(f); 139322347Spst } 139422347Spst } 139522347Spst#endif /* HAVE_LOGIN_ENVFILE */ 139622347Spst 139722347Spst if ((namep = strrchr(thisuser.pw_shell, '/')) == NULL) 139822347Spst namep = thisuser.pw_shell; 139922347Spst else 140022347Spst namep++; 140122347Spst strcat(minusnam, namep); 140222347Spst if (tty[sizeof("tty") - 1] == 'd') 140322347Spst syslog(LOG_INFO, "DIALUP %s, %s", tty, name); 140422347Spst if (!thisuser.pw_uid) 140522347Spst if (host[0]) 140622347Spst syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %.*s", tty, HMAX, host); 140722347Spst else 140822347Spst syslog(LOG_NOTICE, "ROOT LOGIN %s", tty); 140922347Spst#if !HAVE_MOTD_IN_PROFILE 141022347Spst if (!quietlog) { 141122347Spst FILE *mf; 141222347Spst register c; 141322347Spst 141422347Spst signal(SIGINT, catch); 141522347Spst if ((mf = fopen(MOTD_FILE, "r")) != NULL) { 141622347Spst while ((c = getc(mf)) != EOF && !stopmotd) 141722347Spst putchar(c); 141822347Spst fclose(mf); 141922347Spst } 142022347Spst signal(SIGINT, SIG_IGN); 142122347Spst } 142222347Spst#endif /* !HAVE_MOTD_IN_PROFILE */ 142322347Spst#if !HAVE_MAILCHECK_IN_PROFILE 142422347Spst if (!quietlog) { 142522347Spst struct stat st; 142622347Spst char buf[128]; 142722347Spst int len; 142822347Spst 142992906Smarkm opiestrncpy(buf, PATH_MAIL, sizeof(buf) - 2); 143022347Spst 143122347Spst len = strlen(buf); 143222347Spst if (*(buf + len - 1) != '/') { 143322347Spst *(buf + len) = '/'; 143422347Spst *(buf + len + 1) = 0; 143522347Spst } 143622347Spst 143722347Spst strcat(buf, name); 143822347Spst#if DEBUG 143922347Spst syslog(LOG_DEBUG, "statting %s", buf); 144022347Spst#endif /* DEBUG */ 144122347Spst if (!stat(buf, &st) && st.st_size) 144222347Spst printf("You have %smail.\n", 144322347Spst (st.st_mtime > st.st_atime) ? "new " : ""); 144422347Spst } 144522347Spst#endif /* !HAVE_MAILCHECK_IN_PROFILE */ 144622347Spst signal(SIGALRM, SIG_DFL); 144722347Spst signal(SIGQUIT, SIG_DFL); 144822347Spst signal(SIGINT, SIG_DFL); 144922347Spst signal(SIGTSTP, SIG_IGN); 145022347Spst 145122347Spst attr.c_lflag |= (ISIG | IEXTEN); 145222347Spst 145322347Spst catchexit(); 145422347Spst execlp(thisuser.pw_shell, minusnam, 0); 145522347Spst perror(thisuser.pw_shell); 145622347Spst printf("No shell\n"); 145722347Spst exit(0); 145822347Spst} 1459