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 * login -r hostname (for rlogind)
19 * login -h hostname (for telnetd, etc.)
21 #include <afsconfig.h>
22 #include <afs/param.h>
25 #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) && !defined(AFS_XBSD_ENV)
26 #include <sys/param.h>
28 #define quota(a,b,c,d) 0
32 #include <sys/resource.h>
34 #include <afs/afsutil.h>
49 static gid_t tty_gid(int default_gid);
50 static void getloginname(register struct utmp *up);
52 #define TTYGRPNAME "tty" /* name of group to own ttys */
53 #define TTYGID(gid) tty_gid(gid) /* gid that owns all ttys */
55 #define SCMPN(a, b) strncmp(a, b, sizeof(a))
56 #define SCPYN(a, b) strncpy(a, b, sizeof(a))
58 #define NMAX sizeof(utmp.ut_name)
59 #define HMAX sizeof(utmp.ut_host)
64 char nolog[] = "/etc/nologin";
65 char qlog[] = ".hushlogin";
66 char maildir[30] = "/usr/spool/mail/";
67 char lastlog[] = "/usr/adm/lastlog";
71 char minusnam[16] = "-";
72 char *envinit[] = { 0 }; /* now set by setenv calls */
75 * This bounds the time given to login. We initialize it here
76 * so it can be patched on machines where it's too small.
83 char *strcat(), *malloc(), *realloc();
84 static void timedout(void);
85 static void showmotd(void);
86 static void doremoteterm(char *term, struct sgttyb *tp);
87 static void setenv(char *var, char *value, int clobber);
92 extern char **environ;
96 CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK
98 struct ltchars ltc = {
99 CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT
102 struct winsize win = { 0, 0, 0, 0 };
106 char rusername[NMAX + 1], lusername[NMAX + 1];
107 char rpassword[NMAX + 1];
114 /* this sucks but it works for now.
120 #include "AFS_component_version_number.c"
123 main(int argc, char **argv)
125 register char *namep;
126 int pflag = 0, hflag = 0, t, f, c;
127 int invalid, quietlog;
130 int ldisc = 0, zero = 0, i;
135 * The following signal action for AIX is necessary so that in case of a
136 * crash (i.e. core is generated) we can include the user's data section
137 * in the core dump. Unfortunately, by default, only a partial core is
138 * generated which, in many cases, isn't too useful.
140 struct sigaction nsa;
142 sigemptyset(&nsa.sa_mask);
143 nsa.sa_handler = SIG_DFL;
144 nsa.sa_flags = SA_FULLDUMP;
145 sigaction(SIGSEGV, &nsa, NULL);
147 signal(SIGALRM, timedout);
149 signal(SIGQUIT, SIG_IGN);
150 signal(SIGINT, SIG_IGN);
151 setpriority(PRIO_PROCESS, 0, 0);
152 quota(Q_SETUID, 0, 0, 0);
154 /* create a dummy user */
155 memset(&nouser, 0, sizeof(nouser));
157 nouser.pw_passwd = "*";
158 nouser.pw_dir = nouser.pw_shell = "";
159 nouser.pw_uid = nouser.pw_gid = -1;
162 * -p is used by getty to tell login not to destroy the environment
163 * -r is used by rlogind to cause the autologin protocol;
164 * -h is used by other servers to pass the name of the
165 * remote host to login so that it may be placed in utmp and wtmp
168 if (strcmp(argv[1], "-r") == 0) {
169 if (rflag || hflag) {
170 printf("Only one of -r and -h allowed\n");
174 usererr = doremotelogin(argv[2]);
175 SCPYN(utmp.ut_host, argv[2]);
180 if (strcmp(argv[1], "-h") == 0 && getuid() == 0) {
181 if (rflag || hflag) {
182 printf("Only one of -r and -h allowed\n");
186 SCPYN(utmp.ut_host, argv[2]);
191 if (strcmp(argv[1], "-p") == 0) {
199 ioctl(0, TIOCLSET, &zero);
200 ioctl(0, TIOCNXCL, 0);
201 ioctl(0, FIONBIO, &zero);
202 ioctl(0, FIOASYNC, &zero);
203 ioctl(0, TIOCGETP, &ttyb);
205 * If talking to an rlogin process,
206 * propagate the terminal type and
207 * baud rate across the network.
210 doremoteterm(term, &ttyb);
211 ttyb.sg_erase = CERASE;
212 ttyb.sg_kill = CKILL;
213 ioctl(0, TIOCSLTC, <c);
214 ioctl(0, TIOCSETC, &tc);
215 ioctl(0, TIOCSETP, &ttyb);
216 for (t = getdtablesize(); t > 2; t--)
219 if (ttyn == (char *)0 || *ttyn == '\0')
221 tty = strrchr(ttyn, '/');
226 openlog("login", LOG_ODELAY, LOG_AUTH);
231 ioctl(0, TIOCSETD, &ldisc);
232 SCPYN(utmp.ut_name, "");
234 * Name specified, take it.
237 SCPYN(utmp.ut_name, argv[1]);
241 * If remote login take given name,
242 * otherwise prompt user for something.
244 if (rflag && !invalid)
245 SCPYN(utmp.ut_name, lusername);
249 if (!strcmp(pwd->pw_shell, "/bin/csh")) {
251 ioctl(0, TIOCSETD, &ldisc);
254 * If no remote login authentication and
255 * a password exists for this user, prompt
256 * for one and verify it.
258 if (usererr == -1 && *pwd->pw_passwd != '\0') {
260 char password[BUFSIZ];
262 if (ka_UserReadPassword
263 ("Password:", password, sizeof(password), &reason)) {
264 printf("Unable to login because %s,\n", reason);
267 if (ka_UserAuthenticate
268 (pwd->pw_name, /*inst */ 0, /*realm */ 0, password,
269 /*sepag */ 1, &reason)) {
270 printf("Unable to authenticate to AFS because %s.\n", reason);
271 printf(" proceeding with local authentication... \n");
272 /* try local login */
273 namep = crypt(password, pwd->pw_passwd);
274 if (strcmp(namep, pwd->pw_passwd))
279 setpriority(PRIO_PROCESS, 0, -4);
280 pp = getpass("Password:");
281 namep = crypt(pp, pwd->pw_passwd);
282 setpriority(PRIO_PROCESS, 0, 0);
283 if (strcmp(namep, pwd->pw_passwd))
288 * If user not super-user, check for logins disabled.
290 if (pwd->pw_uid != 0 && (nlfd = fopen(nolog, "r")) != 0) {
291 while ((c = getc(nlfd)) != EOF)
298 * If valid so far and root is logging in,
299 * see if root logins on this terminal are permitted.
301 if (!invalid && pwd->pw_uid == 0 && !rootterm(tty)) {
303 syslog(LOG_CRIT, "ROOT LOGIN REFUSED ON %s FROM %.*s", tty,
306 syslog(LOG_CRIT, "ROOT LOGIN REFUSED ON %s", tty);
310 printf("Login incorrect\n");
314 "REPEATED LOGIN FAILURES ON %s FROM %.*s, %.*s",
315 tty, HMAX, utmp.ut_host, NMAX, utmp.ut_name);
317 syslog(LOG_CRIT, "REPEATED LOGIN FAILURES ON %s, %.*s",
318 tty, NMAX, utmp.ut_name);
319 ioctl(0, TIOCHPCL, NULL);
320 close(0), close(1), close(2);
325 if (*pwd->pw_shell == '\0')
326 pwd->pw_shell = "/bin/sh";
327 if (chdir(pwd->pw_dir) < 0 && !invalid) {
328 if (chdir("/") < 0) {
329 printf("No directory!\n");
332 printf("No directory! %s\n", "Logging in with home=/");
337 * Remote login invalid must have been because
338 * of a restriction of some sort, no extra chances.
340 if (!usererr && invalid)
343 /* committed to login turn off timeout */
346 if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) {
348 printf("%s.\n%s.\n", "Too many users logged on already",
350 else if (errno == EPROCLIM)
351 printf("You have too many processes running.\n");
353 perror("quota (Q_SETUID)");
359 if (t > 0 && (f = open("/etc/utmp", O_WRONLY)) >= 0) {
360 lseek(f, (afs_int32) (t * sizeof(utmp)), 0);
361 SCPYN(utmp.ut_line, tty);
362 write(f, (char *)&utmp, sizeof(utmp));
365 if ((f = open("/usr/adm/wtmp", O_WRONLY | O_APPEND)) >= 0) {
366 write(f, (char *)&utmp, sizeof(utmp));
369 quietlog = access(qlog, F_OK) == 0;
370 if ((f = open(lastlog, O_RDWR)) >= 0) {
373 lseek(f, (afs_int32) pwd->pw_uid * sizeof(struct lastlog), 0);
374 if (read(f, (char *)&ll, sizeof ll) == sizeof ll && ll.ll_time != 0
376 printf("Last login: %.*s ", 24 - 5, (char *)ctime(&ll.ll_time));
377 if (*ll.ll_host != '\0')
378 printf("from %.*s\n", sizeof(ll.ll_host), ll.ll_host);
380 printf("on %.*s\n", sizeof(ll.ll_line), ll.ll_line);
382 lseek(f, (afs_int32) pwd->pw_uid * sizeof(struct lastlog), 0);
384 SCPYN(ll.ll_line, tty);
385 SCPYN(ll.ll_host, utmp.ut_host);
386 write(f, (char *)&ll, sizeof ll);
389 chown(ttyn, pwd->pw_uid, TTYGID(pwd->pw_gid));
390 if (!hflag && !rflag) /* XXX */
391 ioctl(0, TIOCSWINSZ, &win);
394 strncpy(name, utmp.ut_name, NMAX);
396 initgroups(name, pwd->pw_gid);
397 quota(Q_DOWARN, pwd->pw_uid, (dev_t) - 1, 0);
399 /* destroy environment unless user has asked to preserve it */
403 /* set up environment, this time without destruction */
404 /* copy the environment before setenving */
406 while (environ[i] != NULL)
408 envnew = (char **)malloc(sizeof(char *) * (i + 1));
410 envnew[i] = environ[i];
413 setenv("HOME=", pwd->pw_dir, 1);
414 setenv("SHELL=", pwd->pw_shell, 1);
416 strncpy(term, stypeof(tty), sizeof(term));
417 setenv("TERM=", term, 0);
418 setenv("USER=", pwd->pw_name, 1);
419 setenv("PATH=", ":/usr/ucb:/bin:/usr/bin", 0);
421 if ((namep = strrchr(pwd->pw_shell, '/')) == NULL)
422 namep = pwd->pw_shell;
425 strcat(minusnam, namep);
426 if (tty[sizeof("tty") - 1] == 'd')
427 syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
428 if (pwd->pw_uid == 0)
430 syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %.*s", tty, HMAX,
433 syslog(LOG_NOTICE, "ROOT LOGIN %s", tty);
438 strcat(maildir, pwd->pw_name);
439 if (stat(maildir, &st) == 0 && st.st_size != 0)
440 printf("You have %smail.\n",
441 (st.st_mtime > st.st_atime) ? "new " : "");
443 signal(SIGALRM, SIG_DFL);
444 signal(SIGQUIT, SIG_DFL);
445 signal(SIGINT, SIG_DFL);
446 signal(SIGTSTP, SIG_IGN);
447 execlp(pwd->pw_shell, minusnam, 0);
448 perror(pwd->pw_shell);
449 printf("No shell\n");
454 getloginname(register struct utmp *up)
456 register char *namep;
459 while (up->ut_name[0] == '\0') {
462 while ((c = getchar()) != '\n') {
467 if (namep < up->ut_name + NMAX)
471 strncpy(lusername, up->ut_name, NMAX);
473 if ((pwd = getpwnam(lusername)) == NULL)
481 printf("Login timed out after %d seconds\n", timeout);
490 signal(SIGINT, SIG_IGN);
497 register struct ttyent *t;
499 if ((t = getttynam(tty)) != NULL) {
500 if (t->ty_status & TTY_SECURE)
512 signal(SIGINT, catch);
513 if ((mf = fopen("/etc/motd", "r")) != NULL) {
514 while ((c = getc(mf)) != EOF && stopmotd == 0)
518 signal(SIGINT, SIG_IGN);
527 register struct ttyent *t;
529 if (ttyid == NULL || (t = getttynam(ttyid)) == NULL)
535 doremotelogin(char *host)
537 getstr(rusername, sizeof(rusername), "remuser");
538 getstr(lusername, sizeof(lusername), "locuser");
539 getstr(term, sizeof(term), "Terminal type");
544 pwd = getpwnam(lusername);
549 return (ruserok(host, (pwd->pw_uid == 0), rusername, lusername));
553 getstr(char *buf, int cnt, char *err)
558 if (read(0, &c, 1) != 1)
561 printf("%s too long\r\n", err);
568 char *speeds[] = { "0", "50", "75", "110", "134", "150", "200", "300",
569 "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400"
572 #define NSPEEDS (sizeof (speeds) / sizeof (speeds[0]))
575 doremoteterm(char *term, struct sgttyb *tp)
577 register char *cp = strchr(term, '/'), **cpp;
583 cp = strchr(speed, '/');
586 for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++)
587 if (strcmp(*cpp, speed) == 0) {
588 tp->sg_ispeed = tp->sg_ospeed = cpp - speeds;
592 tp->sg_flags = ECHO | CRMOD | ANYP | XTABS;
596 * Set the value of var to be arg in the Unix 4.2 BSD environment env.
597 * Var should end with '='.
598 * (bindings are of the form "var=value")
599 * This procedure assumes the memory for the first level of environ
600 * was allocated using malloc.
603 setenv(char *var, char *value, int clobber)
605 extern char **environ;
607 int varlen = strlen(var);
608 int vallen = strlen(value);
610 for (index = 0; environ[index] != NULL; index++) {
611 if (strncmp(environ[index], var, varlen) == 0) {
615 environ[index] = malloc(varlen + vallen + 1);
616 strcpy(environ[index], var);
617 strcat(environ[index], value);
621 environ = (char **)realloc(environ, sizeof(char *) * (index + 2));
622 if (environ == NULL) {
623 fprintf(stderr, "login: malloc out of memory\n");
626 environ[index] = malloc(varlen + vallen + 1);
627 strcpy(environ[index], var);
628 strcat(environ[index], value);
629 environ[++index] = NULL;
633 tty_gid(int default_gid)
635 struct group *getgrnam(), *gr;
636 gid_t gid = default_gid;
638 gr = getgrnam(TTYGRPNAME);
648 #include "AFS_component_version_number.c"
653 #endif /*!defined(AFS_SUN_ENV) && !defined(AFS_AIX_ENV) && !defined(AFS_HPUX_ENV) */