rxgen, kauth: Set but not used variables
[openafs.git] / src / kauth / klogin.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
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
8  */
9
10 /*
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.
14  */
15
16 /*
17  * login [ name ]
18  * login -r hostname (for rlogind)
19  * login -h hostname (for telnetd, etc.)
20  */
21 #include <afsconfig.h>
22 #include <afs/param.h>
23
24
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>
27
28 #define quota(a,b,c,d) 0
29
30 #include <sys/stat.h>
31 #include <sys/time.h>
32 #include <sys/resource.h>
33 #include <sys/file.h>
34 #include <afs/afsutil.h>
35 #include <sgtty.h>
36 #include <utmp.h>
37 #include <signal.h>
38 #include <pwd.h>
39 #include <stdio.h>
40 #include <lastlog.h>
41 #include <errno.h>
42 #include <ttyent.h>
43
44
45 #include <syslog.h>
46
47 #include <grp.h>
48
49 static gid_t tty_gid(int default_gid);
50 static void getloginname(struct utmp *up);
51
52 #define TTYGRPNAME      "tty"   /* name of group to own ttys */
53 #define TTYGID(gid)     tty_gid(gid)    /* gid that owns all ttys */
54
55 #define SCMPN(a, b)     strncmp(a, b, sizeof(a))
56 #define SCPYN(a, b)     strncpy(a, b, sizeof(a))
57
58 #define NMAX    sizeof(utmp.ut_name)
59 #define HMAX    sizeof(utmp.ut_host)
60
61 #define FALSE   0
62 #define TRUE    -1
63
64 char nolog[] = "/etc/nologin";
65 char qlog[] = ".hushlogin";
66 char maildir[30] = "/usr/spool/mail/";
67 char lastlog[] = "/usr/adm/lastlog";
68 struct passwd nouser;
69 struct sgttyb ttyb;
70 struct utmp utmp;
71 char minusnam[16] = "-";
72 char *envinit[] = { 0 };        /* now set by setenv calls */
73
74 /*
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.
77  */
78 int timeout = 60;
79
80 char term[64];
81
82 struct passwd *pwd;
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);
88 char *ttyname();
89 char *crypt();
90 char *getpass();
91 char *stypeof();
92 extern char **environ;
93
94
95 struct tchars tc = {
96     CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK
97 };
98 struct ltchars ltc = {
99     CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT
100 };
101
102 struct winsize win = { 0, 0, 0, 0 };
103
104 int rflag;
105 int usererr = -1;
106 char rusername[NMAX + 1], lusername[NMAX + 1];
107 char rpassword[NMAX + 1];
108 char name[NMAX + 1];
109 char *rhost;
110
111 int
112 osi_audit(void)
113 {
114     /* this sucks but it works for now.
115      */
116     return 0;
117 }
118
119
120 #include "AFS_component_version_number.c"
121
122 int
123 main(int argc, char **argv)
124 {
125     char *namep;
126     int pflag = 0, hflag = 0, t, f, c;
127     int invalid, quietlog;
128     FILE *nlfd;
129     char *ttyn, *tty;
130     int ldisc = 0, zero = 0, i;
131     char **envnew;
132
133 #ifdef  AFS_AIX32_ENV
134     /*
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.
139      */
140     struct sigaction nsa;
141
142     sigemptyset(&nsa.sa_mask);
143     nsa.sa_handler = SIG_DFL;
144     nsa.sa_flags = SA_FULLDUMP;
145     sigaction(SIGSEGV, &nsa, NULL);
146 #endif
147     signal(SIGALRM, timedout);
148     alarm(timeout);
149     signal(SIGQUIT, SIG_IGN);
150     signal(SIGINT, SIG_IGN);
151     setpriority(PRIO_PROCESS, 0, 0);
152     quota(Q_SETUID, 0, 0, 0);
153
154     /* create a dummy user */
155     memset(&nouser, 0, sizeof(nouser));
156     nouser.pw_name = "";
157     nouser.pw_passwd = "*";
158     nouser.pw_dir = nouser.pw_shell = "";
159     nouser.pw_uid = nouser.pw_gid = -1;
160
161     /*
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
166      */
167     while (argc > 1) {
168         if (strcmp(argv[1], "-r") == 0) {
169             if (rflag || hflag) {
170                 printf("Only one of -r and -h allowed\n");
171                 exit(1);
172             }
173             rflag = 1;
174             usererr = doremotelogin(argv[2]);
175             SCPYN(utmp.ut_host, argv[2]);
176             argc -= 2;
177             argv += 2;
178             continue;
179         }
180         if (strcmp(argv[1], "-h") == 0 && getuid() == 0) {
181             if (rflag || hflag) {
182                 printf("Only one of -r and -h allowed\n");
183                 exit(1);
184             }
185             hflag = 1;
186             SCPYN(utmp.ut_host, argv[2]);
187             argc -= 2;
188             argv += 2;
189             continue;
190         }
191         if (strcmp(argv[1], "-p") == 0) {
192             argc--;
193             argv++;
194             pflag = 1;
195             continue;
196         }
197         break;
198     }
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);
204     /*
205      * If talking to an rlogin process,
206      * propagate the terminal type and
207      * baud rate across the network.
208      */
209     if (rflag)
210         doremoteterm(term, &ttyb);
211     ttyb.sg_erase = CERASE;
212     ttyb.sg_kill = CKILL;
213     ioctl(0, TIOCSLTC, &ltc);
214     ioctl(0, TIOCSETC, &tc);
215     ioctl(0, TIOCSETP, &ttyb);
216     for (t = getdtablesize(); t > 2; t--)
217         close(t);
218     ttyn = ttyname(0);
219     if (ttyn == (char *)0 || *ttyn == '\0')
220         ttyn = "/dev/tty??";
221     tty = strrchr(ttyn, '/');
222     if (tty == NULL)
223         tty = ttyn;
224     else
225         tty++;
226     openlog("login", LOG_ODELAY, LOG_AUTH);
227     t = 0;
228     invalid = FALSE;
229     do {
230         ldisc = 0;
231         ioctl(0, TIOCSETD, &ldisc);
232         SCPYN(utmp.ut_name, "");
233         /*
234          * Name specified, take it.
235          */
236         if (argc > 1) {
237             SCPYN(utmp.ut_name, argv[1]);
238             argc = 0;
239         }
240         /*
241          * If remote login take given name,
242          * otherwise prompt user for something.
243          */
244         if (rflag && !invalid)
245             SCPYN(utmp.ut_name, lusername);
246         else
247             getloginname(&utmp);
248         invalid = FALSE;
249         if (!strcmp(pwd->pw_shell, "/bin/csh")) {
250             ldisc = NTTYDISC;
251             ioctl(0, TIOCSETD, &ldisc);
252         }
253         /*
254          * If no remote login authentication and
255          * a password exists for this user, prompt
256          * for one and verify it.
257          */
258         if (usererr == -1 && *pwd->pw_passwd != '\0') {
259 #ifdef KAUTH
260             char password[BUFSIZ];
261             char *reason;
262             if (ka_UserReadPassword
263                 ("Password:", password, sizeof(password), &reason)) {
264                 printf("Unable to login because %s,\n", reason);
265                 invalid = TRUE;
266             } else
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))
275                     invalid = TRUE;
276             }
277 #else
278             char *pp;
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))
284                 invalid = TRUE;
285 #endif
286         }
287         /*
288          * If user not super-user, check for logins disabled.
289          */
290         if (pwd->pw_uid != 0 && (nlfd = fopen(nolog, "r")) != 0) {
291             while ((c = getc(nlfd)) != EOF)
292                 putchar(c);
293             fflush(stdout);
294             sleep(5);
295             exit(0);
296         }
297         /*
298          * If valid so far and root is logging in,
299          * see if root logins on this terminal are permitted.
300          */
301         if (!invalid && pwd->pw_uid == 0 && !rootterm(tty)) {
302             if (utmp.ut_host[0])
303                 syslog(LOG_CRIT, "ROOT LOGIN REFUSED ON %s FROM %.*s", tty,
304                        HMAX, utmp.ut_host);
305             else
306                 syslog(LOG_CRIT, "ROOT LOGIN REFUSED ON %s", tty);
307             invalid = TRUE;
308         }
309         if (invalid) {
310             printf("Login incorrect\n");
311             if (++t >= 5) {
312                 if (utmp.ut_host[0])
313                     syslog(LOG_CRIT,
314                            "REPEATED LOGIN FAILURES ON %s FROM %.*s, %.*s",
315                            tty, HMAX, utmp.ut_host, NMAX, utmp.ut_name);
316                 else
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);
321                 sleep(10);
322                 exit(1);
323             }
324         }
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");
330                 invalid = TRUE;
331             } else {
332                 printf("No directory! %s\n", "Logging in with home=/");
333                 pwd->pw_dir = "/";
334             }
335         }
336         /*
337          * Remote login invalid must have been because
338          * of a restriction of some sort, no extra chances.
339          */
340         if (!usererr && invalid)
341             exit(1);
342     } while (invalid);
343 /* committed to login turn off timeout */
344     alarm(0);
345
346     if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) {
347         if (errno == EUSERS)
348             printf("%s.\n%s.\n", "Too many users logged on already",
349                    "Try again later");
350         else if (errno == EPROCLIM)
351             printf("You have too many processes running.\n");
352         else
353             perror("quota (Q_SETUID)");
354         sleep(5);
355         exit(0);
356     }
357     time(&utmp.ut_time);
358     t = ttyslot();
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));
363         close(f);
364     }
365     if ((f = open("/usr/adm/wtmp", O_WRONLY | O_APPEND)) >= 0) {
366         write(f, (char *)&utmp, sizeof(utmp));
367         close(f);
368     }
369     quietlog = access(qlog, F_OK) == 0;
370     if ((f = open(lastlog, O_RDWR)) >= 0) {
371         struct lastlog ll;
372
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
375             && !quietlog) {
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);
379             else
380                 printf("on %.*s\n", sizeof(ll.ll_line), ll.ll_line);
381         }
382         lseek(f, (afs_int32) pwd->pw_uid * sizeof(struct lastlog), 0);
383         time(&ll.ll_time);
384         SCPYN(ll.ll_line, tty);
385         SCPYN(ll.ll_host, utmp.ut_host);
386         write(f, (char *)&ll, sizeof ll);
387         close(f);
388     }
389     chown(ttyn, pwd->pw_uid, TTYGID(pwd->pw_gid));
390     if (!hflag && !rflag)       /* XXX */
391         ioctl(0, TIOCSWINSZ, &win);
392     chmod(ttyn, 0620);
393     setgid(pwd->pw_gid);
394     strncpy(name, utmp.ut_name, NMAX);
395     name[NMAX] = '\0';
396     initgroups(name, pwd->pw_gid);
397     quota(Q_DOWARN, pwd->pw_uid, (dev_t) - 1, 0);
398     setuid(pwd->pw_uid);
399     /* destroy environment unless user has asked to preserve it */
400     if (!pflag)
401         environ = envinit;
402
403     /* set up environment, this time without destruction */
404     /* copy the environment before setenving */
405     i = 0;
406     while (environ[i] != NULL)
407         i++;
408     envnew = (char **)malloc(sizeof(char *) * (i + 1));
409     for (; i >= 0; i--)
410         envnew[i] = environ[i];
411     environ = envnew;
412
413     setenv("HOME=", pwd->pw_dir, 1);
414     setenv("SHELL=", pwd->pw_shell, 1);
415     if (term[0] == '\0')
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);
420
421     if ((namep = strrchr(pwd->pw_shell, '/')) == NULL)
422         namep = pwd->pw_shell;
423     else
424         namep++;
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)
429         if (utmp.ut_host[0])
430             syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %.*s", tty, HMAX,
431                    utmp.ut_host);
432         else
433             syslog(LOG_NOTICE, "ROOT LOGIN %s", tty);
434     if (!quietlog) {
435         struct stat st;
436
437         showmotd();
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 " : "");
442     }
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");
450     exit(0);
451 }
452
453 static void
454 getloginname(struct utmp *up)
455 {
456     char *namep;
457     int c;
458
459     while (up->ut_name[0] == '\0') {
460         namep = up->ut_name;
461         printf("login: ");
462         while ((c = getchar()) != '\n') {
463             if (c == ' ')
464                 c = '_';
465             if (c == EOF)
466                 exit(0);
467             if (namep < up->ut_name + NMAX)
468                 *namep++ = (char)c;
469         }
470     }
471     strncpy(lusername, up->ut_name, NMAX);
472     lusername[NMAX] = 0;
473     if ((pwd = getpwnam(lusername)) == NULL)
474         pwd = &nouser;
475 }
476
477 static void
478 timedout(void)
479 {
480
481     printf("Login timed out after %d seconds\n", timeout);
482     exit(0);
483 }
484
485 int stopmotd;
486 static void
487 catch(void)
488 {
489
490     signal(SIGINT, SIG_IGN);
491     stopmotd++;
492 }
493
494 int
495 rootterm(char *tty)
496 {
497     struct ttyent *t;
498
499     if ((t = getttynam(tty)) != NULL) {
500         if (t->ty_status & TTY_SECURE)
501             return (1);
502     }
503     return (0);
504 }
505
506 static void
507 showmotd(void)
508 {
509     FILE *mf;
510     int c;
511
512     signal(SIGINT, catch);
513     if ((mf = fopen("/etc/motd", "r")) != NULL) {
514         while ((c = getc(mf)) != EOF && stopmotd == 0)
515             putchar(c);
516         fclose(mf);
517     }
518     signal(SIGINT, SIG_IGN);
519 }
520
521 #undef  UNKNOWN
522 #define UNKNOWN "su"
523
524 char *
525 stypeof(char *ttyid)
526 {
527     struct ttyent *t;
528
529     if (ttyid == NULL || (t = getttynam(ttyid)) == NULL)
530         return (UNKNOWN);
531     return (t->ty_type);
532 }
533
534 int
535 doremotelogin(char *host)
536 {
537     getstr(rusername, sizeof(rusername), "remuser");
538     getstr(lusername, sizeof(lusername), "locuser");
539     getstr(term, sizeof(term), "Terminal type");
540     if (getuid()) {
541         pwd = &nouser;
542         return (-1);
543     }
544     pwd = getpwnam(lusername);
545     if (pwd == NULL) {
546         pwd = &nouser;
547         return (-1);
548     }
549     return (ruserok(host, (pwd->pw_uid == 0), rusername, lusername));
550 }
551
552 int
553 getstr(char *buf, int cnt, char *err)
554 {
555     char c;
556
557     do {
558         if (read(0, &c, 1) != 1)
559             exit(1);
560         if (--cnt < 0) {
561             printf("%s too long\r\n", err);
562             exit(1);
563         }
564         *buf++ = c;
565     } while (c != 0);
566 }
567
568 char *speeds[] = { "0", "50", "75", "110", "134", "150", "200", "300",
569     "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400"
570 };
571
572 #define NSPEEDS (sizeof (speeds) / sizeof (speeds[0]))
573
574 static void
575 doremoteterm(char *term, struct sgttyb *tp)
576 {
577     char *cp = strchr(term, '/'), **cpp;
578     char *speed;
579
580     if (cp) {
581         *cp++ = '\0';
582         speed = cp;
583         cp = strchr(speed, '/');
584         if (cp)
585             *cp++ = '\0';
586         for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++)
587             if (strcmp(*cpp, speed) == 0) {
588                 tp->sg_ispeed = tp->sg_ospeed = cpp - speeds;
589                 break;
590             }
591     }
592     tp->sg_flags = ECHO | CRMOD | ANYP | XTABS;
593 }
594
595 /*
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.
601  */
602 static void
603 setenv(char *var, char *value, int clobber)
604 {
605     extern char **environ;
606     int index = 0;
607     int varlen = strlen(var);
608     int vallen = strlen(value);
609
610     for (index = 0; environ[index] != NULL; index++) {
611         if (strncmp(environ[index], var, varlen) == 0) {
612             /* found it */
613             if (!clobber)
614                 return;
615             environ[index] = malloc(varlen + vallen + 1);
616             strcpy(environ[index], var);
617             strcat(environ[index], value);
618             return;
619         }
620     }
621     environ = (char **)realloc(environ, sizeof(char *) * (index + 2));
622     if (environ == NULL) {
623         fprintf(stderr, "login: malloc out of memory\n");
624         exit(1);
625     }
626     environ[index] = malloc(varlen + vallen + 1);
627     strcpy(environ[index], var);
628     strcat(environ[index], value);
629     environ[++index] = NULL;
630 }
631
632 static gid_t
633 tty_gid(int default_gid)
634 {
635     struct group *getgrnam(), *gr;
636     gid_t gid = default_gid;
637
638     gr = getgrnam(TTYGRPNAME);
639     if (gr != NULL)
640         gid = gr->gr_gid;
641
642     endgrent();
643
644     return (gid);
645 }
646 #else
647
648 #include "AFS_component_version_number.c"
649
650 main()
651 {
652 }
653 #endif /*!defined(AFS_SUN_ENV) && !defined(AFS_AIX_ENV) && !defined(AFS_HPUX_ENV) */