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

Revision 2149, 39.5 KB checked in by probe, 35 years ago (diff)
Kerberos conversion
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.27 1989-10-18 09:40:47 probe 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.27 1989-10-18 09:40:47 probe 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
63#define TTYGRPNAME      "tty"           /* name of group to own ttys */
64#define TTYGID(gid)     tty_gid(gid)    /* gid that owns all ttys */
65
66#define SCMPN(a, b)     strncmp(a, b, sizeof(a))
67#define SCPYN(a, b)     strncpy(a, b, sizeof(a))
68
69#define NMAX    sizeof(utmp.ut_name)
70#define HMAX    sizeof(utmp.ut_host)
71
72#define FALSE   0
73#define TRUE    -1
74
75#ifdef VFS
76#define QUOTAWARN       "/usr/ucb/quota"        /* warn user about quotas */
77#endif VFS
78
79#ifndef KRB_REALM
80#define KRB_REALM       "ATHENA.MIT.EDU"
81#endif
82
83#define KRB_ENVIRON     "KRBTKFILE" /* Ticket file environment variable */
84#define KRB_TK_DIR      "/tmp/tkt_" /* Where to put the ticket */
85#define KRBTKLIFETIME   96      /* 8 hours */
86
87#define PROTOTYPE_DIR   "/usr/prototype_user" /* Source for temp files */
88#define TEMP_DIR_PERM   0755    /* Permission on temporary directories */
89
90#define MAXPWSIZE       128     /* Biggest key getlongpass will return */
91
92#define START_UID       200     /* start assigning arbitrary UID's here */
93#define MIT_GID         101     /* standard primary group "mit" */
94
95extern char *krb_err_txt[];     /* From libkrb */
96
97char    nolog[] =       "/etc/nologin";
98char    qlog[]  =       ".hushlogin";
99char    maildir[30] =   "/usr/spool/mail/";
100char    lastlog[] =     "/usr/adm/lastlog";
101char    inhibit[] =     "/etc/nocreate";
102char    noattach[] =    "/etc/noattach";
103char    go_register[] = "/usr/etc/go_register";
104char    get_motd[] =    "/bin/athena/get_message";
105
106/* uid, gid, etc. used to be -1; guess what setreuid does with that --asp */
107struct  passwd nouser = {"", "nope", -2, -2, -2, "", "", "", "" };
108
109struct  passwd newuser = {"\0\0\0\0\0\0\0\0", "*", START_UID, MIT_GID, 0,
110                          NULL, NULL, "/mit/\0\0\0\0\0\0\0\0", NULL };
111
112struct  sgttyb ttyb;
113struct  utmp utmp;
114char    minusnam[16] = "-";
115char    *envinit[] = { 0 };             /* now set by setenv calls */
116/*
117 * This bounds the time given to login.  We initialize it here
118 * so it can be patched on machines where it's too small.
119 */
120int     timeout = 60;
121
122char    term[64];
123
124struct  passwd *pwd;
125struct  passwd *hes_getpwnam();
126char    *strcat(), *rindex(), *index(), *malloc(), *realloc();
127int     timedout();
128char    *ttyname();
129char    *crypt();
130char    *getlongpass();
131char    *stypeof();
132extern  char **environ;
133extern  int errno;
134
135struct  tchars tc = {
136        CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK
137};
138struct  ltchars ltc = {
139        CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT
140};
141
142struct winsize win = { 0, 0, 0, 0 };
143
144int     rflag=0;
145int     kflag=0;
146int     Kflag=0;
147int     usererr = -1;
148int     krbflag = FALSE;        /* True if Kerberos-authenticated login */
149int     tmppwflag = FALSE;      /* True if passwd entry is temporary */
150int     tmpdirflag = FALSE;     /* True if home directory is temporary */
151int     inhibitflag = FALSE;    /* inhibit account creation on the fly */
152int     attachable = FALSE;     /* True if /etc/noattach doesn't exist */
153int     attachedflag = FALSE;   /* True if homedir attached */
154int     errorprtflag = FALSE;   /* True if login error already printed */
155char    rusername[NMAX+1], lusername[NMAX+1];
156char    rpassword[NMAX+1];
157char    name[NMAX+1];
158char    *rhost;
159
160AUTH_DAT *kdata = (AUTH_DAT *)NULL;
161
162union wait waitstat;
163
164main(argc, argv)
165    char *argv[];
166{
167    register char *namep;
168    int pflag = 0, hflag = 0, t, f, c;
169    int invalid, quietlog, forkval;
170    FILE *nlfd;
171    char *ttyn, *tty, saltc[2];
172    long salt;
173    int ldisc = 0, zero = 0, found = 0, i;
174    char **envnew;
175
176    signal(SIGALRM, timedout);
177    alarm(timeout);
178    signal(SIGQUIT, SIG_IGN);
179    signal(SIGINT, SIG_IGN);
180    setpriority(PRIO_PROCESS, 0, 0);
181#ifndef VFS
182    quota(Q_SETUID, 0, 0, 0);
183#endif !VFS
184    /*
185     * -p is used by getty to tell login not to destroy the environment
186     * -r is used by rlogind to cause the autologin protocol;
187     * -k is used by klogind to cause the Kerberos autologin protocol;
188     * -K is used by klogind to cause the Kerberos autologin protocol with
189     *    restricted access.;
190     * -h is used by other servers to pass the name of the
191     * remote host to login so that it may be placed in utmp and wtmp
192     */
193    while (argc > 1) {
194        if (strcmp(argv[1], "-r") == 0) {
195            if (rflag || kflag || Kflag || hflag) {
196                printf("Only one of -r -k -K or -h allowed\n");
197                exit(1);
198            }
199            if (argv[2] == 0)
200              exit(1);
201            rflag = 1;
202            usererr = doremotelogin(argv[2]);
203            SCPYN(utmp.ut_host, argv[2]);
204            argc -= 2;
205            argv += 2;
206            continue;
207        }
208                if (strcmp(argv[1], "-k") == 0) {
209                        if (rflag || kflag || Kflag || hflag) {
210                                printf("Only one of -r -k -K or -h allowed\n");
211                                exit(1);
212                        }
213                        kflag = 1;
214                        usererr = doKerberosLogin(argv[2]);
215                        SCPYN(utmp.ut_host, argv[2]);
216                        argc -= 2;
217                        argv += 2;
218                        continue;
219                }
220                if (strcmp(argv[1], "-K") == 0) {
221                        if (rflag || kflag || Kflag || hflag) {
222                                printf("Only one of -r -k -K or -h allowed\n");
223                                exit(1);
224                        }
225                        Kflag = 1;
226                        usererr = doKerberosLogin(argv[2]);
227                        SCPYN(utmp.ut_host, argv[2]);
228                        argc -= 2;
229                        argv += 2;
230                        continue;
231                }
232        if (strcmp(argv[1], "-h") == 0 && getuid() == 0) {
233            if (rflag || kflag || Kflag || hflag) {
234                printf("Only one of -r -k -K or -h allowed\n");
235                exit(1);
236            }
237            hflag = 1;
238            SCPYN(utmp.ut_host, argv[2]);
239            argc -= 2;
240            argv += 2;
241            continue;
242        }
243        if (strcmp(argv[1], "-p") == 0) {
244            argc--;
245            argv++;
246            pflag = 1;
247            continue;
248        }
249        break;
250    }
251    ioctl(0, TIOCLSET, &zero);
252    ioctl(0, TIOCNXCL, 0);
253    ioctl(0, FIONBIO, &zero);
254    ioctl(0, FIOASYNC, &zero);
255    ioctl(0, TIOCGETP, &ttyb);
256    /*
257     * If talking to an rlogin process,
258     * propagate the terminal type and
259     * baud rate across the network.
260     */
261    if (rflag || kflag || Kflag)
262        doremoteterm(term, &ttyb);
263    ttyb.sg_erase = CERASE;
264    ttyb.sg_kill = CKILL;
265    ioctl(0, TIOCSLTC, &ltc);
266    ioctl(0, TIOCSETC, &tc);
267    ioctl(0, TIOCSETP, &ttyb);
268    for (t = getdtablesize(); t > 2; t--)
269        close(t);
270    ttyn = ttyname(0);
271    if (ttyn == (char *)0 || *ttyn == '\0')
272        ttyn = "/dev/tty??";
273    tty = rindex(ttyn, '/');
274    if (tty == NULL)
275        tty = ttyn;
276    else
277        tty++;
278    openlog("login", LOG_ODELAY, LOG_AUTH);
279
280    /* destroy environment unless user has asked to preserve it */
281    /* (Moved before passwd stuff by asp) */
282    if (!pflag)
283        environ = envinit;
284
285    /* set up environment, this time without destruction */
286    /* copy the environment before setenving */
287    i = 0;
288    while (environ[i] != NULL)
289        i++;
290    envnew = (char **) malloc(sizeof (char *) * (i + 1));
291    for (; i >= 0; i--)
292        envnew[i] = environ[i];
293    environ = envnew;
294
295    t = 0;
296    invalid = FALSE;
297    inhibitflag = !access(inhibit,F_OK);
298    attachable = access(noattach, F_OK);
299    do {
300            errorprtflag = 0;
301            ldisc = 0;
302        found = 0;
303        ioctl(0, TIOCSETD, &ldisc);
304        SCPYN(utmp.ut_name, "");
305        /*
306         * Name specified, take it.
307         */
308        if (argc > 1) {
309            SCPYN(utmp.ut_name, argv[1]);
310            argc = 0;
311        }
312        /*
313         * If remote login take given name,
314         * otherwise prompt user for something.
315         */
316        if ((rflag || kflag || Kflag) && !invalid) {
317            SCPYN(utmp.ut_name, lusername);
318            if((pwd = getpwnam(lusername)) == NULL) {
319                    pwd = &nouser;
320                    found = 0;
321            } else found = 1;
322        } else {
323                found = getloginname(&utmp);
324                if (utmp.ut_name[0] == '-') {
325                        puts("login names may not start with '-'.");
326                        invalid = TRUE;
327                        continue;
328                }
329        }
330 
331        invalid = FALSE;
332        if (!strcmp(pwd->pw_shell, "/bin/csh")) {
333            ldisc = NTTYDISC;
334            ioctl(0, TIOCSETD, &ldisc);
335        }
336        /*
337         * If no remote login authentication and
338         * a password exists for this user, prompt
339         * for one and verify it.
340         */
341        if (usererr == -1 && *pwd->pw_passwd != '\0') {
342                /* we need to be careful to overwrite the password once it has
343                 * been checked, so that it can't be recovered from a core image.
344                 */
345
346            char *pp, pp2[MAXPWSIZE+1];
347            int krbval;
348            char tkfile[32];
349            char realm[REALM_SZ];
350           
351            /* Set up the ticket file environment variable */
352            SCPYN(tkfile, KRB_TK_DIR);
353            strncat(tkfile, rindex(ttyn, '/')+1,
354                    sizeof(tkfile) - strlen(tkfile));
355            (void) unlink (tkfile);
356            setenv(KRB_ENVIRON, tkfile);
357           
358            setpriority(PRIO_PROCESS, 0, -4);
359            pp = getlongpass("Password:");
360           
361            if (!found) /* check if we can create an entry */
362                    if (inhibitflag)
363                        invalid = TRUE;
364                    else /* we are allowed to create an entry */
365                        pwd = &newuser;
366
367            /* Modifications for Kerberos authentication -- asp */
368            SCPYN(pp2, pp);
369            pp[8]='\0';
370            if (found)
371                    namep = crypt(pp, pwd->pw_passwd);
372            else {
373                    salt = 9 * getpid();
374                    saltc[0] = salt & 077;
375                    saltc[1] = (salt>>6) & 077;
376                    for (i=0;i<2;i++) {
377                            c = saltc[i] + '.';
378                            if (c > '9')
379                                    c += 7;
380                            if (c > 'Z')
381                                    c += 6;
382                            saltc[i] = c;
383                    }
384                    pwd->pw_passwd = namep = crypt(pp, saltc);
385            }
386                           
387            bzero(pp, 8);               /* No, Senator, I don't recall
388                                           anything of that nature ... */
389            setpriority(PRIO_PROCESS, 0, 0);
390
391            if (!invalid && (pwd->pw_uid != 0)) {
392                    /* if not root, get Kerberos tickets */
393                if(krb_get_lrealm(realm, 1) != KSUCCESS) {
394                    SCPYN(realm, KRB_REALM);
395                }
396                strncpy(lusername, utmp.ut_name, NMAX);
397                lusername[NMAX] = '\0';
398                krbval = krb_get_pw_in_tkt(lusername, "", realm,
399                                    "krbtgt", realm, KRBTKLIFETIME, pp2);
400                bzero(pp2, MAXPWSIZE+1); /* Yes, he's senile.  He doesn't know
401                                            what his administration is doing */
402                switch (krbval) {
403                case INTK_OK:
404                        alarm(0);       /* Authentic, so don't time out. */
405                        if (verify_krb_tgt(realm) < 0) {
406                            /* Oops.  He tried to fool us.  Tsk, tsk. */
407                            invalid = TRUE;
408                            goto leavethis;
409                        }
410                        invalid = FALSE;
411                        krbflag = TRUE;
412                        if (!found) {
413                                /* create a password entry: first ask the nameserver */
414                                /* to get us finger and shell info */
415                                struct passwd *nspwd;
416                                if ((nspwd = hes_getpwnam(lusername)) != NULL) {
417                                        pwd->pw_uid = nspwd->pw_uid;
418                                        pwd->pw_gid = nspwd->pw_gid;
419                                        pwd->pw_gecos = nspwd->pw_gecos;
420                                        pwd->pw_shell = nspwd->pw_shell;
421                                } else {
422                                        pwd->pw_uid = 200;
423                                        pwd->pw_gid = MIT_GID;
424                                        pwd->pw_gecos = "";
425                                        pwd->pw_shell = "/bin/csh";
426                                }
427                                strncpy(pwd->pw_name, utmp.ut_name, NMAX);
428                                strncat(pwd->pw_dir, utmp.ut_name, NMAX);
429                                (void) insert_pwent(pwd);
430                                tmppwflag = TRUE;
431                        }
432                        chown(getenv(KRB_ENVIRON), pwd->pw_uid, pwd->pw_gid);
433                        /* If we already have a homedir, use it.
434                         * Otherwise, try to attach.  If that fails,
435                         * try to create.
436                         */
437                        tmpdirflag = FALSE;
438                        if (!goodhomedir()) {
439                                if (attach_homedir()) {
440                                        puts("\nWarning: Unable to attach home directory.");
441                                        if (make_homedir() >= 0) {
442                                                puts("\nNOTE -- Your home directory is temporary.");
443                                                puts("It will be deleted when this workstation deactivates.\n");
444                                                tmpdirflag = TRUE;
445                                        }
446                                        else if (chdir("/") < 0) {
447                                                printf("No directory '/'!\n");
448                                                invalid = TRUE;
449                                        } else {
450                                                puts("Can't find or build home directory! Logging in with home=/");
451                                                pwd->pw_dir = "/";
452                                                tmpdirflag = FALSE;
453                                        }
454                                }
455                                else {
456                                        attachedflag = TRUE;
457                                }
458                        }
459                        else
460                                puts("\nWarning: Using local home directory.");
461                        break;
462                   
463                  case KDC_NULL_KEY:
464                        invalid = TRUE;
465                        /* tell the luser to go register with kerberos */
466
467                        if (found)
468                                goto good_anyway;
469                       
470                        alarm(0);       /* If we are changing password,
471                                           he won't be logging in in this
472                                           process anyway, so we can reset */
473
474                        (void) insert_pwent(pwd);
475                       
476                        if (forkval = fork()) { /* parent */
477                            if (forkval < 0) {
478                                perror("forking for registration program");
479                                sleep(3);
480                                exit(1);
481                            }
482                            while(wait(0) != forkval);
483                            remove_pwent(pwd);
484                            exit(0);
485                        }
486                        /* run the passwd program as the user */
487                        setuid(pwd->pw_uid);
488                       
489                        execl(go_register, go_register, lusername, 0);
490                        perror("executing registration program");
491                        sleep(2);
492                        exit(1);
493                        /* These errors should be printed and are fatal */
494                case KDC_PR_UNKNOWN:
495                case KDC_PR_N_UNIQUE:
496                        invalid = TRUE;
497                        if (found)
498                                goto good_anyway;
499                case INTK_BADPW:
500                        invalid = TRUE;
501                        errorprtflag = TRUE;
502                        fprintf(stderr, "%s\n",
503                                krb_err_txt[krbval]);
504                        goto leavethis;
505                    /* These should be printed but are not fatal */
506                case INTK_W_NOTALL:
507                    invalid = FALSE;
508                    krbflag = TRUE;
509                    fprintf(stderr, "Kerberos error: %s\n",
510                            krb_err_txt[krbval]);
511                        goto leavethis;
512                  default:
513                    fprintf(stderr, "Kerberos error: %s\n",
514                            krb_err_txt[krbval]);
515                    invalid = TRUE;
516                        errorprtflag = TRUE;
517                        goto leavethis;
518                }
519        } else { /* root logging in or inhibited; check password */
520                bzero(pp2, MAXPWSIZE+1); /* Yes, he's senile.  He doesn't know
521                                          * what his administration is doing */
522                invalid = TRUE;
523        }
524            /* if password is good, user is good */
525    good_anyway:
526            invalid = invalid && strcmp(namep, pwd->pw_passwd);
527    }
528
529leavethis:
530        /*
531         * If our uid < 0, we must be a bogus user.
532         */
533        if(pwd->pw_uid < 0) invalid = TRUE;
534
535        /*
536         * If user not super-user, check for logins disabled.
537         */
538        if (pwd->pw_uid != 0 && (nlfd = fopen(nolog, "r")) != 0) {
539            while ((c = getc(nlfd)) != EOF)
540                putchar(c);
541            fflush(stdout);
542            sleep(5);
543            if (krbflag)
544                    (void) dest_tkt();
545            exit(0);
546        }
547        /*
548         * If valid so far and root is logging in,
549         * see if root logins on this terminal are permitted.
550         */
551        if (!invalid && pwd->pw_uid == 0 && !rootterm(tty)) {
552            if (utmp.ut_host[0])
553                syslog(LOG_CRIT,
554                       "ROOT LOGIN REFUSED ON %s FROM %.*s",
555                       tty, HMAX, utmp.ut_host);
556            else
557                syslog(LOG_CRIT,
558                       "ROOT LOGIN REFUSED ON %s", tty);
559            invalid = TRUE;
560        }
561        if (invalid) {
562                if (!errorprtflag)
563                        printf("Login incorrect\n");
564                if (++t >= 5) {
565                if (utmp.ut_host[0])
566                    syslog(LOG_CRIT,
567                           "REPEATED LOGIN FAILURES ON %s FROM %.*s, %.*s",
568                           tty, HMAX, utmp.ut_host,
569                           NMAX, utmp.ut_name);
570                else
571                    syslog(LOG_CRIT,
572                           "REPEATED LOGIN FAILURES ON %s, %.*s",
573                           tty, NMAX, utmp.ut_name);
574                ioctl(0, TIOCHPCL, (struct sgttyb *) 0);
575                close(0), close(1), close(2);
576                sleep(10);
577                exit(1);
578            }
579        }
580        if (*pwd->pw_shell == '\0')
581            pwd->pw_shell = "/bin/sh";
582        if (chdir(pwd->pw_dir) < 0 && !invalid ) {
583            if (chdir("/") < 0) {
584                printf("No directory!\n");
585                invalid = TRUE;
586            } else {
587                puts("No directory! Logging in with home=/\n");
588                pwd->pw_dir = "/";
589            }
590        }
591        /*
592         * Remote login invalid must have been because
593         * of a restriction of some sort, no extra chances.
594         */
595        if (!usererr && invalid)
596            exit(1);
597
598    } while (invalid);
599    /* committed to login turn off timeout */
600    alarm(0);
601
602    if (tmppwflag) {
603            remove_pwent(pwd);
604            insert_pwent(pwd);
605    }
606
607    if (!krbflag) puts("Warning: no Kerberos tickets obtained.");
608    get_groups();
609#ifndef VFS
610    if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) {
611        if (errno == EUSERS)
612            printf("%s.\n%s.\n",
613                   "Too many users logged on already",
614                   "Try again later");
615        else if (errno == EPROCLIM)
616            printf("You have too many processes running.\n");
617        else
618            perror("quota (Q_SETUID)");
619        sleep(5);
620        if (krbflag)
621                (void) dest_tkt();
622        exit(0);
623    }
624#endif VFS
625    time(&utmp.ut_time);
626    t = ttyslot();
627    if (t > 0 && (f = open("/etc/utmp", O_WRONLY)) >= 0) {
628        lseek(f, (long)(t*sizeof(utmp)), 0);
629        SCPYN(utmp.ut_line, tty);
630        write(f, (char *)&utmp, sizeof(utmp));
631        close(f);
632    }
633    if ((f = open("/usr/adm/wtmp", O_WRONLY|O_APPEND)) >= 0) {
634        write(f, (char *)&utmp, sizeof(utmp));
635        close(f);
636    }
637    quietlog = access(qlog, F_OK) == 0;
638    if ((f = open(lastlog, O_RDWR)) >= 0) {
639        struct lastlog ll;
640
641        lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0);
642        if (read(f, (char *) &ll, sizeof ll) == sizeof ll &&
643            ll.ll_time != 0 && !quietlog) {
644            printf("Last login: %.*s ",
645                   24-5, (char *)ctime(&ll.ll_time));
646            if (*ll.ll_host != '\0')
647            printf("from %.*s\n",
648                   sizeof (ll.ll_host), ll.ll_host);
649            else
650            printf("on %.*s\n",
651                   sizeof (ll.ll_line), ll.ll_line);
652        }
653        lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0);
654        time(&ll.ll_time);
655        SCPYN(ll.ll_line, tty);
656        SCPYN(ll.ll_host, utmp.ut_host);
657        write(f, (char *) &ll, sizeof ll);
658        close(f);
659    }
660    chown(ttyn, pwd->pw_uid, TTYGID(pwd->pw_gid));
661
662    if (!hflag && !rflag && !pflag && !kflag && !Kflag)         /* XXX */
663        ioctl(0, TIOCSWINSZ, &win);
664    chmod(ttyn, 0620);
665
666    init_wgfile();
667   
668    /* Fork so that we can call kdestroy, notification server */
669    dofork();
670       
671    setgid(pwd->pw_gid);
672    strncpy(name, utmp.ut_name, NMAX);
673    name[NMAX] = '\0';
674    initgroups(name, pwd->pw_gid);
675#ifndef VFS
676    quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0);
677#endif !VFS
678
679    /* This call MUST succeed */
680    if(setuid(pwd->pw_uid) < 0) {
681        perror("setuid");
682        if (krbflag)
683                (void) dest_tkt();
684        exit(1);
685    }
686    chdir(pwd->pw_dir);
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) {
1201                chown(pwd->pw_dir, pwd->pw_uid, pwd->pw_gid);
1202                return (0);
1203        }
1204        return (1);
1205}
1206
1207/* Detach the user's home directory */
1208detach_homedir()
1209{
1210        union wait status;
1211        int pid;
1212
1213#ifdef notdef
1214        int i;
1215        char *level;
1216        for (i=0;i<3;i++) {
1217#endif
1218                if (!(pid = fork())) {
1219                        setuid(pwd->pw_uid);
1220                        freopen("/dev/null","w",stdout);
1221                        freopen("/dev/null","w",stderr);
1222                        execl("/bin/athena/detach","detach",lusername,0);
1223                        exit (-1);
1224                }
1225                while (wait(&status) != pid)
1226                        ;
1227#ifdef notdef
1228                if (status.w_retcode == DETACH_OK)
1229                        return;
1230                level = "1";
1231                if (i == 1)
1232                        level = "9";
1233                if (i == 2)
1234                        level = "9";
1235                printf("Killing processes using %s with signal %s\n",
1236                       pwd->pw_dir,level);
1237                if (!(pid = fork())) {
1238                        freopen("/dev/null","w",stdout);
1239                        freopen("/dev/null","w",stderr);
1240                        execl("/etc/athena/ofiles","ofiles","-k",
1241                              level,pwd->pw_dir,0);
1242                        exit (-1);
1243                }
1244                while (wait(0) != pid)
1245                        ;
1246        }
1247#endif notdef
1248        return;
1249#ifdef notdef
1250        printf("Couldn't detach home directory!\n");
1251#endif notdef
1252}
1253
1254isremotedir(dname)
1255char *dname;
1256{
1257        int fh, c;
1258
1259        /*
1260         * The following lines rely on the
1261         * behavior of Sun's NFS (present in 3.0 and 3.2)
1262         * which causes a read on an NFS directory (actually any non-reg file)
1263         * to return -1 with errno set to EISDIR.
1264         *
1265         * This is a fast, cheap way to discover whether a user's
1266         * homedir is a remote NFS filesystem.  Naturally, if the NFS semantics
1267         * change, this must also change.
1268         *
1269         * We return 1 if it is any remote filesystem so that the
1270         * attach_homedir command will run again (sending an "nfsid map"
1271         * command and cleaning up attachtab, if it happens to be out of sync.)
1272         *
1273         * Might want to handle RVD filesystems at some point...
1274         */
1275
1276        fh = open(dname, O_RDONLY);
1277        if (fh < 0)
1278                return(0);
1279        if (read(fh, &c, 1) < 0 && errno == EISDIR) {
1280                close(fh);
1281                return(1);
1282        }
1283        close(fh);
1284        return(0);
1285}
1286
1287goodhomedir()
1288{
1289        DIR *dp;
1290       
1291        if (access(pwd->pw_dir,F_OK))
1292                return (0);
1293
1294        if (isremotedir(pwd->pw_dir))
1295                return(0);
1296
1297        dp = opendir(pwd->pw_dir);
1298        if (!dp)
1299                return (0);
1300        readdir(dp);
1301        readdir(dp);
1302        if (readdir(dp)) {
1303                closedir(dp);
1304                return (1);
1305        }
1306        closedir(dp);
1307        return (0);
1308}
1309       
1310/*
1311 * Make a home directory, copying over files from PROTOTYPE_DIR.
1312 * Ownership and group will be set to the user's uid and gid.  Default
1313 * permission is TEMP_DIR_PERM.  Returns 0 on success, -1 on failure.
1314 */
1315make_homedir()
1316{
1317    DIR *proto;
1318    struct direct *dp;
1319    char tempname[MAXPATHLEN+1];
1320    char buf[MAXBSIZE];
1321    struct stat statbuf;
1322    int fold, fnew;
1323    int n;
1324    extern int errno;
1325
1326    if (inhibitflag)
1327            return (-1);
1328   
1329    strcpy(pwd->pw_dir,"/tmp/");
1330    strcat(pwd->pw_dir,lusername);
1331    setenv("TMPHOME", "", 1);
1332    /* Make the home dir and chdir to it */
1333    unlink(pwd->pw_dir);
1334    if(mkdir(pwd->pw_dir) < 0) {
1335            if (errno == EEXIST)
1336                    return (0);
1337            else
1338                    return(-1);
1339    }
1340    chown(pwd->pw_dir, pwd->pw_uid, pwd->pw_gid);
1341    chmod(pwd->pw_dir, TEMP_DIR_PERM);
1342    chdir(pwd->pw_dir);
1343   
1344    /* Copy over the proto files */
1345    if((proto = opendir(PROTOTYPE_DIR)) == NULL) {
1346        puts("Can't open prototype directory!");
1347        unlink(pwd->pw_dir);
1348        return(-1);
1349    }
1350
1351    for(dp = readdir(proto); dp != NULL; dp = readdir(proto)) {
1352        /* Don't try to copy . or .. */
1353        if(!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue;
1354
1355        /* Copy the file */
1356        SCPYN(tempname, PROTOTYPE_DIR);
1357        strcat(tempname, "/");
1358        strncat(tempname, dp->d_name, sizeof(tempname) - strlen(tempname) - 1);
1359        if(stat(tempname, &statbuf) < 0) {
1360            perror(tempname);
1361            continue;
1362        }
1363        /* Only copy plain files */
1364        if(!(statbuf.st_mode & S_IFREG)) continue;
1365
1366        /* Try to open the source file */
1367        if((fold = open(tempname, O_RDONLY, 0)) < 0) {
1368            perror(tempname);
1369            continue;
1370        }
1371
1372        /* Open the destination file */
1373        if((fnew = open(dp->d_name, O_WRONLY|O_CREAT|O_EXCL,
1374                        statbuf.st_mode)) < 0) {
1375                            perror(dp->d_name);
1376                            continue;
1377                        }
1378
1379        /* Change the ownership */
1380        fchown(fnew, pwd->pw_uid, pwd->pw_gid);
1381
1382        /* Do the copy */
1383        for (;;) {
1384            n = read(fold, buf, sizeof buf);
1385            if(n==0) break;
1386            if(n<0) {
1387                perror(tempname);
1388                break;
1389            }
1390            if (write(fnew, buf, n) != n) {
1391                perror(dp->d_name);
1392                break;
1393            }
1394        }
1395        close(fnew);
1396        close(fold);
1397    }
1398    return(0);
1399}
1400
1401insert_pwent(pwd)
1402struct passwd *pwd;
1403{
1404    FILE *pfile;
1405    int cnt;
1406
1407    while (getpwuid(pwd->pw_uid))
1408      (pwd->pw_uid)++;
1409
1410    cnt = 10;
1411    while (!access("/etc/ptmp",0) && --cnt)
1412            sleep(1);
1413    unlink("/etc/ptmp");
1414   
1415    if((pfile=fopen("/etc/passwd", "a")) != NULL) {
1416        fprintf(pfile, "%s:%s:%d:%d:%s:%s:%s\n",
1417                pwd->pw_name,
1418                pwd->pw_passwd,
1419                pwd->pw_uid,
1420                pwd->pw_gid,
1421                pwd->pw_gecos,
1422                pwd->pw_dir,
1423                pwd->pw_shell);
1424        fclose(pfile);
1425    }
1426}
1427
1428remove_pwent(pwd)
1429struct passwd *pwd;
1430{
1431    FILE *newfile;
1432    struct passwd *copypw;
1433    int cnt;
1434
1435    cnt = 10;
1436    while (!access("/etc/ptmp",0) && --cnt)
1437            sleep(1);
1438    unlink("/etc/ptmp");
1439   
1440    if ((newfile = fopen("/etc/ptmp", "w")) != NULL) {
1441        setpwent();
1442        while ((copypw = getpwent()) != 0)
1443            if (copypw->pw_uid != pwd->pw_uid)
1444                    fprintf(newfile, "%s:%s:%d:%d:%s:%s:%s\n",
1445                            copypw->pw_name,
1446                            copypw->pw_passwd,
1447                            copypw->pw_uid,
1448                            copypw->pw_gid,
1449                            copypw->pw_gecos,
1450                            copypw->pw_dir,
1451                            copypw->pw_shell);
1452        endpwent();
1453        fclose(newfile);
1454        rename("/etc/ptmp", "/etc/passwd");
1455        return(0);
1456    } else return(1);
1457}
1458
1459get_groups()
1460{
1461        FILE *grin,*grout;
1462        char **cp,grbuf[4096],*ptr,*pwptr,*numptr,*lstptr,**grname,**grnum;
1463        char grlst[4096],grtmp[4096],*tmpptr;
1464        int ngroups,i,cnt;
1465       
1466        if (inhibitflag)
1467                return;
1468       
1469        cp = (char **)hes_resolve(pwd->pw_name,"grplist");
1470        if (!cp || !*cp)
1471                return;
1472
1473        cnt = 10;
1474        while (!access("/etc/gtmp",0) && --cnt)
1475                sleep(1);
1476        unlink("/etc/gtmp");
1477       
1478        grin = fopen("/etc/group","r");
1479        if (!grin) {
1480                fprintf(stderr,"Can't open /etc/group!\n");
1481                return;
1482        }
1483        grout = fopen("/etc/gtmp","w");
1484        if (!grout) {
1485                fprintf(stderr,"Can't open /etc/gtmp!\n");
1486                fclose(grin);
1487                return;
1488        }
1489
1490        ngroups = 0;
1491        for (ptr=cp[0];*ptr;ptr++)
1492                if (*ptr == ':')
1493                        ngroups++;
1494
1495        ngroups = (ngroups+1)/2;
1496
1497        if (ngroups > NGROUPS-1)
1498                ngroups = NGROUPS-1;
1499
1500        grname = (char **)malloc(ngroups * sizeof(char *));
1501        if (!grname) {
1502                fprintf(stderr,"Out of memory!\n");
1503                fclose(grin);
1504                fclose(grout);
1505                unlink("/etc/gtmp");
1506                return;
1507        }
1508
1509        grnum = (char **)malloc(ngroups * sizeof(char *));
1510        if (!grnum) {
1511                fprintf(stderr,"Out of memory!\n");
1512                fclose(grin);
1513                fclose(grout);
1514                unlink("/etc/gtmp");
1515                return;
1516        }
1517
1518        for (i=0,ptr=cp[0];i<ngroups;i++) {
1519                grname[i] = ptr;
1520                ptr = (char *)index(ptr,':');
1521                if (!ptr) {
1522                        fprintf(stderr,"Internal failure while initializing groups\n");
1523                        fclose(grin);
1524                        fclose(grout);
1525                        free(grname);
1526                        free(grnum);
1527                        unlink("/etc/gtmp");
1528                        return;
1529                }
1530                *ptr++ = '\0';
1531                grnum[i] = ptr;
1532                ptr = (char *)index(ptr,':');
1533                if (!ptr)
1534                        ptr = grnum[i]+strlen(grnum[i]);
1535                *ptr++ = '\0';
1536        }
1537
1538        while (fgets(grbuf,sizeof grbuf,grin) != 0) {
1539                if (!*grbuf)
1540                        break;
1541                grbuf[strlen(grbuf)-1] = '\0';
1542                pwptr = (char *)index(grbuf,':');
1543                if (!pwptr)
1544                        continue;
1545                *pwptr++ = '\0';
1546                numptr = (char *)index(pwptr,':');
1547                if (!numptr)
1548                        continue;
1549                *numptr++ = '\0';
1550                lstptr = (char *)index(numptr,':');
1551                if (!lstptr)
1552                        continue;
1553                *lstptr++ = '\0';
1554                strcpy(grlst,lstptr);
1555                for (i=0;i<ngroups;i++) {
1556                        if (strcmp(grname[i],grbuf))
1557                                continue;
1558                        lstptr = grlst;
1559                        while (lstptr) {
1560                                strcpy(grtmp,lstptr);
1561                                tmpptr = (char *)index(grtmp,',');
1562                                if (tmpptr)
1563                                        *tmpptr = '\0';
1564                                if (!strcmp(grtmp,pwd->pw_name)) {
1565                                        grname[i] = "*";
1566                                        break;
1567                                }
1568                                lstptr = (char *)index(lstptr,',');
1569                                if (lstptr)
1570                                        lstptr++;
1571                        }
1572                        if (lstptr)
1573                                break;
1574                        strcat(grlst,",");
1575                        strcat(grlst,pwd->pw_name);
1576                        grname[i] = "*";
1577                        break;
1578                }
1579                fprintf(grout,"%s:%s:%s:%s\n",grbuf,pwptr,numptr,grlst);
1580        }
1581
1582        for (i=0;i<ngroups;i++)
1583                if (strcmp(grname[i],"*"))
1584                        fprintf(grout,"%s:%s:%s:%s\n",grname[i],"*",
1585                                grnum[i],pwd->pw_name);
1586
1587        fclose(grin);
1588        fclose(grout);
1589        rename("/etc/gtmp","/etc/group");
1590        unlink("/etc/gtmp");
1591        free(grname);
1592        free(grnum);
1593}
1594
1595init_wgfile()
1596{
1597        char *wgfile;
1598
1599        wgfile = "/tmp/wg.XXXXXX";
1600
1601        mktemp(wgfile);
1602
1603        setenv("WGFILE",wgfile,1);
1604}
1605
1606/*
1607 * Verify the Kerberos ticket-granting ticket just retrieved for the
1608 * user.  If the Kerberos server doesn't respond, assume the user is
1609 * trying to fake us out (since we DID just get a TGT from what is
1610 * supposedly our KDC).  If the rcmd.<host> service is unknown (i.e.,
1611 * the local /etc/srvtab doesn't have it), let her in.
1612 *
1613 * Returns 1 for confirmation, -1 for failure, 0 for uncertainty.
1614 */
1615int verify_krb_tgt (realm)
1616    char *realm;
1617{
1618    char hostname[MAXHOSTNAMELEN], phost[BUFSIZ];
1619    struct hostent *hp;
1620    KTEXT_ST ticket;
1621    AUTH_DAT authdata;
1622    unsigned long addr;
1623    static /*const*/ char rcmd[] = "rcmd";
1624    char key[8];
1625    int krbval, retval, have_keys;
1626
1627    if (gethostname(hostname, sizeof(hostname)) == -1) {
1628        perror ("cannot retrieve local hostname");
1629        return -1;
1630    }
1631    strncpy (phost, krb_get_phost (hostname), sizeof (phost));
1632    phost[sizeof(phost)-1] = 0;
1633    hp = gethostbyname (hostname);
1634    if (!hp) {
1635        perror ("cannot retrieve local host address");
1636        return -1;
1637    }
1638    bcopy ((char *)hp->h_addr, (char *) &addr, sizeof (addr));
1639    /* Do we have rcmd.<host> keys? */
1640    have_keys = read_service_key (rcmd, phost, realm, 0, "/etc/srvtab", key)
1641        ? 0 : 1;
1642    krbval = krb_mk_req (&ticket, rcmd, phost, realm, 0);
1643    if (krbval == KDC_PR_UNKNOWN) {
1644        /*
1645         * Our rcmd.<host> principal isn't known -- just assume valid
1646         * for now?  This is one case that the user _could_ fake out.
1647         */
1648        if (have_keys)
1649            return -1;
1650        else
1651            return 0;
1652    }
1653    else if (krbval != KSUCCESS) {
1654        printf ("Unable to verify Kerberos TGT: %s\n", krb_err_txt[krbval]);
1655        syslog (LOG_NOTICE|LOG_AUTH, "Kerberos TGT bad: %s",
1656                krb_err_txt[krbval]);
1657        return -1;
1658    }
1659    /* got ticket, try to use it */
1660    krbval = krb_rd_req (&ticket, rcmd, phost, addr, &authdata, "");
1661    if (krbval != KSUCCESS) {
1662        if (krbval == RD_AP_UNDEC && !have_keys)
1663            retval = 0;
1664        else {
1665            retval = -1;
1666            printf ("Unable to verify `rcmd' ticket: %s\n",
1667                    krb_err_txt[krbval]);
1668        }
1669        syslog (LOG_NOTICE|LOG_AUTH, "can't verify rcmd ticket: %s;%s\n",
1670                krb_err_txt[krbval],
1671                retval
1672                ? "srvtab found, assuming failure"
1673                : "no srvtab found, assuming success");
1674        goto EGRESS;
1675    }
1676    /*
1677     * The rcmd.<host> ticket has been received _and_ verified.
1678     */
1679    retval = 1;
1680    /* do cleanup and return */
1681EGRESS:
1682    bzero (&ticket, sizeof (ticket));
1683    bzero (&authdata, sizeof (authdata));
1684    return retval;
1685}
Note: See TracBrowser for help on using the repository browser.