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