|
|
1.1 root 1: /*-
2: * Copyright (c) 1980, 1987, 1988 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted provided
6: * that: (1) source distributions retain this entire copyright notice and
7: * comment, and (2) distributions including binaries display the following
8: * acknowledgement: ``This product includes software developed by the
9: * University of California, Berkeley and its contributors'' in the
10: * documentation or other materials provided with the distribution and in
11: * all advertising materials mentioning features or use of this software.
12: * Neither the name of the University nor the names of its contributors may
13: * be used to endorse or promote products derived from this software without
14: * specific prior written permission.
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18: */
19:
20: #ifndef lint
21: char copyright[] =
22: "@(#) Copyright (c) 1980, 1987, 1988 The Regents of the University of California.\n\
23: All rights reserved.\n";
24: #endif /* not lint */
25:
26: #ifndef lint
27: static char sccsid[] = "@(#)login.c 5.63 (Berkeley) 6/29/90";
28: #endif /* not lint */
29:
30: /*
31: * login [ name ]
32: * login -h hostname (for telnetd, etc.)
33: * login -f name (for pre-authenticated login: datakit, xterm, etc.)
34: */
35:
36: #include <sys/param.h>
37: #include <sys/stat.h>
38: #include <sys/time.h>
39: #include <sys/resource.h>
40: #include <sys/file.h>
41: #include <sgtty.h>
42:
43: #include <utmp.h>
44: #include <signal.h>
45: #include <errno.h>
46: #include <ttyent.h>
47: #include <syslog.h>
48: #include <grp.h>
49: #include <pwd.h>
50: #include <setjmp.h>
51: #include <stdio.h>
52: #include <string.h>
53: #include <tzfile.h>
54: #include "pathnames.h"
55:
56: #define TTYGRPNAME "tty" /* name of group to own ttys */
57:
58: /*
59: * This bounds the time given to login. Not a define so it can
60: * be patched on machines where it's too small.
61: */
62: int timeout = 300;
63: #ifdef KERBEROS
64: int notickets = 1;
65: #endif
66:
67: struct passwd *pwd;
68: int failures;
69: char term[64], *envinit[1], *hostname, *username, *tty;
70:
71: main(argc, argv)
72: int argc;
73: char **argv;
74: {
75: extern int optind;
76: extern char *optarg, **environ;
77: struct timeval tp;
78: struct group *gr;
79: register int ch;
80: register char *p;
81: int ask, fflag, hflag, pflag, cnt, uid;
82: int quietlog, rval;
83: char *domain, *salt, *ttyn;
84: char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10];
85: char localhost[MAXHOSTNAMELEN];
86: char *ctime(), *ttyname(), *stypeof(), *crypt(), *getpass();
87: time_t time();
88: off_t lseek();
89: void timedout();
90:
91: (void)signal(SIGALRM, timedout);
92: (void)alarm((u_int)timeout);
93: (void)signal(SIGQUIT, SIG_IGN);
94: (void)signal(SIGINT, SIG_IGN);
95: (void)setpriority(PRIO_PROCESS, 0, 0);
96:
97: openlog("login", LOG_ODELAY, LOG_AUTH);
98:
99: /*
100: * -p is used by getty to tell login not to destroy the environment
101: * -f is used to skip a second login authentication
102: * -h is used by other servers to pass the name of the remote
103: * host to login so that it may be placed in utmp and wtmp
104: */
105: domain = NULL;
106: if (gethostname(localhost, sizeof(localhost)) < 0)
107: syslog(LOG_ERR, "couldn't get local hostname: %m");
108: else
109: domain = index(localhost, '.');
110:
111: fflag = hflag = pflag = 0;
112: uid = getuid();
113: while ((ch = getopt(argc, argv, "fh:p")) != EOF)
114: switch (ch) {
115: case 'f':
116: fflag = 1;
117: break;
118: case 'h':
119: if (uid) {
120: (void)fprintf(stderr,
121: "login: -h for super-user only.\n");
122: exit(1);
123: }
124: hflag = 1;
125: if (domain && (p = index(optarg, '.')) &&
126: strcasecmp(p, domain) == 0)
127: *p = 0;
128: hostname = optarg;
129: break;
130: case 'p':
131: pflag = 1;
132: break;
133: case '?':
134: default:
135: if (!uid)
136: syslog(LOG_ERR, "invalid flag %c", ch);
137: (void)fprintf(stderr,
138: "usage: login [-fp] [username]\n");
139: exit(1);
140: }
141: argc -= optind;
142: argv += optind;
143: if (*argv) {
144: username = *argv;
145: if (strlen(username) > UT_NAMESIZE)
146: username[UT_NAMESIZE] = '\0';
147: ask = 0;
148: } else
149: ask = 1;
150:
151: for (cnt = getdtablesize(); cnt > 2; cnt--)
152: close(cnt);
153:
154: ttyn = ttyname(0);
155: if (ttyn == NULL || *ttyn == '\0') {
156: (void)sprintf(tname, "%s??", _PATH_TTY);
157: ttyn = tname;
158: }
159: if (tty = rindex(ttyn, '/'))
160: ++tty;
161: else
162: tty = ttyn;
163:
164: for (cnt = 0;; ask = 1) {
165: if (ask) {
166: fflag = 0;
167: getloginname();
168: }
169: /*
170: * Note if trying multiple user names; log failures for
171: * previous user name, but don't bother logging one failure
172: * for nonexistent name (mistyped username).
173: */
174: if (failures && strcmp(tbuf, username)) {
175: if (failures > (pwd ? 0 : 1))
176: badlogin(tbuf);
177: failures = 0;
178: }
179: (void)strcpy(tbuf, username);
180:
181: if (pwd = getpwnam(username))
182: salt = pwd->pw_passwd;
183: else
184: salt = "xx";
185:
186: /*
187: * if we have a valid account name, and it doesn't have a
188: * password, or the -f option was specified and the caller
189: * is root or the caller isn't changing their uid, don't
190: * authenticate.
191: */
192: if (pwd && (*pwd->pw_passwd == '\0' ||
193: fflag && (uid == 0 || uid == pwd->pw_uid)))
194: break;
195: fflag = 0;
196:
197: /*
198: * If trying to log in as root, but with insecure terminal,
199: * refuse the login attempt.
200: */
201: if (pwd && pwd->pw_uid == 0 && !rootterm(tty)) {
202: (void)fprintf(stderr,
203: "%s login refused on this terminal.\n",
204: pwd->pw_name);
205: if (hostname)
206: syslog(LOG_NOTICE,
207: "LOGIN %s REFUSED FROM %s ON TTY %s",
208: pwd->pw_name, hostname, tty);
209: else
210: syslog(LOG_NOTICE,
211: "LOGIN %s REFUSED ON TTY %s",
212: pwd->pw_name, tty);
213: continue;
214: }
215:
216: (void)setpriority(PRIO_PROCESS, 0, -4);
217:
218: p = getpass("Password:");
219:
220: if (pwd) {
221: #ifdef KERBEROS
222: rval = klogin(pwd, localhost, p);
223: if (rval == 1)
224: rval = strcmp(crypt(p, salt), pwd->pw_passwd);
225: #else
226: rval = strcmp(crypt(p, salt), pwd->pw_passwd);
227: #endif
228: }
229: bzero(p, strlen(p));
230:
231: (void)setpriority(PRIO_PROCESS, 0, 0);
232:
233: if (pwd && !rval)
234: break;
235:
236: (void)printf("Login incorrect\n");
237: failures++;
238: /* we allow 10 tries, but after 3 we start backing off */
239: if (++cnt > 3) {
240: if (cnt >= 10) {
241: badlogin(username);
242: sleepexit(1);
243: }
244: sleep((u_int)((cnt - 3) * 5));
245: }
246: }
247:
248: /* committed to login -- turn off timeout */
249: (void)alarm((u_int)0);
250:
251: /* paranoia... */
252: endpwent();
253:
254: /* if user not super-user, check for disabled logins */
255: if (pwd->pw_uid)
256: checknologin();
257:
258: if (chdir(pwd->pw_dir) < 0) {
259: (void)printf("No directory %s!\n", pwd->pw_dir);
260: if (chdir("/"))
261: exit(0);
262: pwd->pw_dir = "/";
263: (void)printf("Logging in with home = \"/\".\n");
264: }
265:
266: quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
267:
268: if (pwd->pw_change || pwd->pw_expire)
269: (void)gettimeofday(&tp, (struct timezone *)NULL);
270: if (pwd->pw_change)
271: if (tp.tv_sec >= pwd->pw_change) {
272: (void)printf("Sorry -- your password has expired.\n");
273: sleepexit(1);
274: }
275: else if (pwd->pw_change - tp.tv_sec <
276: 2 * DAYSPERWEEK * SECSPERDAY && !quietlog)
277: (void)printf("Warning: your password expires on %s",
278: ctime(&pwd->pw_expire));
279: if (pwd->pw_expire)
280: if (tp.tv_sec >= pwd->pw_expire) {
281: (void)printf("Sorry -- your account has expired.\n");
282: sleepexit(1);
283: }
284: else if (pwd->pw_expire - tp.tv_sec <
285: 2 * DAYSPERWEEK * SECSPERDAY && !quietlog)
286: (void)printf("Warning: your account expires on %s",
287: ctime(&pwd->pw_expire));
288:
289: /* nothing else left to fail -- really log in */
290: {
291: struct utmp utmp;
292:
293: bzero((void *)&utmp, sizeof(utmp));
294: (void)time(&utmp.ut_time);
295: strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
296: if (hostname)
297: strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
298: strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
299: login(&utmp);
300: }
301:
302: dolastlog(quietlog);
303:
304: (void)chown(ttyn, pwd->pw_uid,
305: (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
306: (void)chmod(ttyn, 0620);
307: (void)setgid(pwd->pw_gid);
308:
309: initgroups(username, pwd->pw_gid);
310:
311: if (*pwd->pw_shell == '\0')
312: pwd->pw_shell = _PATH_BSHELL;
313:
314: /* destroy environment unless user has requested preservation */
315: if (!pflag)
316: environ = envinit;
317: (void)setenv("HOME", pwd->pw_dir, 1);
318: (void)setenv("SHELL", pwd->pw_shell, 1);
319: if (term[0] == '\0')
320: strncpy(term, stypeof(tty), sizeof(term));
321: (void)setenv("TERM", term, 0);
322: (void)setenv("USER", pwd->pw_name, 1);
323: (void)setenv("PATH", _PATH_DEFPATH, 0);
324:
325: if (tty[sizeof("tty")-1] == 'd')
326: syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
327: /* if fflag is on, assume caller/authenticator has logged root login */
328: if (pwd->pw_uid == 0 && fflag == 0)
329: if (hostname)
330: syslog(LOG_NOTICE, "ROOT LOGIN ON %s FROM %s",
331: tty, hostname);
332: else
333: syslog(LOG_NOTICE, "ROOT LOGIN ON %s", tty);
334:
335: #ifdef KERBEROS
336: if (!quietlog && notickets == 1)
337: (void)printf("Warning: no Kerberos tickets issued.\n");
338: #endif
339:
340: if (!quietlog) {
341: struct stat st;
342:
343: motd();
344: (void)sprintf(tbuf, "%s/%s", _PATH_MAILDIR, pwd->pw_name);
345: if (stat(tbuf, &st) == 0 && st.st_size != 0)
346: (void)printf("You have %smail.\n",
347: (st.st_mtime > st.st_atime) ? "new " : "");
348: }
349:
350: (void)signal(SIGALRM, SIG_DFL);
351: (void)signal(SIGQUIT, SIG_DFL);
352: (void)signal(SIGINT, SIG_DFL);
353: (void)signal(SIGTSTP, SIG_IGN);
354:
355: tbuf[0] = '-';
356: strcpy(tbuf + 1, (p = rindex(pwd->pw_shell, '/')) ?
357: p + 1 : pwd->pw_shell);
358:
359: if (setlogin(pwd->pw_name) < 0)
360: syslog(LOG_ERR, "setlogin() failure: %m");
361:
362: /* discard permissions last so can't get killed and drop core */
363: (void)setuid(pwd->pw_uid);
364:
365: execlp(pwd->pw_shell, tbuf, 0);
366: (void)fprintf(stderr, "login: no shell: %s.\n", strerror(errno));
367: exit(0);
368: }
369:
370: getloginname()
371: {
372: register int ch;
373: register char *p;
374: static char nbuf[UT_NAMESIZE + 1];
375:
376: for (;;) {
377: (void)printf("login: ");
378: for (p = nbuf; (ch = getchar()) != '\n'; ) {
379: if (ch == EOF) {
380: badlogin(username);
381: exit(0);
382: }
383: if (p < nbuf + UT_NAMESIZE)
384: *p++ = ch;
385: }
386: if (p > nbuf)
387: if (nbuf[0] == '-')
388: (void)fprintf(stderr,
389: "login names may not start with '-'.\n");
390: else {
391: *p = '\0';
392: username = nbuf;
393: break;
394: }
395: }
396: }
397:
398: void
399: timedout()
400: {
401: (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout);
402: exit(0);
403: }
404:
405: rootterm(ttyn)
406: char *ttyn;
407: {
408: struct ttyent *t;
409:
410: return((t = getttynam(ttyn)) && t->ty_status&TTY_SECURE);
411: }
412:
413: jmp_buf motdinterrupt;
414:
415: motd()
416: {
417: register int fd, nchars;
418: sig_t oldint;
419: int sigint();
420: char tbuf[8192];
421:
422: if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0)
423: return;
424: oldint = signal(SIGINT, sigint);
425: if (setjmp(motdinterrupt) == 0)
426: while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
427: (void)write(fileno(stdout), tbuf, nchars);
428: (void)signal(SIGINT, oldint);
429: (void)close(fd);
430: }
431:
432: sigint()
433: {
434: longjmp(motdinterrupt, 1);
435: }
436:
437: checknologin()
438: {
439: register int fd, nchars;
440: char tbuf[8192];
441:
442: if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
443: while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
444: (void)write(fileno(stdout), tbuf, nchars);
445: sleepexit(0);
446: }
447: }
448:
449: dolastlog(quiet)
450: int quiet;
451: {
452: struct lastlog ll;
453: int fd;
454: char *ctime();
455:
456: if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
457: (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
458: if (!quiet) {
459: if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
460: ll.ll_time != 0) {
461: (void)printf("Last login: %.*s ",
462: 24-5, (char *)ctime(&ll.ll_time));
463: if (*ll.ll_host != '\0')
464: (void)printf("from %.*s\n",
465: sizeof(ll.ll_host), ll.ll_host);
466: else
467: (void)printf("on %.*s\n",
468: sizeof(ll.ll_line), ll.ll_line);
469: }
470: (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
471: }
472: bzero((void *)&ll, sizeof(ll));
473: (void)time(&ll.ll_time);
474: strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
475: if (hostname)
476: strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
477: (void)write(fd, (char *)&ll, sizeof(ll));
478: (void)close(fd);
479: }
480: }
481:
482: badlogin(name)
483: char *name;
484: {
485: if (failures == 0)
486: return;
487: if (hostname)
488: syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s, %s",
489: failures, failures > 1 ? "S" : "", hostname, name);
490: else
491: syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s, %s",
492: failures, failures > 1 ? "S" : "", tty, name);
493: }
494:
495: #undef UNKNOWN
496: #define UNKNOWN "su"
497:
498: char *
499: stypeof(ttyid)
500: char *ttyid;
501: {
502: struct ttyent *t;
503:
504: return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
505: }
506:
507: sleepexit(eval)
508: int eval;
509: {
510: sleep((u_int)5);
511: exit(eval);
512: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.