|
|
1.1 root 1: /*
2: * Copyright (c) 1980 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: char copyright[] =
9: "@(#) Copyright (c) 1980 Regents of the University of California.\n\
10: All rights reserved.\n";
11: #endif not lint
12:
13: #ifndef lint
14: static char sccsid[] = "@(#)login.c 5.15 (Berkeley) 4/12/86";
15: #endif not lint
16:
17: /*
18: * login [ name ]
19: * login -r hostname (for rlogind)
20: * login -h hostname (for telnetd, etc.)
21: */
22:
23: #include <sys/param.h>
24: #include <sys/quota.h>
25: #include <sys/stat.h>
26: #include <sys/time.h>
27: #include <sys/resource.h>
28: #include <sys/file.h>
29:
30: #include <sgtty.h>
31: #include <utmp.h>
32: #include <signal.h>
33: #include <pwd.h>
34: #include <stdio.h>
35: #include <lastlog.h>
36: #include <errno.h>
37: #include <ttyent.h>
38: #include <syslog.h>
39: #include <grp.h>
40:
41: #define TTYGRPNAME "tty" /* name of group to own ttys */
42: #define TTYGID(gid) tty_gid(gid) /* gid that owns all ttys */
43:
44: #define SCMPN(a, b) strncmp(a, b, sizeof(a))
45: #define SCPYN(a, b) strncpy(a, b, sizeof(a))
46:
47: #define NMAX sizeof(utmp.ut_name)
48: #define HMAX sizeof(utmp.ut_host)
49:
50: #define FALSE 0
51: #define TRUE -1
52:
53: char nolog[] = "/etc/nologin";
54: char qlog[] = ".hushlogin";
55: char maildir[30] = "/usr/spool/mail/";
56: char lastlog[] = "/usr/adm/lastlog";
57: struct passwd nouser = {"", "nope", -1, -1, -1, "", "", "", "" };
58: struct sgttyb ttyb;
59: struct utmp utmp;
60: char minusnam[16] = "-";
61: char *envinit[] = { 0 }; /* now set by setenv calls */
62: /*
63: * This bounds the time given to login. We initialize it here
64: * so it can be patched on machines where it's too small.
65: */
66: int timeout = 60;
67:
68: char term[64];
69:
70: struct passwd *pwd;
71: char *strcat(), *rindex(), *index(), *malloc(), *realloc();
72: int timedout();
73: char *ttyname();
74: char *crypt();
75: char *getpass();
76: char *stypeof();
77: extern char **environ;
78: extern int errno;
79:
80: struct tchars tc = {
81: CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK
82: };
83: struct ltchars ltc = {
84: CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT
85: };
86:
87: struct winsize win = { 0, 0, 0, 0 };
88:
89: int rflag;
90: int usererr = -1;
91: char rusername[NMAX+1], lusername[NMAX+1];
92: char rpassword[NMAX+1];
93: char name[NMAX+1];
94: char *rhost;
95:
96: main(argc, argv)
97: char *argv[];
98: {
99: register char *namep;
100: int pflag = 0, hflag = 0, t, f, c;
101: int invalid, quietlog;
102: FILE *nlfd;
103: char *ttyn, *tty;
104: int ldisc = 0, zero = 0, i;
105: char **envnew;
106:
107: signal(SIGALRM, timedout);
108: alarm(timeout);
109: signal(SIGQUIT, SIG_IGN);
110: signal(SIGINT, SIG_IGN);
111: setpriority(PRIO_PROCESS, 0, 0);
112: quota(Q_SETUID, 0, 0, 0);
113: /*
114: * -p is used by getty to tell login not to destroy the environment
115: * -r is used by rlogind to cause the autologin protocol;
116: * -h is used by other servers to pass the name of the
117: * remote host to login so that it may be placed in utmp and wtmp
118: */
119: while (argc > 1) {
120: if (strcmp(argv[1], "-r") == 0) {
121: if (rflag || hflag) {
122: printf("Only one of -r and -h allowed\n");
123: exit(1);
124: }
125: rflag = 1;
126: usererr = doremotelogin(argv[2]);
127: SCPYN(utmp.ut_host, argv[2]);
128: argc -= 2;
129: argv += 2;
130: continue;
131: }
132: if (strcmp(argv[1], "-h") == 0 && getuid() == 0) {
133: if (rflag || hflag) {
134: printf("Only one of -r and -h allowed\n");
135: exit(1);
136: }
137: hflag = 1;
138: SCPYN(utmp.ut_host, argv[2]);
139: argc -= 2;
140: argv += 2;
141: continue;
142: }
143: if (strcmp(argv[1], "-p") == 0) {
144: argc--;
145: argv++;
146: pflag = 1;
147: continue;
148: }
149: break;
150: }
151: ioctl(0, TIOCLSET, &zero);
152: ioctl(0, TIOCNXCL, 0);
153: ioctl(0, FIONBIO, &zero);
154: ioctl(0, FIOASYNC, &zero);
155: ioctl(0, TIOCGETP, &ttyb);
156: /*
157: * If talking to an rlogin process,
158: * propagate the terminal type and
159: * baud rate across the network.
160: */
161: if (rflag)
162: doremoteterm(term, &ttyb);
163: ttyb.sg_erase = CERASE;
164: ttyb.sg_kill = CKILL;
165: ioctl(0, TIOCSLTC, <c);
166: ioctl(0, TIOCSETC, &tc);
167: ioctl(0, TIOCSETP, &ttyb);
168: for (t = getdtablesize(); t > 2; t--)
169: close(t);
170: ttyn = ttyname(0);
171: if (ttyn == (char *)0 || *ttyn == '\0')
172: ttyn = "/dev/tty??";
173: tty = rindex(ttyn, '/');
174: if (tty == NULL)
175: tty = ttyn;
176: else
177: tty++;
178: openlog("login", LOG_ODELAY, LOG_AUTH);
179: t = 0;
180: invalid = FALSE;
181: do {
182: ldisc = 0;
183: ioctl(0, TIOCSETD, &ldisc);
184: SCPYN(utmp.ut_name, "");
185: /*
186: * Name specified, take it.
187: */
188: if (argc > 1) {
189: SCPYN(utmp.ut_name, argv[1]);
190: argc = 0;
191: }
192: /*
193: * If remote login take given name,
194: * otherwise prompt user for something.
195: */
196: if (rflag && !invalid)
197: SCPYN(utmp.ut_name, lusername);
198: else
199: getloginname(&utmp);
200: invalid = FALSE;
201: if (!strcmp(pwd->pw_shell, "/bin/csh")) {
202: ldisc = NTTYDISC;
203: ioctl(0, TIOCSETD, &ldisc);
204: }
205: /*
206: * If no remote login authentication and
207: * a password exists for this user, prompt
208: * for one and verify it.
209: */
210: if (usererr == -1 && *pwd->pw_passwd != '\0') {
211: char *pp;
212:
213: setpriority(PRIO_PROCESS, 0, -4);
214: pp = getpass("Password:");
215: namep = crypt(pp, pwd->pw_passwd);
216: setpriority(PRIO_PROCESS, 0, 0);
217: if (strcmp(namep, pwd->pw_passwd))
218: invalid = TRUE;
219: }
220: /*
221: * If user not super-user, check for logins disabled.
222: */
223: if (pwd->pw_uid != 0 && (nlfd = fopen(nolog, "r")) > 0) {
224: while ((c = getc(nlfd)) != EOF)
225: putchar(c);
226: fflush(stdout);
227: sleep(5);
228: exit(0);
229: }
230: /*
231: * If valid so far and root is logging in,
232: * see if root logins on this terminal are permitted.
233: */
234: if (!invalid && pwd->pw_uid == 0 && !rootterm(tty)) {
235: if (utmp.ut_host[0])
236: syslog(LOG_CRIT,
237: "ROOT LOGIN REFUSED ON %s FROM %.*s",
238: tty, HMAX, utmp.ut_host);
239: else
240: syslog(LOG_CRIT,
241: "ROOT LOGIN REFUSED ON %s", tty);
242: invalid = TRUE;
243: }
244: if (invalid) {
245: printf("Login incorrect\n");
246: if (++t >= 5) {
247: if (utmp.ut_host[0])
248: syslog(LOG_CRIT,
249: "REPEATED LOGIN FAILURES ON %s FROM %.*s, %.*s",
250: tty, HMAX, utmp.ut_host,
251: NMAX, utmp.ut_name);
252: else
253: syslog(LOG_CRIT,
254: "REPEATED LOGIN FAILURES ON %s, %.*s",
255: tty, NMAX, utmp.ut_name);
256: ioctl(0, TIOCHPCL, (struct sgttyb *) 0);
257: close(0), close(1), close(2);
258: sleep(10);
259: exit(1);
260: }
261: }
262: if (*pwd->pw_shell == '\0')
263: pwd->pw_shell = "/bin/sh";
264: if (chdir(pwd->pw_dir) < 0 && !invalid ) {
265: if (chdir("/") < 0) {
266: printf("No directory!\n");
267: invalid = TRUE;
268: } else {
269: printf("No directory! %s\n",
270: "Logging in with home=/");
271: pwd->pw_dir = "/";
272: }
273: }
274: /*
275: * Remote login invalid must have been because
276: * of a restriction of some sort, no extra chances.
277: */
278: if (!usererr && invalid)
279: exit(1);
280: } while (invalid);
281: /* committed to login turn off timeout */
282: alarm(0);
283:
284: if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) {
285: if (errno == EUSERS)
286: printf("%s.\n%s.\n",
287: "Too many users logged on already",
288: "Try again later");
289: else if (errno == EPROCLIM)
290: printf("You have too many processes running.\n");
291: else
292: perror("quota (Q_SETUID)");
293: sleep(5);
294: exit(0);
295: }
296: time(&utmp.ut_time);
297: t = ttyslot();
298: if (t > 0 && (f = open("/etc/utmp", O_WRONLY)) >= 0) {
299: lseek(f, (long)(t*sizeof(utmp)), 0);
300: SCPYN(utmp.ut_line, tty);
301: write(f, (char *)&utmp, sizeof(utmp));
302: close(f);
303: }
304: if ((f = open("/usr/adm/wtmp", O_WRONLY|O_APPEND)) >= 0) {
305: write(f, (char *)&utmp, sizeof(utmp));
306: close(f);
307: }
308: quietlog = access(qlog, F_OK) == 0;
309: if ((f = open(lastlog, O_RDWR)) >= 0) {
310: struct lastlog ll;
311:
312: lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0);
313: if (read(f, (char *) &ll, sizeof ll) == sizeof ll &&
314: ll.ll_time != 0 && !quietlog) {
315: printf("Last login: %.*s ",
316: 24-5, (char *)ctime(&ll.ll_time));
317: if (*ll.ll_host != '\0')
318: printf("from %.*s\n",
319: sizeof (ll.ll_host), ll.ll_host);
320: else
321: printf("on %.*s\n",
322: sizeof (ll.ll_line), ll.ll_line);
323: }
324: lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0);
325: time(&ll.ll_time);
326: SCPYN(ll.ll_line, tty);
327: SCPYN(ll.ll_host, utmp.ut_host);
328: write(f, (char *) &ll, sizeof ll);
329: close(f);
330: }
331: chown(ttyn, pwd->pw_uid, TTYGID(pwd->pw_gid));
332: if (!hflag && !rflag) /* XXX */
333: ioctl(0, TIOCSWINSZ, &win);
334: chmod(ttyn, 0620);
335: setgid(pwd->pw_gid);
336: strncpy(name, utmp.ut_name, NMAX);
337: name[NMAX] = '\0';
338: initgroups(name, pwd->pw_gid);
339: quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0);
340: setuid(pwd->pw_uid);
341: /* destroy environment unless user has asked to preserve it */
342: if (!pflag)
343: environ = envinit;
344:
345: /* set up environment, this time without destruction */
346: /* copy the environment before setenving */
347: i = 0;
348: while (environ[i] != NULL)
349: i++;
350: envnew = (char **) malloc(sizeof (char *) * (i + 1));
351: for (; i >= 0; i--)
352: envnew[i] = environ[i];
353: environ = envnew;
354:
355: setenv("HOME=", pwd->pw_dir, 1);
356: setenv("SHELL=", pwd->pw_shell, 1);
357: if (term[0] == '\0')
358: strncpy(term, stypeof(tty), sizeof(term));
359: setenv("TERM=", term, 0);
360: setenv("USER=", pwd->pw_name, 1);
361: setenv("PATH=", ":/usr/ucb:/bin:/usr/bin", 0);
362:
363: if ((namep = rindex(pwd->pw_shell, '/')) == NULL)
364: namep = pwd->pw_shell;
365: else
366: namep++;
367: strcat(minusnam, namep);
368: if (tty[sizeof("tty")-1] == 'd')
369: syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
370: if (pwd->pw_uid == 0)
371: if (utmp.ut_host[0])
372: syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %.*s",
373: tty, HMAX, utmp.ut_host);
374: else
375: syslog(LOG_NOTICE, "ROOT LOGIN %s", tty);
376: if (!quietlog) {
377: struct stat st;
378:
379: showmotd();
380: strcat(maildir, pwd->pw_name);
381: if (stat(maildir, &st) == 0 && st.st_size != 0)
382: printf("You have %smail.\n",
383: (st.st_mtime > st.st_atime) ? "new " : "");
384: }
385: signal(SIGALRM, SIG_DFL);
386: signal(SIGQUIT, SIG_DFL);
387: signal(SIGINT, SIG_DFL);
388: signal(SIGTSTP, SIG_IGN);
389: execlp(pwd->pw_shell, minusnam, 0);
390: perror(pwd->pw_shell);
391: printf("No shell\n");
392: exit(0);
393: }
394:
395: getloginname(up)
396: register struct utmp *up;
397: {
398: register char *namep;
399: char c;
400:
401: while (up->ut_name[0] == '\0') {
402: namep = up->ut_name;
403: printf("login: ");
404: while ((c = getchar()) != '\n') {
405: if (c == ' ')
406: c = '_';
407: if (c == EOF)
408: exit(0);
409: if (namep < up->ut_name+NMAX)
410: *namep++ = c;
411: }
412: }
413: strncpy(lusername, up->ut_name, NMAX);
414: lusername[NMAX] = 0;
415: if ((pwd = getpwnam(lusername)) == NULL)
416: pwd = &nouser;
417: }
418:
419: timedout()
420: {
421:
422: printf("Login timed out after %d seconds\n", timeout);
423: exit(0);
424: }
425:
426: int stopmotd;
427: catch()
428: {
429:
430: signal(SIGINT, SIG_IGN);
431: stopmotd++;
432: }
433:
434: rootterm(tty)
435: char *tty;
436: {
437: register struct ttyent *t;
438:
439: if ((t = getttynam(tty)) != NULL) {
440: if (t->ty_status & TTY_SECURE)
441: return (1);
442: }
443: return (0);
444: }
445:
446: showmotd()
447: {
448: FILE *mf;
449: register c;
450:
451: signal(SIGINT, catch);
452: if ((mf = fopen("/etc/motd", "r")) != NULL) {
453: while ((c = getc(mf)) != EOF && stopmotd == 0)
454: putchar(c);
455: fclose(mf);
456: }
457: signal(SIGINT, SIG_IGN);
458: }
459:
460: #undef UNKNOWN
461: #define UNKNOWN "su"
462:
463: char *
464: stypeof(ttyid)
465: char *ttyid;
466: {
467: register struct ttyent *t;
468:
469: if (ttyid == NULL || (t = getttynam(ttyid)) == NULL)
470: return (UNKNOWN);
471: return (t->ty_type);
472: }
473:
474: doremotelogin(host)
475: char *host;
476: {
477: getstr(rusername, sizeof (rusername), "remuser");
478: getstr(lusername, sizeof (lusername), "locuser");
479: getstr(term, sizeof(term), "Terminal type");
480: if (getuid()) {
481: pwd = &nouser;
482: return(-1);
483: }
484: pwd = getpwnam(lusername);
485: if (pwd == NULL) {
486: pwd = &nouser;
487: return(-1);
488: }
489: return(ruserok(host, (pwd->pw_uid == 0), rusername, lusername));
490: }
491:
492: getstr(buf, cnt, err)
493: char *buf;
494: int cnt;
495: char *err;
496: {
497: char c;
498:
499: do {
500: if (read(0, &c, 1) != 1)
501: exit(1);
502: if (--cnt < 0) {
503: printf("%s too long\r\n", err);
504: exit(1);
505: }
506: *buf++ = c;
507: } while (c != 0);
508: }
509:
510: char *speeds[] =
511: { "0", "50", "75", "110", "134", "150", "200", "300",
512: "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
513: #define NSPEEDS (sizeof (speeds) / sizeof (speeds[0]))
514:
515: doremoteterm(term, tp)
516: char *term;
517: struct sgttyb *tp;
518: {
519: register char *cp = index(term, '/'), **cpp;
520: char *speed;
521:
522: if (cp) {
523: *cp++ = '\0';
524: speed = cp;
525: cp = index(speed, '/');
526: if (cp)
527: *cp++ = '\0';
528: for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++)
529: if (strcmp(*cpp, speed) == 0) {
530: tp->sg_ispeed = tp->sg_ospeed = cpp-speeds;
531: break;
532: }
533: }
534: tp->sg_flags = ECHO|CRMOD|ANYP|XTABS;
535: }
536:
537: /*
538: * Set the value of var to be arg in the Unix 4.2 BSD environment env.
539: * Var should end with '='.
540: * (bindings are of the form "var=value")
541: * This procedure assumes the memory for the first level of environ
542: * was allocated using malloc.
543: */
544: setenv(var, value, clobber)
545: char *var, *value;
546: {
547: extern char **environ;
548: int index = 0;
549: int varlen = strlen(var);
550: int vallen = strlen(value);
551:
552: for (index = 0; environ[index] != NULL; index++) {
553: if (strncmp(environ[index], var, varlen) == 0) {
554: /* found it */
555: if (!clobber)
556: return;
557: environ[index] = malloc(varlen + vallen + 1);
558: strcpy(environ[index], var);
559: strcat(environ[index], value);
560: return;
561: }
562: }
563: environ = (char **) realloc(environ, sizeof (char *) * (index + 2));
564: if (environ == NULL) {
565: fprintf(stderr, "login: malloc out of memory\n");
566: exit(1);
567: }
568: environ[index] = malloc(varlen + vallen + 1);
569: strcpy(environ[index], var);
570: strcat(environ[index], value);
571: environ[++index] = NULL;
572: }
573:
574: tty_gid(default_gid)
575: int default_gid;
576: {
577: struct group *getgrnam(), *gr;
578: int gid = default_gid;
579:
580: gr = getgrnam(TTYGRPNAME);
581: if (gr != (struct group *) 0)
582: gid = gr->gr_gid;
583:
584: endgrent();
585:
586: return (gid);
587: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.