|
|
1.1 root 1: static char _version[]="login version 3.2.1";
2: /*
3: * Rec'd from Lauren Weinstein, 7-16-84.
4: * Hacked by rec to enable remote kludge on pdp11 10-84.
5: * Hacked extensively by rec 84-11-02.
6: * Added terminal locking and version number October 1991 by piggy.
7: *
8: * login connects a user terminal:
9: * 1) unless executed by /etc/getty, the terminal is set back to
10: * default modes and characters while preserving the speeds
11: * and the parity.
12: * 2) The user name supplied or prompted for is located in the
13: * password file, and the password, if any is specified,
14: * is prompted for, encrypted, and compared to the specified
15: * password.
16: * 3) If the user name did not exist, or the password was wrong, the
17: * login is reported as incorrect and the procedure repeats.
18: * 4) If the tty is identified as 'remote' then:
19: * a) at most MAXFAIL attempts are permitted before the tty
20: * is hung up.
21: * b) at most MAXTIME seconds are permitted for a successful
22: * login before the tty is hung up.
23: * c) if the user has no password, and the REMACC user in
24: * /etc/passwd does have a password, then the REMACC password
25: * must be supplied. If this program is compiled with
26: * "BBS" defined, then a valid serial number must be supplied
27: * at the remote access password prompt.
28: * 5) An unsuccessful login appends a utmp record to the file
29: * /usr/adm/failed if it exists.
30: * It also removes the tty lock from /usr/spool/uucp.
31: * 6) A successful login:
32: * a-1) Locks the tty in /usr/spool/uucp.
33: * a) chdir's to the home directory specified by /etc/passwd
34: * b) writes utmp records to /usr/adm/wtmp and /etc/utmp if.
35: * possible.
36: * c) chowns the tty to be owned by the user.
37: * d) chmods the tty to TTYMODE mode.
38: * e) sets the user and group id's as specified by /etc/passwd.
39: * f) sets USER to the user name matched in /etc/passwd.
40: * g) sets HOME to the home directory specified in /etc/passwd.
41: * h) sets SHELL to the shell specified in /etc/passwd.
42: * i) exec's /bin/sh as "-sh" if and only if the shell
43: * specified in /etc/passwd is either blank or /bin/sh,
44: * otherwise as "+sh"; the "+/-" is for the benefit of /bin/sh.
45: *
46: * All other connect procedures and initializations should be performed by
47: * including them in /etc/profile or $HOME/.profile which the shell will
48: * perform before exec'ing the command interpreter specified by $SHELL.
49: * The shell will exit if any signals are received during /etc/profile.
50: */
51: #include <stdio.h>
52: #include <pwd.h>
53: #include <signal.h>
54: #include <utmp.h>
55: #include <sys/dir.h>
56: #include <sys/stat.h>
57: #include <sgtty.h>
58: #if NEWTTYS
59: #include <sys/tty.h>
60: #endif
61: #include <sys/deftty.h>
62: #ifdef BBS
63: #include <sys/types.h>
64: #endif
65:
66: extern long lseek();
67: #ifdef BBS
68: extern int chk_srlno();
69: extern time_t time();
70: #endif
71:
72: #define FALSE 0
73: #define TRUE 1
74:
75: #define TTYMODE (S_IREAD|S_IWRITE|S_IEXEC)
76: #define MAXFAIL 3 /* Maximum permitted failed login attempts */
77: #define MAXTIME 60 /* Maximum seconds permitted for login */
78: #define PASSLEN 13 /* Length of encrypted passwords */
79: #define ACCNAME "remacc" /* Remote access password dummy username */
80: #define NBUF 128 /* Assorted buffers */
81: #define LOGMSG "/etc/logmsg" /* Login message file */
82: #define DEFMSG "Login: " /* Default login message */
83:
84: /*
85: * Default sgtty and tchars settings.
86: */
87:
88: struct sgttyb defsgt = { /* Initial sgtty */
89: DEF_SG_ISPEED,
90: DEF_SG_OSPEED,
91: DEF_SG_ERASE,
92: DEF_SG_KILL,
93: DEF_SG_FLAGS
94: };
95:
96: struct tchars deftch = { /* Initial tchars */
97: DEF_T_INTRC,
98: DEF_T_QUITC,
99: DEF_T_STARTC,
100: DEF_T_STOPC,
101: DEF_T_EOFC,
102: DEF_T_BRKC
103: };
104:
105: /*
106: * Default environment list for shell.
107: */
108: #define NDENV 64
109: char euser[NDENV] = "USER=root";
110: char ehome[NDENV] = "HOME=/etc";
111: char eshell[NDENV] = "SHELL=";
112: char *defenv0[] = { /* Default environment for super user */
113: euser, ehome, "PATH=/bin:/usr/bin:/etc:", "PS1=# ", eshell, NULL
114: };
115: char *defenvn[] = { /* Default environment for other user */
116: euser, ehome, "PATH=:/bin:/usr/bin", "PS1=$ ", eshell, NULL
117: };
118:
119: /*
120: * Assorted data.
121: */
122: char faillog[] = "/usr/adm/failed"; /* failed login attempt log */
123: char wholog[] = "/etc/utmp"; /* current login log */
124: char motd[] = "/etc/motd"; /* message of the day */
125: char goodlog[] = "/usr/adm/wtmp"; /* successful login log */
126: #ifdef BBS
127: char goodsrl[] = "/usr/adm/wsrl"; /* successful login log */
128: #endif
129: char *prompt[] = {
130: "Password: ", /* password msg 1 */
131: #ifdef BBS
132: "BBS access password: " /* password msg 2 */
133: #else
134: "Remote access password: " /* password msg 2 */
135: #endif
136: };
137: char buff[NBUF]; /* I/O buffer */
138: char *argv0 = "login"; /* Command name */
139:
140: #ifdef BBS
141: static int good_serialno;
142: FILE * fp_srl;
143: time_t tnum;
144: #endif
145:
146: main(argc, argv) int argc; char *argv[];
147: {
148: register char *cp; /* Password pointer */
149: register struct passwd *pwp;
150: int i, fd;
151: int oldtime; /* Alarm temporary */
152: int failed = TRUE; /* Assume cracker */
153: int remote = FALSE; /* Assume not remote tty line */
154: int passcount = 0; /* Password pass */
155: int logcount = 0; /* Login attempt count */
156: char *s_tty; /* tty name */
157: char *s_user; /* user name, saved in euser[] */
158: char *s_dir; /* user directory, saved in ehome[] */
159: char *s_shell; /* user shell, saved in eshell[] */
160: int s_uid; /* user id */
161: int s_gid; /* group id */
162: extern int timeout(); /* Login attempt alarm function */
163: extern char *crypt();
164: extern char *getpass();
165: extern char *ttyname();
166: extern char *strcpy();
167: extern char *index();
168:
169: if (argc > 0)
170: argv0 = argv[0];
171:
172: /* Usage check */
173: if (argc < 1 || argc > 2) {
174: fprintf(stderr, "Usage: %s [username]\n", argv0);
175: slowexit(1);
176: }
177:
178: /* Login no args, let getty start us from scratch */
179: if (argc == 1 && argv0[0] != '-')
180: exit(0);
181:
182: /* Default signals */
183: for (i=1; i<=NSIG; i++)
184: signal(i, SIG_DFL);
185:
186: /* Default file descriptors */
187: for (i=3; close(i)>=0; i++)
188: ;
189:
190: /* Locate buffers */
191: s_dir = index(ehome, '=') + 1;
192: s_user = index(euser, '=') + 1;
193: s_shell = index(eshell, '=') + 1;
194:
195: /* Find out tty, and reset if necessary */
196: if ((s_tty = ttyname(2)) == NULL) {
197: fprintf(stderr, "%s: cannot find terminal.\n", argv0);
198: slowexit(1);
199: }
200:
201: /*
202: * If login has been exec()'d by a login shell, there will
203: * already be a lock file. Fortunately, this lock file belongs
204: * to us, so we can remove it. If there is a lock file that
205: * doesn't belong to us, unlocktty() won't remove it, and the
206: * subsequent locktty() will fail, as it should. We are
207: * explicitly ignoring the return value of unlocktty().
208: */
209: (void) unlocktty(strrchr(s_tty, '/') + 1);
210:
211: /* Let's lock this tty, so nobody else grabs it until we log out. */
212: if (-1 == locktty(strrchr(s_tty, '/') + 1) ){
213: fprintf(stderr, "%s: cannot lock terminal.\n", argv0);
214: slowexit(1);
215: }
216:
217: if (argv0[0] != '-' /* Not called from /etc/getty */
218: && settty(2) != 0) { /* Reset terminal failed */
219: perror(s_tty);
220: slowexit(1);
221: }
222:
223: if (argv0[0] == '-' && argv0[1] == 'r') /* Isolate remote determination */
224: { remote = TRUE;
225: signal(SIGALRM, &timeout); /* catch login timeout */
226: alarm(MAXTIME); /* set timeout alarm */
227: }
228:
229: again: failed = TRUE; /* assume attempt will fail */
230: setpwent(); /* rewind password file */
231: if (remote && (++logcount > MAXFAIL)) /* count remote attempts */
232: slowexit(1); /* exit (and try force hangup) if too many attempts */
233:
234: if (passcount == 0) /* first pass?, user name and password */
235: { if (argc > 1)
236: { strcpy(buff, argv[1]); /* Use argument once */
237: argc = 0;
238: }
239: else
240: {
241: do {
242: printprompt();
243: if (fgets(buff, NBUF-1, stdin) == NULL)
244: { putchar('\n');
245: slowexit(1);
246: }
247: } while (buff[0] == '\n' && buff[1] == 0);
248: buff[strlen(buff)-1] = 0; /* null terminate over newline */
249: }
250: pwp = getpwnam(buff); /* get name entry */
251: if (pwp != NULL) /* if entry found */
252: {
253: if (strcmp(pwp->pw_name, ACCNAME) == 0) {
254: printf("Login incorrect\n"); /* disallow remacc logins */
255: goto again;
256: }
257: strcpy(s_user, pwp->pw_name); /* save name */
258: s_uid = pwp->pw_uid; /* save uid */
259: s_gid = pwp->pw_gid; /* save gid */
260: strcpy(s_dir, pwp->pw_dir); /* save directory */
261: strcpy(s_shell, (*pwp->pw_shell == '\0') ? "/bin/sh"
262: : pwp->pw_shell);
263: }
264: }
265: else /* second pass, remote access password */
266: {
267: #ifdef BBS
268: pwp = NULL;
269: #else
270: pwp = getpwnam(ACCNAME); /* check for remote access entry */
271: if (pwp == NULL || pwp->pw_passwd[0] == 0) /* no access pass? */
272: goto ok; /* all done */
273: #endif
274: }
275:
276: if (pwp == NULL /* Not a user name */
277: || pwp->pw_passwd[0] != 0) /* Password present */
278: { if ((cp = getpass(prompt[passcount])) != NULL && cp[0] != '\0') {
279: #ifdef BBS
280: if (passcount == 0) {
281: #endif
282: cp = crypt(cp, pwp==NULL ? "xx" : pwp->pw_passwd);
283: if (pwp != NULL
284: && strcmp(cp, pwp->pw_passwd) == 0
285: && strcmp(s_user, ACCNAME) != 0
286: && strlen(pwp->pw_passwd) == PASSLEN)
287: failed = FALSE; /* success */
288: #ifdef BBS
289: } else { /* for BBS, second password is a serial # */
290: if (chk_srlno(cp)) {
291: failed = FALSE; /* success */
292: good_serialno = TRUE;
293: }
294: }
295: #endif
296: }
297:
298: if (failed) /* failed attempt? */
299: { oldtime = alarm(0); /* turn off alarm */
300: passcount = 0; /* reset pass count */
301: setutmp(s_tty, buff, faillog, FALSE); /* failed attempt */
302: alarm(oldtime); /* continue timeout */
303: printf("Login incorrect\n"); /* incorrect */
304: goto again;
305: }
306: }
307:
308: if (remote && passcount++ == 0) /* need another pass? */
309: { logcount--; /* don't count as login attempt */
310: goto again; /* yes */
311: }
312:
313: ok: alarm(0); /* turn off login alarm timeout */
314: endpwent(); /* close password file */
315: if (chdir(s_dir) < 0) { /* cd to $HOME */
316: perror(s_dir);
317: slowexit(1);
318: }
319: setutmp(s_tty, buff, goodlog, TRUE); /* successful login */
320: #ifdef BBS
321: /*
322: * for BBS users, write "xxxxxxxxx time tty" to /usr/adm/wsrl
323: * where xxxxxxxxx is the serial number
324: * time is decimal long value of clock time at login
325: * tty is login device minus "/dev/"
326: */
327: if (good_serialno) {
328: good_serialno = FALSE;
329: if (fp_srl = fopen(goodsrl, "a")) {
330: time(&tnum);
331: fprintf(fp_srl, "%s %10ld %s\n", cp, tnum, s_tty+5);
332: fclose(fp_srl);
333: }
334: }
335: #endif
336: chown(s_tty, s_uid, s_gid); /* grab the terminal */
337: chmod(s_tty, TTYMODE); /* initialize its modes */
338: setgid(s_gid); /* set group */
339: setuid(s_uid); /* set user */
340: if ((fd = open(motd, 0)) >= 0) { /* list message of day */
341: while ((i = read(fd, buff, NBUF)) > 0)
342: write(2, buff, i);
343: close(fd);
344: }
345: execle("/bin/sh",
346: strcmp(s_shell, "/bin/sh") ? "+sh" : "-sh",
347: NULL,
348: s_uid == 0 ? defenv0 : defenvn);
349: fprintf(stderr, "No /bin/sh.\n");
350: slowexit(1);
351: }
352:
353: /*
354: * Write out an accounting entry for
355: * 'tty' and 'username' into filename pointed to by "filep".
356: * If "success" is TRUE (indicating a good login) also write 'utmp' entry.
357: */
358: setutmp(tty, username, filep, success)
359: char *tty, *username, *filep;
360: {
361: time_t time();
362: struct utmp utmp;
363: struct utmp spare;
364: fsize_t freeslot = -1, slot = 0;
365: register ufd;
366:
367: utmp.ut_time = time(NULL);
368: strncpy(utmp.ut_line, tty+5, 8);
369: strncpy(utmp.ut_name, username, DIRSIZ);
370: if ((ufd = open(filep, 1)) >= 0) {
371: lseek(ufd, 0L, 2);
372: write(ufd, &utmp, sizeof (utmp));
373: close(ufd);
374: }
375: if (!success) /* failed login attempt? */
376: return; /* all done */
377:
378: if ((ufd = open("/etc/utmp", 2)) >= 0) {
379: while (read(ufd, &spare, sizeof (spare)) == sizeof (spare)) {
380: if (spare.ut_line[0] == '\0')
381: freeslot = slot;
382: else if (strncmp(spare.ut_line, utmp.ut_line, 8) == 0) {
383: freeslot = slot;
384: break;
385: }
386: slot += sizeof (utmp);
387: }
388: if (freeslot >= 0)
389: lseek(ufd, freeslot, 0);
390: write(ufd, &utmp, sizeof (utmp));
391: close (ufd);
392: }
393: }
394:
395: /* login alarm timeout routine */
396: timeout()
397: {
398: printf("\n"); /* neatness */
399: slowexit(1); /* exit (and try force hangup for remote line) */
400: }
401:
402: /*
403: * Set the characters for the terminal to the defaults.
404: * Return non-zero on error.
405: */
406: settty(fd)
407: {
408: struct sgttyb sgp;
409:
410: if (ioctl(fd, TIOCGETP, &sgp) < 0)
411: return (1);
412: defsgt.sg_ispeed = sgp.sg_ispeed;
413: defsgt.sg_ospeed = sgp.sg_ospeed;
414: defsgt.sg_flags &= ~(EVENP|ODDP);
415: defsgt.sg_flags |= sgp.sg_flags&(EVENP|ODDP);
416: if (ioctl(fd, TIOCSETN, &defsgt) < 0)
417: return(1);
418: if (ioctl(fd, TIOCSETC, &deftch) < 0)
419: return(1);
420: return(0);
421: }
422:
423: /* sleep for 2 seconds to make sure output has flushed, then exit */
424: slowexit(status)
425: {
426: char *s_tty;
427:
428: if ((s_tty = ttyname(2)) != NULL) {
429: if (-1 == unlocktty(strrchr(s_tty, '/') + 1)) {
430: fprintf(stderr, "Trouble unlocking tty %s.\n", s_tty);
431: }
432: }
433:
434: sleep(2);
435: exit(status);
436: }
437:
438: /*
439: * Initial attempt failed, print a new prompt.
440: * The prompt is the last line of file LOGMSG or DEFMSG.
441: */
442: printprompt()
443: {
444: #define BSIZE 128
445: static char *msg;
446: int msgfd, count;
447: long n;
448: static char msgbuf[BSIZE+1]; /* login msg buffer */
449:
450: if (msg != NULL) { /* Prompt already known. */
451: printf("\r\n%s", msg);
452: return;
453: }
454: if ((msgfd = open(LOGMSG, 0)) < 0) { /* try for login msg file */
455: printf(DEFMSG);
456: msg = DEFMSG;
457: return;
458: }
459: n = lseek(msgfd, 0L, 2);
460: if (n > BSIZE)
461: lseek(msgfd, -(long)BSIZE, 2);
462: else
463: lseek(msgfd, 0L, 0);
464: count = read(msgfd, msgbuf, BSIZE); /* read from file */
465: close(msgfd);
466: while (count > 0 && msgbuf[count-1] == '\n')
467: --count; /* skip trailing newlines */
468: msgbuf[count] = '\0';
469: if (count == 0) {
470: printf(DEFMSG);
471: msg = DEFMSG;
472: return;
473: }
474: /* Reprint only the last line of the message file. */
475: for (msg = &msgbuf[count]; msg >= msgbuf && *msg != '\n'; msg--)
476: ;
477: ++msg;
478: printf("\r\n%s", msg);
479: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.