2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
11 * Copyright (c) 1980 Regents of the University of California.
12 * All rights reserved. The Berkeley software License Agreement
13 * specifies the terms and conditions for redistribution.
18 "@(#) Copyright (c) 1980 Regents of the University of California.\n\
19 All rights reserved.\n";
23 static char sccsid[] = "@(#)login.c 5.15 (Berkeley) 4/12/86";
28 * login -r hostname (for rlogind)
29 * login -h hostname (for telnetd, etc.)
31 #include <afs/param.h>
32 #if !defined(AFS_SUN_ENV) && !defined(AFS_AIX_ENV) && !defined(AFS_HPUX_ENV) && !defined(AFS_SGI_ENV) && !defined(AFS_SUN5_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV)
33 #include <sys/param.h>
35 #define quota(a,b,c,d) 0
39 #include <sys/resource.h>
41 #include <afs/afsutil.h>
56 static gid_t tty_gid(int default_gid);
57 static void getloginname(register struct utmp *up);
59 #define TTYGRPNAME "tty" /* name of group to own ttys */
60 #define TTYGID(gid) tty_gid(gid) /* gid that owns all ttys */
62 #define SCMPN(a, b) strncmp(a, b, sizeof(a))
63 #define SCPYN(a, b) strncpy(a, b, sizeof(a))
65 #define NMAX sizeof(utmp.ut_name)
66 #define HMAX sizeof(utmp.ut_host)
71 char nolog[] = "/etc/nologin";
72 char qlog[] = ".hushlogin";
73 char maildir[30] = "/usr/spool/mail/";
74 char lastlog[] = "/usr/adm/lastlog";
78 char minusnam[16] = "-";
79 char *envinit[] = { 0 }; /* now set by setenv calls */
81 * This bounds the time given to login. We initialize it here
82 * so it can be patched on machines where it's too small.
89 char *strcat(), *rindex(), *index(), *malloc(), *realloc();
90 static void timedout(void);
91 static void showmotd(void);
92 static void doremoteterm(char *term, struct sgttyb *tp);
93 static void setenv(char *var, char *value, int clobber);
98 extern char **environ;
102 CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK
104 struct ltchars ltc = {
105 CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT
108 struct winsize win = { 0, 0, 0, 0 };
112 char rusername[NMAX+1], lusername[NMAX+1];
113 char rpassword[NMAX+1];
119 /* this sucks but it works for now.
125 #include "AFS_component_version_number.c"
131 register char *namep;
132 int pflag = 0, hflag = 0, t, f, c;
133 int invalid, quietlog;
136 int ldisc = 0, zero = 0, i;
141 * The following signal action for AIX is necessary so that in case of a
142 * crash (i.e. core is generated) we can include the user's data section
143 * in the core dump. Unfortunately, by default, only a partial core is
144 * generated which, in many cases, isn't too useful.
146 struct sigaction nsa;
148 sigemptyset(&nsa.sa_mask);
149 nsa.sa_handler = SIG_DFL;
150 nsa.sa_flags = SA_FULLDUMP;
151 sigaction(SIGSEGV, &nsa, NULL);
153 signal(SIGALRM, timedout);
155 signal(SIGQUIT, SIG_IGN);
156 signal(SIGINT, SIG_IGN);
157 setpriority(PRIO_PROCESS, 0, 0);
158 quota(Q_SETUID, 0, 0, 0);
160 /* create a dummy user */
161 bzero (&nouser, sizeof(nouser));
163 nouser.pw_passwd = "*";
164 nouser.pw_dir = nouser.pw_shell = "";
165 nouser.pw_uid = nouser.pw_gid = -1;
168 * -p is used by getty to tell login not to destroy the environment
169 * -r is used by rlogind to cause the autologin protocol;
170 * -h is used by other servers to pass the name of the
171 * remote host to login so that it may be placed in utmp and wtmp
174 if (strcmp(argv[1], "-r") == 0) {
175 if (rflag || hflag) {
176 printf("Only one of -r and -h allowed\n");
180 usererr = doremotelogin(argv[2]);
181 SCPYN(utmp.ut_host, argv[2]);
186 if (strcmp(argv[1], "-h") == 0 && getuid() == 0) {
187 if (rflag || hflag) {
188 printf("Only one of -r and -h allowed\n");
192 SCPYN(utmp.ut_host, argv[2]);
197 if (strcmp(argv[1], "-p") == 0) {
205 ioctl(0, TIOCLSET, &zero);
206 ioctl(0, TIOCNXCL, 0);
207 ioctl(0, FIONBIO, &zero);
208 ioctl(0, FIOASYNC, &zero);
209 ioctl(0, TIOCGETP, &ttyb);
211 * If talking to an rlogin process,
212 * propagate the terminal type and
213 * baud rate across the network.
216 doremoteterm(term, &ttyb);
217 ttyb.sg_erase = CERASE;
218 ttyb.sg_kill = CKILL;
219 ioctl(0, TIOCSLTC, <c);
220 ioctl(0, TIOCSETC, &tc);
221 ioctl(0, TIOCSETP, &ttyb);
222 for (t = getdtablesize(); t > 2; t--)
225 if (ttyn == (char *)0 || *ttyn == '\0')
227 tty = rindex(ttyn, '/');
232 openlog("login", LOG_ODELAY, LOG_AUTH);
237 ioctl(0, TIOCSETD, &ldisc);
238 SCPYN(utmp.ut_name, "");
240 * Name specified, take it.
243 SCPYN(utmp.ut_name, argv[1]);
247 * If remote login take given name,
248 * otherwise prompt user for something.
250 if (rflag && !invalid)
251 SCPYN(utmp.ut_name, lusername);
255 if (!strcmp(pwd->pw_shell, "/bin/csh")) {
257 ioctl(0, TIOCSETD, &ldisc);
260 * If no remote login authentication and
261 * a password exists for this user, prompt
262 * for one and verify it.
264 if (usererr == -1 && *pwd->pw_passwd != '\0') {
266 char password[BUFSIZ];
268 if (ka_UserReadPassword
269 ("Password:", password, sizeof(password), &reason)) {
270 printf("Unable to login because %s,\n", reason);
273 else if (ka_UserAuthenticate
274 (pwd->pw_name, /*inst*/0, /*realm*/0, password,
275 /*sepag*/1, &reason)) {
276 printf("Unable to authenticate to AFS because %s.\n",
278 printf(" proceeding with local authentication... \n");
279 /* try local login */
280 namep = crypt(password, pwd->pw_passwd);
281 if (strcmp(namep, pwd->pw_passwd)) invalid = TRUE;
285 setpriority(PRIO_PROCESS, 0, -4);
286 pp = getpass("Password:");
287 namep = crypt(pp, pwd->pw_passwd);
288 setpriority(PRIO_PROCESS, 0, 0);
289 if (strcmp(namep, pwd->pw_passwd)) invalid = TRUE;
293 * If user not super-user, check for logins disabled.
295 if (pwd->pw_uid != 0 && (nlfd = fopen(nolog, "r")) != 0) {
296 while ((c = getc(nlfd)) != EOF)
303 * If valid so far and root is logging in,
304 * see if root logins on this terminal are permitted.
306 if (!invalid && pwd->pw_uid == 0 && !rootterm(tty)) {
309 "ROOT LOGIN REFUSED ON %s FROM %.*s",
310 tty, HMAX, utmp.ut_host);
313 "ROOT LOGIN REFUSED ON %s", tty);
317 printf("Login incorrect\n");
321 "REPEATED LOGIN FAILURES ON %s FROM %.*s, %.*s",
322 tty, HMAX, utmp.ut_host,
326 "REPEATED LOGIN FAILURES ON %s, %.*s",
327 tty, NMAX, utmp.ut_name);
328 ioctl(0, TIOCHPCL, (struct sgttyb *) 0);
329 close(0), close(1), close(2);
334 if (*pwd->pw_shell == '\0')
335 pwd->pw_shell = "/bin/sh";
336 if (chdir(pwd->pw_dir) < 0 && !invalid ) {
337 if (chdir("/") < 0) {
338 printf("No directory!\n");
341 printf("No directory! %s\n",
342 "Logging in with home=/");
347 * Remote login invalid must have been because
348 * of a restriction of some sort, no extra chances.
350 if (!usererr && invalid)
353 /* committed to login turn off timeout */
356 if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) {
359 "Too many users logged on already",
361 else if (errno == EPROCLIM)
362 printf("You have too many processes running.\n");
364 perror("quota (Q_SETUID)");
370 if (t > 0 && (f = open("/etc/utmp", O_WRONLY)) >= 0) {
371 lseek(f, (afs_int32)(t*sizeof(utmp)), 0);
372 SCPYN(utmp.ut_line, tty);
373 write(f, (char *)&utmp, sizeof(utmp));
376 if ((f = open("/usr/adm/wtmp", O_WRONLY|O_APPEND)) >= 0) {
377 write(f, (char *)&utmp, sizeof(utmp));
380 quietlog = access(qlog, F_OK) == 0;
381 if ((f = open(lastlog, O_RDWR)) >= 0) {
384 lseek(f, (afs_int32)pwd->pw_uid * sizeof (struct lastlog), 0);
385 if (read(f, (char *) &ll, sizeof ll) == sizeof ll &&
386 ll.ll_time != 0 && !quietlog) {
387 printf("Last login: %.*s ",
388 24-5, (char *)ctime(&ll.ll_time));
389 if (*ll.ll_host != '\0')
390 printf("from %.*s\n",
391 sizeof (ll.ll_host), ll.ll_host);
394 sizeof (ll.ll_line), ll.ll_line);
396 lseek(f, (afs_int32)pwd->pw_uid * sizeof (struct lastlog), 0);
398 SCPYN(ll.ll_line, tty);
399 SCPYN(ll.ll_host, utmp.ut_host);
400 write(f, (char *) &ll, sizeof ll);
403 chown(ttyn, pwd->pw_uid, TTYGID(pwd->pw_gid));
404 if (!hflag && !rflag) /* XXX */
405 ioctl(0, TIOCSWINSZ, &win);
408 strncpy(name, utmp.ut_name, NMAX);
410 initgroups(name, pwd->pw_gid);
411 quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0);
413 /* destroy environment unless user has asked to preserve it */
417 /* set up environment, this time without destruction */
418 /* copy the environment before setenving */
420 while (environ[i] != NULL)
422 envnew = (char **) malloc(sizeof (char *) * (i + 1));
424 envnew[i] = environ[i];
427 setenv("HOME=", pwd->pw_dir, 1);
428 setenv("SHELL=", pwd->pw_shell, 1);
430 strncpy(term, stypeof(tty), sizeof(term));
431 setenv("TERM=", term, 0);
432 setenv("USER=", pwd->pw_name, 1);
433 setenv("PATH=", ":/usr/ucb:/bin:/usr/bin", 0);
435 if ((namep = rindex(pwd->pw_shell, '/')) == NULL)
436 namep = pwd->pw_shell;
439 strcat(minusnam, namep);
440 if (tty[sizeof("tty")-1] == 'd')
441 syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
442 if (pwd->pw_uid == 0)
444 syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %.*s",
445 tty, HMAX, utmp.ut_host);
447 syslog(LOG_NOTICE, "ROOT LOGIN %s", tty);
452 strcat(maildir, pwd->pw_name);
453 if (stat(maildir, &st) == 0 && st.st_size != 0)
454 printf("You have %smail.\n",
455 (st.st_mtime > st.st_atime) ? "new " : "");
457 signal(SIGALRM, SIG_DFL);
458 signal(SIGQUIT, SIG_DFL);
459 signal(SIGINT, SIG_DFL);
460 signal(SIGTSTP, SIG_IGN);
461 execlp(pwd->pw_shell, minusnam, 0);
462 perror(pwd->pw_shell);
463 printf("No shell\n");
467 static void getloginname(register struct utmp *up)
469 register char *namep;
472 while (up->ut_name[0] == '\0') {
475 while ((c = getchar()) != '\n') {
480 if (namep < up->ut_name+NMAX)
484 strncpy(lusername, up->ut_name, NMAX);
486 if ((pwd = getpwnam(lusername)) == NULL)
490 static void timedout(void)
493 printf("Login timed out after %d seconds\n", timeout);
498 static void catch(void)
501 signal(SIGINT, SIG_IGN);
505 int rootterm(char *tty)
507 register struct ttyent *t;
509 if ((t = getttynam(tty)) != NULL) {
510 if (t->ty_status & TTY_SECURE)
516 static void showmotd(void)
521 signal(SIGINT, catch);
522 if ((mf = fopen("/etc/motd", "r")) != NULL) {
523 while ((c = getc(mf)) != EOF && stopmotd == 0)
527 signal(SIGINT, SIG_IGN);
533 char *stypeof(char *ttyid)
535 register struct ttyent *t;
537 if (ttyid == NULL || (t = getttynam(ttyid)) == NULL)
542 int doremotelogin(char *host)
544 getstr(rusername, sizeof (rusername), "remuser");
545 getstr(lusername, sizeof (lusername), "locuser");
546 getstr(term, sizeof(term), "Terminal type");
551 pwd = getpwnam(lusername);
556 return(ruserok(host, (pwd->pw_uid == 0), rusername, lusername));
567 if (read(0, &c, 1) != 1)
570 printf("%s too long\r\n", err);
578 { "0", "50", "75", "110", "134", "150", "200", "300",
579 "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
580 #define NSPEEDS (sizeof (speeds) / sizeof (speeds[0]))
582 static void doremoteterm(
586 register char *cp = index(term, '/'), **cpp;
592 cp = index(speed, '/');
595 for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++)
596 if (strcmp(*cpp, speed) == 0) {
597 tp->sg_ispeed = tp->sg_ospeed = cpp-speeds;
601 tp->sg_flags = ECHO|CRMOD|ANYP|XTABS;
605 * Set the value of var to be arg in the Unix 4.2 BSD environment env.
606 * Var should end with '='.
607 * (bindings are of the form "var=value")
608 * This procedure assumes the memory for the first level of environ
609 * was allocated using malloc.
616 extern char **environ;
618 int varlen = strlen(var);
619 int vallen = strlen(value);
621 for (index = 0; environ[index] != NULL; index++) {
622 if (strncmp(environ[index], var, varlen) == 0) {
626 environ[index] = malloc(varlen + vallen + 1);
627 strcpy(environ[index], var);
628 strcat(environ[index], value);
632 environ = (char **) realloc(environ, sizeof (char *) * (index + 2));
633 if (environ == NULL) {
634 fprintf(stderr, "login: malloc out of memory\n");
637 environ[index] = malloc(varlen + vallen + 1);
638 strcpy(environ[index], var);
639 strcat(environ[index], value);
640 environ[++index] = NULL;
643 static gid_t tty_gid(int default_gid)
645 struct group *getgrnam(), *gr;
646 gid_t gid = default_gid;
648 gr = getgrnam(TTYGRPNAME);
649 if (gr != (struct group *) 0)
658 #include "AFS_component_version_number.c"
661 #endif /*!defined(AFS_SUN_ENV) && !defined(AFS_AIX_ENV) && !defined(AFS_HPUX_ENV)*/