source: trunk/athena/bin/login/login.c @ 1975

Revision 1975, 39.5 KB checked in by raeburn, 35 years ago (diff)
Added a routine to verify the received ticket-granting ticket. Also re-arranged and deleted some unused variables.
Line 
1/*
2 *      $Source: /afs/dev.mit.edu/source/repository/athena/bin/login/login.c,v $
3 *      $Header: /afs/dev.mit.edu/source/repository/athena/bin/login/login.c,v 1.25 1989-07-19 20:24:16 raeburn Exp $
4 */
5
6#ifndef lint
7static char *rcsid_login_c =
8    "$Header: /afs/dev.mit.edu/source/repository/athena/bin/login/login.c,v 1.25 1989-07-19 20:24:16 raeburn Exp $";
9#endif  /* lint */
10
11/*
12 * Copyright (c) 1980 Regents of the University of California.
13 * All rights reserved.  The Berkeley software License Agreement
14 * specifies the terms and conditions for redistribution.
15 */
16
17#ifndef lint
18char copyright[] =
19"@(#) Copyright (c) 1980 Regents of the University of California.\n\
20 All rights reserved.\n";
21#endif not lint
22
23#ifndef lint
24static char sccsid[] = "@(#)login.c     5.15 (Berkeley) 4/12/86";
25#endif not lint
26
27/*
28 * login [ name ]
29 * login -r hostname (for rlogind)
30 * login -k hostname (for Kerberos rlogind with password access)
31 * login -K hostname (for Kerberos rlogind with restricted access)
32 * login -h hostname (for telnetd, etc.)
33 */
34
35#include <sys/param.h>
36#ifndef VFS
37#include <sys/quota.h>
38#endif !VFS
39#include <sys/stat.h>
40#include <sys/time.h>
41#include <sys/resource.h>
42#include <sys/file.h>
43#include <sys/dir.h>
44#include <sys/wait.h>
45
46#include <sgtty.h>
47#include <utmp.h>
48#include <signal.h>
49#include <pwd.h>
50#include <stdio.h>
51#include <lastlog.h>
52#include <errno.h>
53#include <ttyent.h>
54#include <syslog.h>
55#include <strings.h>
56#include <krb.h>       
57#include <netdb.h>
58#include <sys/types.h>
59#include <netinet/in.h>
60#include <grp.h>
61typedef struct in_addr inaddr_t;
62#include <attach.h>
63
64#define TTYGRPNAME      "tty"           /* name of group to own ttys */
65#define TTYGID(gid)     tty_gid(gid)    /* gid that owns all ttys */
66
67#define SCMPN(a, b)     strncmp(a, b, sizeof(a))
68#define SCPYN(a, b)     strncpy(a, b, sizeof(a))
69
70#define NMAX    sizeof(utmp.ut_name)
71#define HMAX    sizeof(utmp.ut_host)
72
73#define FALSE   0
74#define TRUE    -1
75
76#ifdef VFS
77#define QUOTAWARN       "/usr/ucb/quota"        /* warn user about quotas */
78#endif VFS
79
80#ifndef KRB_REALM
81#define KRB_REALM       "ATHENA.MIT.EDU"
82#endif
83
84#define KRB_ENVIRON     "KRBTKFILE" /* Ticket file environment variable */
85#define KRB_TK_DIR      "/tmp/tkt_" /* Where to put the ticket */
86#define KRBTKLIFETIME   96      /* 8 hours */
87
88#define PROTOTYPE_DIR   "/usr/prototype_user" /* Source for temp files */
89#define TEMP_DIR_PERM   0755    /* Permission on temporary directories */
90
91#define MAXPWSIZE       128     /* Biggest key getlongpass will return */
92
93#define START_UID       200     /* start assigning arbitrary UID's here */
94#define MIT_GID         101     /* standard primary group "mit" */
95
96extern char *krb_err_txt[];     /* From libkrb */
97
98char    nolog[] =       "/etc/nologin";
99char    qlog[]  =       ".hushlogin";
100char    maildir[30] =   "/usr/spool/mail/";
101char    lastlog[] =     "/usr/adm/lastlog";
102char    inhibit[] =     "/etc/nocreate";
103char    noattach[] =    "/etc/noattach";
104char    go_register[] = "/usr/etc/go_register";
105char    get_motd[] =    "/bin/athena/get_message";
106
107/* uid, gid, etc. used to be -1; guess what setreuid does with that --asp */
108struct  passwd nouser = {"", "nope", -2, -2, -2, "", "", "", "" };
109
110struct  passwd newuser = {"\0\0\0\0\0\0\0\0", "*", START_UID, MIT_GID, 0,
111                          NULL, NULL, "/mit/\0\0\0\0\0\0\0\0", NULL };
112
113struct  sgttyb ttyb;
114struct  utmp utmp;
115char    minusnam[16] = "-";
116char    *envinit[] = { 0 };             /* now set by setenv calls */
117/*
118 * This bounds the time given to login.  We initialize it here
119 * so it can be patched on machines where it's too small.
120 */
121int     timeout = 60;
122
123char    term[64];
124
125struct  passwd *pwd;
126struct  passwd *hes_getpwnam();
127char    *strcat(), *rindex(), *index(), *malloc(), *realloc();
128int     timedout();
129char    *ttyname();
130char    *crypt();
131char    *getlongpass();
132char    *stypeof();
133extern  char **environ;
134extern  int errno;
135
136struct  tchars tc = {
137        CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK
138};
139struct  ltchars ltc = {
140        CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT
141};
142
143struct winsize win = { 0, 0, 0, 0 };
144
145int     rflag=0;
146int     kflag=0;
147int     Kflag=0;
148int     usererr = -1;
149int     krbflag = FALSE;        /* True if Kerberos-authenticated login */
150int     tmppwflag = FALSE;      /* True if passwd entry is temporary */
151int     tmpdirflag = FALSE;     /* True if home directory is temporary */
152int     inhibitflag = FALSE;    /* inhibit account creation on the fly */
153int     attachable = FALSE;     /* True if /etc/noattach doesn't exist */
154int     attachedflag = FALSE;   /* True if homedir attached */
155int     errorprtflag = FALSE;   /* True if login error already printed */
156char    rusername[NMAX+1], lusername[NMAX+1];
157char    rpassword[NMAX+1];
158char    name[NMAX+1];
159char    *rhost;
160
161AUTH_DAT *kdata = (AUTH_DAT *)NULL;
162
163union wait waitstat;
164
165main(argc, argv)
166    char *argv[];
167{
168    register char *namep;
169    int pflag = 0, hflag = 0, t, f, c;
170    int invalid, quietlog, forkval;
171    FILE *nlfd;
172    char *ttyn, *tty, saltc[2];
173    long salt;
174    int ldisc = 0, zero = 0, found = 0, i;
175    char **envnew;
176
177    signal(SIGALRM, timedout);
178    alarm(timeout);
179    signal(SIGQUIT, SIG_IGN);
180    signal(SIGINT, SIG_IGN);
181    setpriority(PRIO_PROCESS, 0, 0);
182#ifndef VFS
183    quota(Q_SETUID, 0, 0, 0);
184#endif !VFS
185    /*
186     * -p is used by getty to tell login not to destroy the environment
187     * -r is used by rlogind to cause the autologin protocol;
188     * -k is used by klogind to cause the Kerberos autologin protocol;
189     * -K is used by klogind to cause the Kerberos autologin protocol with
190     *    restricted access.;
191     * -h is used by other servers to pass the name of the
192     * remote host to login so that it may be placed in utmp and wtmp
193     */
194    while (argc > 1) {
195        if (strcmp(argv[1], "-r") == 0) {
196            if (rflag || kflag || Kflag || hflag) {
197                printf("Only one of -r -k -K or -h allowed\n");
198                exit(1);
199            }
200            if (argv[2] == 0)
201              exit(1);
202            rflag = 1;
203            usererr = doremotelogin(argv[2]);
204            SCPYN(utmp.ut_host, argv[2]);
205            argc -= 2;
206            argv += 2;
207            continue;
208        }
209                if (strcmp(argv[1], "-k") == 0) {
210                        if (rflag || kflag || Kflag || hflag) {
211                                printf("Only one of -r -k -K or -h allowed\n");
212                                exit(1);
213                        }
214                        kflag = 1;
215                        usererr = doKerberosLogin(argv[2]);
216                        SCPYN(utmp.ut_host, argv[2]);
217                        argc -= 2;
218                        argv += 2;
219                        continue;
220                }
221                if (strcmp(argv[1], "-K") == 0) {
222                        if (rflag || kflag || Kflag || hflag) {
223                                printf("Only one of -r -k -K or -h allowed\n");
224                                exit(1);
225                        }
226                        Kflag = 1;
227                        usererr = doKerberosLogin(argv[2]);
228                        SCPYN(utmp.ut_host, argv[2]);
229                        argc -= 2;
230                        argv += 2;
231                        continue;
232                }
233        if (strcmp(argv[1], "-h") == 0 && getuid() == 0) {
234            if (rflag || kflag || Kflag || hflag) {
235                printf("Only one of -r -k -K or -h allowed\n");
236                exit(1);
237            }
238            hflag = 1;
239            SCPYN(utmp.ut_host, argv[2]);
240            argc -= 2;
241            argv += 2;
242            continue;
243        }
244        if (strcmp(argv[1], "-p") == 0) {
245            argc--;
246            argv++;
247            pflag = 1;
248            continue;
249        }
250        break;
251    }
252    ioctl(0, TIOCLSET, &zero);
253    ioctl(0, TIOCNXCL, 0);
254    ioctl(0, FIONBIO, &zero);
255    ioctl(0, FIOASYNC, &zero);
256    ioctl(0, TIOCGETP, &ttyb);
257    /*
258     * If talking to an rlogin process,
259     * propagate the terminal type and
260     * baud rate across the network.
261     */
262    if (rflag || kflag || Kflag)
263        doremoteterm(term, &ttyb);
264    ttyb.sg_erase = CERASE;
265    ttyb.sg_kill = CKILL;
266    ioctl(0, TIOCSLTC, &ltc);
267    ioctl(0, TIOCSETC, &tc);
268    ioctl(0, TIOCSETP, &ttyb);
269    for (t = getdtablesize(); t > 2; t--)
270        close(t);
271    ttyn = ttyname(0);
272    if (ttyn == (char *)0 || *ttyn == '\0')
273        ttyn = "/dev/tty??";
274    tty = rindex(ttyn, '/');
275    if (tty == NULL)
276        tty = ttyn;
277    else
278        tty++;
279    openlog("login", LOG_ODELAY, LOG_AUTH);
280
281    /* destroy environment unless user has asked to preserve it */
282    /* (Moved before passwd stuff by asp) */
283    if (!pflag)
284        environ = envinit;
285
286    /* set up environment, this time without destruction */
287    /* copy the environment before setenving */
288    i = 0;
289    while (environ[i] != NULL)
290        i++;
291    envnew = (char **) malloc(sizeof (char *) * (i + 1));
292    for (; i >= 0; i--)
293        envnew[i] = environ[i];
294    environ = envnew;
295
296    t = 0;
297    invalid = FALSE;
298    inhibitflag = !access(inhibit,F_OK);
299    attachable = access(noattach, F_OK);
300    do {
301            errorprtflag = 0;
302            ldisc = 0;
303        found = 0;
304        ioctl(0, TIOCSETD, &ldisc);
305        SCPYN(utmp.ut_name, "");
306        /*
307         * Name specified, take it.
308         */
309        if (argc > 1) {
310            SCPYN(utmp.ut_name, argv[1]);
311            argc = 0;
312        }
313        /*
314         * If remote login take given name,
315         * otherwise prompt user for something.
316         */
317        if ((rflag || kflag || Kflag) && !invalid) {
318            SCPYN(utmp.ut_name, lusername);
319            if((pwd = getpwnam(lusername)) == NULL) {
320                    pwd = &nouser;
321                    found = 0;
322            } else found = 1;
323        } else {
324                found = getloginname(&utmp);
325                if (utmp.ut_name[0] == '-') {
326                        puts("login names may not start with '-'.");
327                        invalid = TRUE;
328                        continue;
329                }
330        }
331 
332        invalid = FALSE;
333        if (!strcmp(pwd->pw_shell, "/bin/csh")) {
334            ldisc = NTTYDISC;
335            ioctl(0, TIOCSETD, &ldisc);
336        }
337        /*
338         * If no remote login authentication and
339         * a password exists for this user, prompt
340         * for one and verify it.
341         */
342        if (usererr == -1 && *pwd->pw_passwd != '\0') {
343                /* we need to be careful to overwrite the password once it has
344                 * been checked, so that it can't be recovered from a core image.
345                 */
346
347            char *pp, pp2[MAXPWSIZE+1];
348            int krbval;
349            char tkfile[32];
350            char realm[REALM_SZ];
351           
352            /* Set up the ticket file environment variable */
353            SCPYN(tkfile, KRB_TK_DIR);
354            strncat(tkfile, rindex(ttyn, '/')+1,
355                    sizeof(tkfile) - strlen(tkfile));
356            (void) unlink (tkfile);
357            setenv(KRB_ENVIRON, tkfile);
358           
359            setpriority(PRIO_PROCESS, 0, -4);
360            pp = getlongpass("Password:");
361           
362            if (!found) /* check if we can create an entry */
363                    if (inhibitflag)
364                        invalid = TRUE;
365                    else /* we are allowed to create an entry */
366                        pwd = &newuser;
367
368            /* Modifications for Kerberos authentication -- asp */
369            SCPYN(pp2, pp);
370            pp[8]='\0';
371            if (found)
372                    namep = crypt(pp, pwd->pw_passwd);
373            else {
374                    salt = 9 * getpid();
375                    saltc[0] = salt & 077;
376                    saltc[1] = (salt>>6) & 077;
377                    for (i=0;i<2;i++) {
378                            c = saltc[i] + '.';
379                            if (c > '9')
380                                    c += 7;
381                            if (c > 'Z')
382                                    c += 6;
383                            saltc[i] = c;
384                    }
385                    pwd->pw_passwd = namep = crypt(pp, saltc);
386            }
387                           
388            bzero(pp, 8);               /* No, Senator, I don't recall
389                                           anything of that nature ... */
390            setpriority(PRIO_PROCESS, 0, 0);
391
392            if (!invalid && (pwd->pw_uid != 0)) {
393                    /* if not root, get Kerberos tickets */
394                if(get_krbrlm(realm, 1) != KSUCCESS) {
395                    SCPYN(realm, KRB_REALM);
396                }
397                strncpy(lusername, utmp.ut_name, NMAX);
398                lusername[NMAX] = '\0';
399                krbval = get_in_tkt(lusername, "", realm,
400                                    "krbtgt", realm, KRBTKLIFETIME, pp2);
401                bzero(pp2, MAXPWSIZE+1); /* Yes, he's senile.  He doesn't know
402                                            what his administration is doing */
403                switch (krbval) {
404                case INTK_OK:
405                        alarm(0);       /* Authentic, so don't time out. */
406                        if (verify_krb_tgt(realm) < 0) {
407                            /* Oops.  He tried to fool us.  Tsk, tsk. */
408                            invalid = TRUE;
409                            goto leavethis;
410                        }
411                        invalid = FALSE;
412                        krbflag = TRUE;
413                        if (!found) {
414                                /* create a password entry: first ask the nameserver */
415                                /* to get us finger and shell info */
416                                struct passwd *nspwd;
417                                if ((nspwd = hes_getpwnam(lusername)) != NULL) {
418                                        pwd->pw_uid = nspwd->pw_uid;
419                                        pwd->pw_gid = nspwd->pw_gid;
420                                        pwd->pw_gecos = nspwd->pw_gecos;
421                                        pwd->pw_shell = nspwd->pw_shell;
422                                } else {
423                                        pwd->pw_uid = 200;
424                                        pwd->pw_gid = MIT_GID;
425                                        pwd->pw_gecos = "";
426                                        pwd->pw_shell = "/bin/csh";
427                                }
428                                strncpy(pwd->pw_name, utmp.ut_name, NMAX);
429                                strncat(pwd->pw_dir, utmp.ut_name, NMAX);
430                                (void) insert_pwent(pwd);
431                                tmppwflag = TRUE;
432                        }
433                        chown(getenv(KRB_ENVIRON), pwd->pw_uid, pwd->pw_gid);
434                        /* If we already have a homedir, use it.
435                         * Otherwise, try to attach.  If that fails,
436                         * try to create.
437                         */
438                        tmpdirflag = FALSE;
439                        if (!goodhomedir()) {
440                                if (attach_homedir()) {
441                                        puts("\nWarning: Unable to attach home directory.");
442                                        if (make_homedir() >= 0) {
443                                                puts("\nNOTE -- Your home directory is temporary.");
444                                                puts("It will be deleted when this workstation deactivates.\n");
445                                                tmpdirflag = TRUE;
446                                        }
447                                        else if (chdir("/") < 0) {
448                                                printf("No directory '/'!\n");
449                                                invalid = TRUE;
450                                        } else {
451                                                puts("Can't find or build home directory! Logging in with home=/");
452                                                pwd->pw_dir = "/";
453                                                tmpdirflag = FALSE;
454                                        }
455                                }
456                                else {
457                                        attachedflag = TRUE;
458                                }
459                        }
460                        else
461                                puts("\nWarning: Using local home directory.");
462                        break;
463                   
464                  case KDC_NULL_KEY:
465                        invalid = TRUE;
466                        /* tell the luser to go register with kerberos */
467
468                        if (found)
469                                goto good_anyway;
470                       
471                        alarm(0);       /* If we are changing password,
472                                           he won't be logging in in this
473                                           process anyway, so we can reset */
474
475                        (void) insert_pwent(pwd);
476                       
477                        if (forkval = fork()) { /* parent */
478                            if (forkval < 0) {
479                                perror("forking for registration program");
480                                sleep(3);
481                                exit(1);
482                            }
483                            while(wait(0) != forkval);
484                            remove_pwent(pwd);
485                            exit(0);
486                        }
487                        /* run the passwd program as the user */
488                        setuid(pwd->pw_uid);
489                       
490                        execl(go_register, go_register, lusername, 0);
491                        perror("executing registration program");
492                        sleep(2);
493                        exit(1);
494                        /* These errors should be printed and are fatal */
495                case KDC_PR_UNKNOWN:
496                case KDC_PR_N_UNIQUE:
497                        invalid = TRUE;
498                        if (found)
499                                goto good_anyway;
500                case INTK_BADPW:
501                        invalid = TRUE;
502                        errorprtflag = TRUE;
503                        fprintf(stderr, "%s\n",
504                                krb_err_txt[krbval]);
505                        goto leavethis;
506                    /* These should be printed but are not fatal */
507                case INTK_W_NOTALL:
508                    invalid = FALSE;
509                    krbflag = TRUE;
510                    fprintf(stderr, "Kerberos error: %s\n",
511                            krb_err_txt[krbval]);
512                        goto leavethis;
513                  default:
514                    fprintf(stderr, "Kerberos error: %s\n",
515                            krb_err_txt[krbval]);
516                    invalid = TRUE;
517                        errorprtflag = TRUE;
518                        goto leavethis;
519                }
520        } else { /* root logging in or inhibited; check password */
521                bzero(pp2, MAXPWSIZE+1); /* Yes, he's senile.  He doesn't know
522                                          * what his administration is doing */
523                invalid = TRUE;
524        }
525            /* if password is good, user is good */
526    good_anyway:
527            invalid = invalid && strcmp(namep, pwd->pw_passwd);
528    }
529
530leavethis:
531        /*
532         * If our uid < 0, we must be a bogus user.
533         */
534        if(pwd->pw_uid < 0) invalid = TRUE;
535
536        /*
537         * If user not super-user, check for logins disabled.
538         */
539        if (pwd->pw_uid != 0 && (nlfd = fopen(nolog, "r")) != 0) {
540            while ((c = getc(nlfd)) != EOF)
541                putchar(c);
542            fflush(stdout);
543            sleep(5);
544            if (krbflag)
545                    (void) dest_tkt();
546            exit(0);
547        }
548        /*
549         * If valid so far and root is logging in,
550         * see if root logins on this terminal are permitted.
551         */
552        if (!invalid && pwd->pw_uid == 0 && !rootterm(tty)) {
553            if (utmp.ut_host[0])
554                syslog(LOG_CRIT,
555                       "ROOT LOGIN REFUSED ON %s FROM %.*s",
556                       tty, HMAX, utmp.ut_host);
557            else
558                syslog(LOG_CRIT,
559                       "ROOT LOGIN REFUSED ON %s", tty);
560            invalid = TRUE;
561        }
562        if (invalid) {
563                if (!errorprtflag)
564                        printf("Login incorrect\n");
565                if (++t >= 5) {
566                if (utmp.ut_host[0])
567                    syslog(LOG_CRIT,
568                           "REPEATED LOGIN FAILURES ON %s FROM %.*s, %.*s",
569                           tty, HMAX, utmp.ut_host,
570                           NMAX, utmp.ut_name);
571                else
572                    syslog(LOG_CRIT,
573                           "REPEATED LOGIN FAILURES ON %s, %.*s",
574                           tty, NMAX, utmp.ut_name);
575                ioctl(0, TIOCHPCL, (struct sgttyb *) 0);
576                close(0), close(1), close(2);
577                sleep(10);
578                exit(1);
579            }
580        }
581        if (*pwd->pw_shell == '\0')
582            pwd->pw_shell = "/bin/sh";
583        if (chdir(pwd->pw_dir) < 0 && !invalid ) {
584            if (chdir("/") < 0) {
585                printf("No directory!\n");
586                invalid = TRUE;
587            } else {
588                puts("No directory! Logging in with home=/\n");
589                pwd->pw_dir = "/";
590            }
591        }
592        /*
593         * Remote login invalid must have been because
594         * of a restriction of some sort, no extra chances.
595         */
596        if (!usererr && invalid)
597            exit(1);
598
599    } while (invalid);
600    /* committed to login turn off timeout */
601    alarm(0);
602
603    if (tmppwflag) {
604            remove_pwent(pwd);
605            insert_pwent(pwd);
606    }
607
608    if (!krbflag) puts("Warning: no Kerberos tickets obtained.");
609    get_groups();
610#ifndef VFS
611    if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) {
612        if (errno == EUSERS)
613            printf("%s.\n%s.\n",
614                   "Too many users logged on already",
615                   "Try again later");
616        else if (errno == EPROCLIM)
617            printf("You have too many processes running.\n");
618        else
619            perror("quota (Q_SETUID)");
620        sleep(5);
621        if (krbflag)
622                (void) dest_tkt();
623        exit(0);
624    }
625#endif VFS
626    time(&utmp.ut_time);
627    t = ttyslot();
628    if (t > 0 && (f = open("/etc/utmp", O_WRONLY)) >= 0) {
629        lseek(f, (long)(t*sizeof(utmp)), 0);
630        SCPYN(utmp.ut_line, tty);
631        write(f, (char *)&utmp, sizeof(utmp));
632        close(f);
633    }
634    if ((f = open("/usr/adm/wtmp", O_WRONLY|O_APPEND)) >= 0) {
635        write(f, (char *)&utmp, sizeof(utmp));
636        close(f);
637    }
638    quietlog = access(qlog, F_OK) == 0;
639    if ((f = open(lastlog, O_RDWR)) >= 0) {
640        struct lastlog ll;
641
642        lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0);
643        if (read(f, (char *) &ll, sizeof ll) == sizeof ll &&
644            ll.ll_time != 0 && !quietlog) {
645            printf("Last login: %.*s ",
646                   24-5, (char *)ctime(&ll.ll_time));
647            if (*ll.ll_host != '\0')
648            printf("from %.*s\n",
649                   sizeof (ll.ll_host), ll.ll_host);
650            else
651            printf("on %.*s\n",
652                   sizeof (ll.ll_line), ll.ll_line);
653        }
654        lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0);
655        time(&ll.ll_time);
656        SCPYN(ll.ll_line, tty);
657        SCPYN(ll.ll_host, utmp.ut_host);
658        write(f, (char *) &ll, sizeof ll);
659        close(f);
660    }
661    chown(ttyn, pwd->pw_uid, TTYGID(pwd->pw_gid));
662
663    if (!hflag && !rflag && !pflag && !kflag && !Kflag)         /* XXX */
664        ioctl(0, TIOCSWINSZ, &win);
665    chmod(ttyn, 0620);
666
667    init_wgfile();
668   
669    /* Fork so that we can call kdestroy, notification server */
670    dofork();
671       
672    setgid(pwd->pw_gid);
673    strncpy(name, utmp.ut_name, NMAX);
674    name[NMAX] = '\0';
675    initgroups(name, pwd->pw_gid);
676#ifndef VFS
677    quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0);
678#endif !VFS
679
680    /* This call MUST succeed */
681    if(setuid(pwd->pw_uid) < 0) {
682        perror("setuid");
683        if (krbflag)
684                (void) dest_tkt();
685        exit(1);
686    }
687
688    setenv("HOME", pwd->pw_dir, 1);
689    setenv("SHELL", pwd->pw_shell, 1);
690    if (term[0] == '\0')
691        strncpy(term, stypeof(tty), sizeof(term));
692    setenv("TERM", term, 0);
693    setenv("USER", pwd->pw_name, 1);
694    setenv("PATH", ":/usr/athena:/bin/athena:/usr/new:/usr/new/mh/bin:\
695/usr/local:/usr/ucb:/bin:/usr/bin", 0);
696
697    if ((namep = rindex(pwd->pw_shell, '/')) == NULL)
698        namep = pwd->pw_shell;
699    else
700        namep++;
701    strcat(minusnam, namep);
702    if (tty[sizeof("tty")-1] == 'd')
703        syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
704    if (pwd->pw_uid == 0)
705        if (utmp.ut_host[0])
706                        if (kdata) {
707                                syslog(LOG_NOTICE, "ROOT LOGIN via Kerberos from %.*s",
708                                        HMAX, utmp.ut_host);
709                                syslog(LOG_NOTICE, "     (name=%s, instance=%s, realm=%s).",
710                                        kdata->pname, kdata->pinst, kdata->prealm );
711                        } else {
712                                syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %.*s",
713                                        tty, HMAX, utmp.ut_host);
714                        }
715                else
716                        if (kdata) {
717                                syslog(LOG_NOTICE, "ROOT LOGIN via Kerberos %s ", tty);
718                                syslog(LOG_NOTICE, "     (name=%s, instance=%s, realm=%s).",
719                                        kdata->pname,kdata->pinst,kdata->prealm);
720                        } else {
721                                syslog(LOG_NOTICE, "ROOT LOGIN %s", tty);
722                        }
723    if (!quietlog) {
724        struct stat st;
725
726        showmotd();
727        strcat(maildir, pwd->pw_name);
728        if (stat(maildir, &st) == 0 && st.st_size != 0)
729            printf("You have %smail.\n",
730                   (st.st_mtime > st.st_atime) ? "new " : "");
731    }
732#ifdef VFS
733    if (! access( QUOTAWARN, X_OK)) system(QUOTAWARN);
734#endif VFS
735    signal(SIGALRM, SIG_DFL);
736    signal(SIGQUIT, SIG_DFL);
737    signal(SIGINT, SIG_DFL);
738    signal(SIGTSTP, SIG_IGN);
739    execlp(pwd->pw_shell, minusnam, 0);
740    perror(pwd->pw_shell);
741    printf("No shell\n");
742    if (krbflag)
743            (void) dest_tkt();
744    exit(0);
745}
746
747getloginname(up)
748        register struct utmp *up;
749{
750        register char *namep;
751        int c;
752
753        while (up->ut_name[0] == '\0') {
754                namep = up->ut_name;
755                printf("login: ");
756                while ((c = getchar()) != '\n') {
757                        if (c == ' ')
758                                c = '_';
759                        if (c == EOF)
760                                exit(0);
761                        if (namep < up->ut_name+NMAX)
762                                *namep++ = c;
763                }
764        }
765        strncpy(lusername, up->ut_name, NMAX);
766        lusername[NMAX] = 0;
767        if((pwd = getpwnam(lusername)) == NULL) {
768            pwd = &nouser;
769            return(0);                  /* NOT FOUND */
770        }
771        return(1);                      /* FOUND */
772}
773
774timedout()
775{
776
777        printf("Login timed out after %d seconds\n", timeout);
778        exit(0);
779}
780
781int     stopmotd;
782catch()
783{
784
785        signal(SIGINT, SIG_IGN);
786        stopmotd++;
787}
788
789rootterm(tty)
790        char *tty;
791{
792        register struct ttyent *t;
793
794        if ((t = getttynam(tty)) != NULL) {
795                if (t->ty_status & TTY_SECURE)
796                        return (1);
797        }
798        return (0);
799}
800
801showmotd()
802{
803        FILE *mf;
804        register c;
805        int forkval;
806
807        signal(SIGINT, catch);
808        if (forkval = fork()) { /* parent */
809                if (forkval < 0) {
810                        perror("forking for motd service");
811                        sleep(3);
812                }
813                else {
814                  while (wait(0) != forkval)
815                    ;
816                }
817        }
818        else {
819                if ((mf = fopen("/etc/motd", "r")) != NULL) {
820                        while ((c = getc(mf)) != EOF && stopmotd == 0)
821                                putchar(c);
822                        fclose(mf);
823                }
824                if (execl(get_motd, get_motd, "-login", 0) < 0) {
825                        /* hide error code if any... */
826                        exit(0);
827                }
828        }
829        signal(SIGINT, SIG_IGN);
830}
831
832#undef  UNKNOWN
833#define UNKNOWN "su"
834
835char *
836stypeof(ttyid)
837        char *ttyid;
838{
839        register struct ttyent *t;
840
841        if (ttyid == NULL || (t = getttynam(ttyid)) == NULL)
842                return (UNKNOWN);
843        return (t->ty_type);
844}
845
846doremotelogin(host)
847        char *host;
848{
849        getstr(rusername, sizeof (rusername), "remuser");
850        getstr(lusername, sizeof (lusername), "locuser");
851        getstr(term, sizeof(term), "Terminal type");
852        if (getuid()) {
853                pwd = &nouser;
854                return(-1);
855        }
856        if((pwd = getpwnam(lusername)) == NULL) {
857            pwd = &nouser;
858            return(-1);
859        }
860        return(ruserok(host, (pwd->pw_uid == 0), rusername, lusername));
861}
862
863doKerberosLogin(host)
864        char *host;
865{
866        int rc;
867        struct hostent *hp = gethostbyname(host);
868        struct sockaddr_in sin;
869
870        /*
871         * Kerberos autologin protocol.
872         */
873
874        (void) bzero(&sin, sizeof(sin));
875
876        if (hp)
877                (void) bcopy (hp->h_addr, &sin.sin_addr, sizeof(sin.sin_addr));
878        else
879                /*
880                 * No host addr prevents auth, so
881                 * punt krb and require password
882                 */
883                if (Kflag) {
884                        goto paranoid;
885                } else {
886                        pwd = &nouser;
887                        return(-1);
888                }
889
890        kdata = (AUTH_DAT *)malloc( sizeof(AUTH_DAT) );
891        if (rc=GetKerberosData(0, sin.sin_addr, kdata, "rcmd" )) {
892                printf("Kerberos rlogin failed: %s\r\n",krb_err_txt[rc]);
893                if (Kflag) {
894paranoid:
895                        /*
896                         * Paranoid hosts, such as a Kerberos server, specify the Klogind
897                         * daemon to disallow even password access here.
898                         */
899                        printf("Sorry, you must have Kerberos authentication to access this host.\r\n");
900                        exit(1);
901                }
902        }
903        getstr(lusername, sizeof (lusername), "locuser");
904        getstr(term, sizeof(term), "Terminal type");
905        if (getuid()) {
906                pwd = &nouser;
907                return(-1);
908        }
909        pwd = getpwnam(lusername);
910        if (pwd == NULL) {
911                pwd = &nouser;
912                return(-1);
913        }
914
915        /*
916         * if Kerberos login failed because of an error in GetKerberosData,
917         * return the indication of a bad attempt.  User will be prompted
918         * for a password.  We CAN'T check the .rhost file, because we need
919         * the remote username to do that, and the remote username is in the
920         * Kerberos ticket.  This affects ONLY the case where there is Kerberos
921         * on both ends, but Kerberos fails on the server end.
922         */
923        if (rc) {
924                return(-1);
925        }
926
927        if (rc=kuserok(kdata,lusername)) {
928                printf("login: %s has not given you permission to login without a password.\r\n",lusername);
929                if (Kflag) {
930                  exit(1);
931                }
932                return(-1);
933        }
934        return(0);
935
936}
937
938getstr(buf, cnt, err)
939        char *buf;
940        int cnt;
941        char *err;
942{
943        char c;
944
945        do {
946                if (read(0, &c, 1) != 1)
947                        exit(1);
948                if (--cnt < 0) {
949                        printf("%s too long\r\n", err);
950                        exit(1);
951                }
952                *buf++ = c;
953        } while (c != 0);
954}
955
956char    *speeds[] =
957    { "0", "50", "75", "110", "134", "150", "200", "300",
958      "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
959#define NSPEEDS (sizeof (speeds) / sizeof (speeds[0]))
960
961doremoteterm(term, tp)
962        char *term;
963        struct sgttyb *tp;
964{
965        register char *cp = index(term, '/'), **cpp;
966        char *speed;
967
968        if (cp) {
969                *cp++ = '\0';
970                speed = cp;
971                cp = index(speed, '/');
972                if (cp)
973                        *cp++ = '\0';
974                for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++)
975                        if (strcmp(*cpp, speed) == 0) {
976                                tp->sg_ispeed = tp->sg_ospeed = cpp-speeds;
977                                break;
978                        }
979        }
980        tp->sg_flags = ECHO|CRMOD|ANYP|XTABS;
981}
982
983/* BEGIN TRASH
984 *
985 * This is here only long enough to get us by to the revised rlogin
986 */
987compatsiz(cp)
988        char *cp;
989{
990        struct winsize ws;
991
992        ws.ws_row = ws.ws_col = -1;
993        ws.ws_xpixel = ws.ws_ypixel = -1;
994        if (cp) {
995                ws.ws_row = atoi(cp);
996                cp = index(cp, ',');
997                if (cp == 0)
998                        goto done;
999                ws.ws_col = atoi(++cp);
1000                cp = index(cp, ',');
1001                if (cp == 0)
1002                        goto done;
1003                ws.ws_xpixel = atoi(++cp);
1004                cp = index(cp, ',');
1005                if (cp == 0)
1006                        goto done;
1007                ws.ws_ypixel = atoi(++cp);
1008        }
1009done:
1010        if (ws.ws_row != -1 && ws.ws_col != -1 &&
1011            ws.ws_xpixel != -1 && ws.ws_ypixel != -1)
1012                ioctl(0, TIOCSWINSZ, &ws);
1013}
1014/* END TRASH */
1015
1016/*
1017 * Set the value of var to be arg in the Unix 4.2 BSD environment env.
1018 * Var should NOT end in '='; setenv inserts it.
1019 * (bindings are of the form "var=value")
1020 * This procedure assumes the memory for the first level of environ
1021 * was allocated using malloc.
1022 */
1023setenv(var, value, clobber)
1024        char *var, *value;
1025{
1026        extern char **environ;
1027        int index = 0;
1028        int varlen = strlen(var);
1029        int vallen = strlen(value);
1030
1031        for (index = 0; environ[index] != NULL; index++) {
1032                if (strncmp(environ[index], var, varlen) == 0) {
1033                        /* found it */
1034                        if (!clobber)
1035                                return;
1036                        environ[index] = malloc(varlen + vallen + 2);
1037                        strcpy(environ[index], var);
1038                        strcat(environ[index], "=");
1039                        strcat(environ[index], value);
1040                        return;
1041                }
1042        }
1043        environ = (char **) realloc(environ, sizeof (char *) * (index + 2));
1044        if (environ == NULL) {
1045                fprintf(stderr, "login: malloc out of memory\n");
1046                if (krbflag)
1047                        (void) dest_tkt();
1048                exit(1);
1049        }
1050        environ[index] = malloc(varlen + vallen + 2);
1051        strcpy(environ[index], var);
1052        strcat(environ[index], "=");
1053        strcat(environ[index], value);
1054        environ[++index] = NULL;
1055}
1056
1057
1058/*
1059 * This routine handles cleanup stuff, notification service, and the like.
1060 * It exits only in the child process.
1061 */
1062dofork()
1063{
1064    int child;
1065
1066    if(!(child=fork()))
1067            return; /* Child process */
1068
1069    /* Setup stuff?  This would be things we could do in parallel with login */
1070    chdir("/"); /* Let's not keep the fs busy... */
1071   
1072   
1073    /* If we're the parent, watch the child until it dies */
1074    while(wait(0) != child)
1075            ;
1076
1077    /* Cleanup stuff */
1078
1079    /* Send a SIGHUP to everything in the process group, but not us.
1080     * Originally included to support Zephyr over rlogin/telnet
1081     * connections, but it has some general use, since any personal
1082     * daemon can setpgrp(0, getpgrp(getppid())) before forking to be
1083     * sure of receiving a HUP when the user logs out.
1084     *
1085     * Note that we are assuming that the shell will set its process
1086     * group to its process id. Our csh does, anyway, and there is no
1087     * other way to reliably find out what that shell's pgrp is.
1088     */
1089    signal(SIGHUP, SIG_IGN);
1090    if(-1 == killpg(child, SIGHUP))
1091      {
1092        /* EINVAL shouldn't happen (SIGHUP is a constant),
1093         * ESRCH could, but we ignore it
1094         * EPERM means something actually is wrong, so log it
1095         * (in this case, the signal didn't get delivered but
1096         * something might have wanted it...)
1097         */
1098        if(errno == EPERM)
1099          syslog(LOG_DEBUG,
1100                 "EPERM trying to kill login process group: child_pgrp %d",
1101                 child);
1102      }
1103
1104    /* Run dest_tkt to destroy tickets */
1105    (void) dest_tkt();          /* If this fails, we lose quietly */
1106
1107   
1108    /* Detach home directory if previously attached */
1109    if (attachedflag)
1110            (void) detach_homedir();
1111
1112    if (tmppwflag)
1113            if (remove_pwent(pwd))
1114                    puts("Couldn't remove password entry");
1115
1116    /* Leave */
1117    exit(0);
1118}
1119
1120
1121tty_gid(default_gid)
1122int default_gid;
1123{
1124        struct group *getgrnam(), *gr;
1125        int gid = default_gid;
1126       
1127        gr = getgrnam(TTYGRPNAME);
1128        if (gr != (struct group *) 0)
1129                gid = gr->gr_gid;
1130   
1131        endgrent();
1132   
1133        return (gid);
1134}
1135
1136char *
1137getlongpass(prompt)
1138char *prompt;
1139{
1140        struct sgttyb ttyb;
1141        int flags;
1142        register char *p;
1143        register c;
1144        FILE *fi;
1145        static char pbuf[MAXPWSIZE+1];
1146        int (*signal())();
1147        int (*sig)();
1148
1149        if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL)
1150                fi = stdin;
1151        else
1152                setbuf(fi, (char *)NULL);
1153        sig = signal(SIGINT, SIG_IGN);
1154        ioctl(fileno(fi), TIOCGETP, &ttyb);
1155        flags = ttyb.sg_flags;
1156        ttyb.sg_flags &= ~ECHO;
1157        ioctl(fileno(fi), TIOCSETP, &ttyb);
1158        fprintf(stderr, "%s", prompt); fflush(stderr);
1159        for (p=pbuf; (c = getc(fi))!='\n' && c!=EOF;) {
1160                if (p < &pbuf[MAXPWSIZE])
1161                        *p++ = c;
1162        }
1163        *p = '\0';
1164        fprintf(stderr, "\n"); fflush(stderr);
1165        ttyb.sg_flags = flags;
1166        ioctl(fileno(fi), TIOCSETP, &ttyb);
1167        signal(SIGINT, sig);
1168        if (fi != stdin)
1169                fclose(fi);
1170        pbuf[MAXPWSIZE]='\0';
1171        return(pbuf);
1172}
1173
1174/* Attach the user's home directory if "attachable" is set.
1175 */
1176attach_homedir()
1177{
1178        union wait status;
1179        int attachpid;
1180       
1181        if (!attachable)
1182                return (1);
1183        chdir("/");     /* XXX This is a temproary hack to fix the
1184                         * fact that home directories sometimes do
1185                         * not get attached if the user types his
1186                         * password wrong the first time. Some how
1187                         * working direcotyr becomes the users home
1188                         * directory BEFORE we try to attach. and it
1189                         * of course fails.
1190                         */
1191
1192        if (!(attachpid = fork())) {
1193                setuid(pwd->pw_uid);
1194                freopen("/dev/null","w",stdout);
1195                execl("/bin/athena/attach","attach","-q", lusername,0);
1196                exit (-1);
1197        }
1198        while (wait(&status) != attachpid)
1199                ;
1200        if (status.w_retcode == ATTACH_OK ||
1201            status.w_retcode == ATTACH_ERR_ATTACHED) {
1202                chown(pwd->pw_dir, pwd->pw_uid, pwd->pw_gid);
1203                chdir(pwd->pw_dir);
1204                return (0);
1205        }
1206        return (1);
1207}
1208
1209/* Detach the user's home directory */
1210detach_homedir()
1211{
1212        union wait status;
1213        int pid;
1214
1215#ifdef notdef
1216        int i;
1217        char *level;
1218        for (i=0;i<3;i++) {
1219#endif
1220                if (!(pid = fork())) {
1221                        setuid(pwd->pw_uid);
1222                        freopen("/dev/null","w",stdout);
1223                        freopen("/dev/null","w",stderr);
1224                        execl("/bin/athena/detach","detach",lusername,0);
1225                        exit (-1);
1226                }
1227                while (wait(&status) != pid)
1228                        ;
1229#ifdef notdef
1230                if (status.w_retcode == DETACH_OK)
1231                        return;
1232                level = "1";
1233                if (i == 1)
1234                        level = "9";
1235                if (i == 2)
1236                        level = "9";
1237                printf("Killing processes using %s with signal %s\n",
1238                       pwd->pw_dir,level);
1239                if (!(pid = fork())) {
1240                        freopen("/dev/null","w",stdout);
1241                        freopen("/dev/null","w",stderr);
1242                        execl("/etc/athena/ofiles","ofiles","-k",
1243                              level,pwd->pw_dir,0);
1244                        exit (-1);
1245                }
1246                while (wait(0) != pid)
1247                        ;
1248        }
1249#endif notdef
1250        return;
1251#ifdef notdef
1252        printf("Couldn't detach home directory!\n");
1253#endif notdef
1254}
1255
1256isremotedir(dname)
1257char *dname;
1258{
1259        int fh, c;
1260
1261        /*
1262         * The following lines rely on the
1263         * behavior of Sun's NFS (present in 3.0 and 3.2)
1264         * which causes a read on an NFS directory (actually any non-reg file)
1265         * to return -1 with errno set to EISDIR.
1266         *
1267         * This is a fast, cheap way to discover whether a user's
1268         * homedir is a remote NFS filesystem.  Naturally, if the NFS semantics
1269         * change, this must also change.
1270         *
1271         * We return 1 if it is any remote filesystem so that the
1272         * attach_homedir command will run again (sending an "nfsid map"
1273         * command and cleaning up attachtab, if it happens to be out of sync.)
1274         *
1275         * Might want to handle RVD filesystems at some point...
1276         */
1277
1278        fh = open(dname, O_RDONLY);
1279        if (fh < 0)
1280                return(0);
1281        if (read(fh, &c, 1) < 0 && errno == EISDIR) {
1282                close(fh);
1283                return(1);
1284        }
1285        close(fh);
1286        return(0);
1287}
1288
1289goodhomedir()
1290{
1291        DIR *dp;
1292       
1293        if (access(pwd->pw_dir,F_OK))
1294                return (0);
1295
1296        if (isremotedir(pwd->pw_dir))
1297                return(0);
1298
1299        dp = opendir(pwd->pw_dir);
1300        if (!dp)
1301                return (0);
1302        readdir(dp);
1303        readdir(dp);
1304        if (readdir(dp)) {
1305                closedir(dp);
1306                return (1);
1307        }
1308        closedir(dp);
1309        return (0);
1310}
1311       
1312/*
1313 * Make a home directory, copying over files from PROTOTYPE_DIR.
1314 * Ownership and group will be set to the user's uid and gid.  Default
1315 * permission is TEMP_DIR_PERM.  Returns 0 on success, -1 on failure.
1316 */
1317make_homedir()
1318{
1319    DIR *proto;
1320    struct direct *dp;
1321    char tempname[MAXPATHLEN+1];
1322    char buf[MAXBSIZE];
1323    struct stat statbuf;
1324    int fold, fnew;
1325    int n;
1326    extern int errno;
1327
1328    if (inhibitflag)
1329            return (-1);
1330   
1331    strcpy(pwd->pw_dir,"/tmp/");
1332    strcat(pwd->pw_dir,lusername);
1333    setenv("TMPHOME", "", 1);
1334    /* Make the home dir and chdir to it */
1335    unlink(pwd->pw_dir);
1336    if(mkdir(pwd->pw_dir) < 0) {
1337            if (errno == EEXIST)
1338                    return (0);
1339            else
1340                    return(-1);
1341    }
1342    chown(pwd->pw_dir, pwd->pw_uid, pwd->pw_gid);
1343    chmod(pwd->pw_dir, TEMP_DIR_PERM);
1344    chdir(pwd->pw_dir);
1345   
1346    /* Copy over the proto files */
1347    if((proto = opendir(PROTOTYPE_DIR)) == NULL) {
1348        puts("Can't open prototype directory!");
1349        unlink(pwd->pw_dir);
1350        return(-1);
1351    }
1352
1353    for(dp = readdir(proto); dp != NULL; dp = readdir(proto)) {
1354        /* Don't try to copy . or .. */
1355        if(!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue;
1356
1357        /* Copy the file */
1358        SCPYN(tempname, PROTOTYPE_DIR);
1359        strcat(tempname, "/");
1360        strncat(tempname, dp->d_name, sizeof(tempname) - strlen(tempname) - 1);
1361        if(stat(tempname, &statbuf) < 0) {
1362            perror(tempname);
1363            continue;
1364        }
1365        /* Only copy plain files */
1366        if(!(statbuf.st_mode & S_IFREG)) continue;
1367
1368        /* Try to open the source file */
1369        if((fold = open(tempname, O_RDONLY, 0)) < 0) {
1370            perror(tempname);
1371            continue;
1372        }
1373
1374        /* Open the destination file */
1375        if((fnew = open(dp->d_name, O_WRONLY|O_CREAT|O_EXCL,
1376                        statbuf.st_mode)) < 0) {
1377                            perror(dp->d_name);
1378                            continue;
1379                        }
1380
1381        /* Change the ownership */
1382        fchown(fnew, pwd->pw_uid, pwd->pw_gid);
1383
1384        /* Do the copy */
1385        for (;;) {
1386            n = read(fold, buf, sizeof buf);
1387            if(n==0) break;
1388            if(n<0) {
1389                perror(tempname);
1390                break;
1391            }
1392            if (write(fnew, buf, n) != n) {
1393                perror(dp->d_name);
1394                break;
1395            }
1396        }
1397        close(fnew);
1398        close(fold);
1399    }
1400    return(0);
1401}
1402
1403insert_pwent(pwd)
1404struct passwd *pwd;
1405{
1406    FILE *pfile;
1407    int cnt;
1408
1409    while (getpwuid(pwd->pw_uid))
1410      (pwd->pw_uid)++;
1411
1412    cnt = 10;
1413    while (!access("/etc/ptmp",0) && --cnt)
1414            sleep(1);
1415    unlink("/etc/ptmp");
1416   
1417    if((pfile=fopen("/etc/passwd", "a")) != NULL) {
1418        fprintf(pfile, "%s:%s:%d:%d:%s:%s:%s\n",
1419                pwd->pw_name,
1420                pwd->pw_passwd,
1421                pwd->pw_uid,
1422                pwd->pw_gid,
1423                pwd->pw_gecos,
1424                pwd->pw_dir,
1425                pwd->pw_shell);
1426        fclose(pfile);
1427    }
1428}
1429
1430remove_pwent(pwd)
1431struct passwd *pwd;
1432{
1433    FILE *newfile;
1434    struct passwd *copypw;
1435    int cnt;
1436
1437    cnt = 10;
1438    while (!access("/etc/ptmp",0) && --cnt)
1439            sleep(1);
1440    unlink("/etc/ptmp");
1441   
1442    if ((newfile = fopen("/etc/ptmp", "w")) != NULL) {
1443        setpwent();
1444        while ((copypw = getpwent()) != 0)
1445            if (copypw->pw_uid != pwd->pw_uid)
1446                    fprintf(newfile, "%s:%s:%d:%d:%s:%s:%s\n",
1447                            copypw->pw_name,
1448                            copypw->pw_passwd,
1449                            copypw->pw_uid,
1450                            copypw->pw_gid,
1451                            copypw->pw_gecos,
1452                            copypw->pw_dir,
1453                            copypw->pw_shell);
1454        endpwent();
1455        fclose(newfile);
1456        rename("/etc/ptmp", "/etc/passwd");
1457        return(0);
1458    } else return(1);
1459}
1460
1461get_groups()
1462{
1463        FILE *grin,*grout;
1464        char **cp,grbuf[4096],*ptr,*pwptr,*numptr,*lstptr,**grname,**grnum;
1465        char grlst[4096],grtmp[4096],*tmpptr;
1466        int ngroups,i,cnt;
1467       
1468        if (inhibitflag)
1469                return;
1470       
1471        cp = (char **)hes_resolve(pwd->pw_name,"grplist");
1472        if (!cp || !*cp)
1473                return;
1474
1475        cnt = 10;
1476        while (!access("/etc/gtmp",0) && --cnt)
1477                sleep(1);
1478        unlink("/etc/gtmp");
1479       
1480        grin = fopen("/etc/group","r");
1481        if (!grin) {
1482                fprintf(stderr,"Can't open /etc/group!\n");
1483                return;
1484        }
1485        grout = fopen("/etc/gtmp","w");
1486        if (!grout) {
1487                fprintf(stderr,"Can't open /etc/gtmp!\n");
1488                fclose(grin);
1489                return;
1490        }
1491
1492        ngroups = 0;
1493        for (ptr=cp[0];*ptr;ptr++)
1494                if (*ptr == ':')
1495                        ngroups++;
1496
1497        ngroups = (ngroups+1)/2;
1498
1499        if (ngroups > NGROUPS-1)
1500                ngroups = NGROUPS-1;
1501
1502        grname = (char **)malloc(ngroups * sizeof(char *));
1503        if (!grname) {
1504                fprintf(stderr,"Out of memory!\n");
1505                fclose(grin);
1506                fclose(grout);
1507                unlink("/etc/gtmp");
1508                return;
1509        }
1510
1511        grnum = (char **)malloc(ngroups * sizeof(char *));
1512        if (!grnum) {
1513                fprintf(stderr,"Out of memory!\n");
1514                fclose(grin);
1515                fclose(grout);
1516                unlink("/etc/gtmp");
1517                return;
1518        }
1519
1520        for (i=0,ptr=cp[0];i<ngroups;i++) {
1521                grname[i] = ptr;
1522                ptr = (char *)index(ptr,':');
1523                if (!ptr) {
1524                        fprintf(stderr,"Internal failure while initializing groups\n");
1525                        fclose(grin);
1526                        fclose(grout);
1527                        free(grname);
1528                        free(grnum);
1529                        unlink("/etc/gtmp");
1530                        return;
1531                }
1532                *ptr++ = '\0';
1533                grnum[i] = ptr;
1534                ptr = (char *)index(ptr,':');
1535                if (!ptr)
1536                        ptr = grnum[i]+strlen(grnum[i]);
1537                *ptr++ = '\0';
1538        }
1539
1540        while (fgets(grbuf,sizeof grbuf,grin) != 0) {
1541                if (!*grbuf)
1542                        break;
1543                grbuf[strlen(grbuf)-1] = '\0';
1544                pwptr = (char *)index(grbuf,':');
1545                if (!pwptr)
1546                        continue;
1547                *pwptr++ = '\0';
1548                numptr = (char *)index(pwptr,':');
1549                if (!numptr)
1550                        continue;
1551                *numptr++ = '\0';
1552                lstptr = (char *)index(numptr,':');
1553                if (!lstptr)
1554                        continue;
1555                *lstptr++ = '\0';
1556                strcpy(grlst,lstptr);
1557                for (i=0;i<ngroups;i++) {
1558                        if (strcmp(grname[i],grbuf))
1559                                continue;
1560                        lstptr = grlst;
1561                        while (lstptr) {
1562                                strcpy(grtmp,lstptr);
1563                                tmpptr = (char *)index(grtmp,',');
1564                                if (tmpptr)
1565                                        *tmpptr = '\0';
1566                                if (!strcmp(grtmp,pwd->pw_name)) {
1567                                        grname[i] = "*";
1568                                        break;
1569                                }
1570                                lstptr = (char *)index(lstptr,',');
1571                                if (lstptr)
1572                                        lstptr++;
1573                        }
1574                        if (lstptr)
1575                                break;
1576                        strcat(grlst,",");
1577                        strcat(grlst,pwd->pw_name);
1578                        grname[i] = "*";
1579                        break;
1580                }
1581                fprintf(grout,"%s:%s:%s:%s\n",grbuf,pwptr,numptr,grlst);
1582        }
1583
1584        for (i=0;i<ngroups;i++)
1585                if (strcmp(grname[i],"*"))
1586                        fprintf(grout,"%s:%s:%s:%s\n",grname[i],"*",
1587                                grnum[i],pwd->pw_name);
1588
1589        fclose(grin);
1590        fclose(grout);
1591        rename("/etc/gtmp","/etc/group");
1592        unlink("/etc/gtmp");
1593        free(grname);
1594        free(grnum);
1595}
1596
1597init_wgfile()
1598{
1599        char *wgfile;
1600
1601        wgfile = "/tmp/wg.XXXXXX";
1602
1603        mktemp(wgfile);
1604
1605        setenv("WGFILE",wgfile,1);
1606}
1607
1608/*
1609 * Verify the Kerberos ticket-granting ticket just retrieved for the
1610 * user.  If the Kerberos server doesn't respond, assume the user is
1611 * trying to fake us out (since we DID just get a TGT from what is
1612 * supposedly our KDC).  If the rcmd.<host> service is unknown (i.e.,
1613 * the local /etc/srvtab doesn't have it), let her in.
1614 *
1615 * Returns 1 for confirmation, -1 for failure, 0 for uncertainty.
1616 */
1617int verify_krb_tgt (realm)
1618    char *realm;
1619{
1620    char hostname[MAXHOSTNAMELEN], phost[BUFSIZ];
1621    struct hostent *hp;
1622    KTEXT_ST ticket;
1623    AUTH_DAT authdata;
1624    unsigned long addr;
1625    static /*const*/ char rcmd[] = "rcmd";
1626    char key[8];
1627    int krbval, retval, have_keys;
1628
1629    if (gethostname(hostname, sizeof(hostname)) == -1) {
1630        perror ("cannot retrieve local hostname");
1631        return -1;
1632    }
1633    strncpy (phost, get_phost (hostname), sizeof (phost));
1634    phost[sizeof(phost)-1] = 0;
1635    hp = gethostbyname (hostname);
1636    if (!hp) {
1637        perror ("cannot retrieve local host address");
1638        return -1;
1639    }
1640    bcopy ((char *)hp->h_addr, (char *) &addr, sizeof (addr));
1641    /* Do we have rcmd.<host> keys? */
1642    have_keys = read_service_key (rcmd, phost, realm, 0, "/etc/srvtab", key)
1643        ? 0 : 1;
1644    krbval = krb_mk_req (&ticket, rcmd, phost, realm, 0);
1645    if (krbval == KDC_PR_UNKNOWN) {
1646        /*
1647         * Our rcmd.<host> principal isn't known -- just assume valid
1648         * for now?  This is one case that the user _could_ fake out.
1649         */
1650        if (have_keys)
1651            return -1;
1652        else
1653            return 0;
1654    }
1655    else if (krbval != KSUCCESS) {
1656        printf ("Unable to verify Kerberos TGT: %s\n", krb_err_txt[krbval]);
1657        syslog (LOG_NOTICE|LOG_AUTH, "Kerberos TGT bad: %s",
1658                krb_err_txt[krbval]);
1659        return -1;
1660    }
1661    /* got ticket, try to use it */
1662    krbval = krb_rd_req (&ticket, rcmd, phost, addr, &authdata, "");
1663    if (krbval != KSUCCESS) {
1664        if (krbval == RD_AP_UNDEC && !have_keys)
1665            retval = 0;
1666        else {
1667            retval = -1;
1668            printf ("Unable to verify `rcmd' ticket: %s\n",
1669                    krb_err_txt[krbval]);
1670        }
1671        syslog (LOG_NOTICE|LOG_AUTH, "can't verify rcmd ticket: %s;%s\n",
1672                krb_err_txt[krbval],
1673                retval
1674                ? "srvtab found, assuming failure"
1675                : "no srvtab found, assuming success");
1676        goto EGRESS;
1677    }
1678    /*
1679     * The rcmd.<host> ticket has been received _and_ verified.
1680     */
1681    retval = 1;
1682    /* do cleanup and return */
1683EGRESS:
1684    bzero (&ticket, sizeof (ticket));
1685    bzero (&authdata, sizeof (authdata));
1686    return retval;
1687}
Note: See TracBrowser for help on using the repository browser.