Annotation of 43BSDReno/kerberosIV/krb/tf_util.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * $Source: /afs/athena.mit.edu/astaff/project/kerberos/src/lib/krb/RCS/tf_util.c,v $
        !             3:  * $Author: jon $
        !             4:  *
        !             5:  * Copyright 1987, 1988 by the Massachusetts Institute of Technology.
        !             6:  *
        !             7:  * For copying and distribution information, please see the file
        !             8:  * <mit-copyright.h>.
        !             9:  */
        !            10: 
        !            11: #ifndef lint
        !            12: static char rcsid_tf_util_c[] =
        !            13: "$Id: tf_util.c,v 4.8 90/01/02 13:34:27 jtkohl Exp Locker: jtkohl $";
        !            14: #endif /* lint */
        !            15: 
        !            16: #include <mit-copyright.h>
        !            17: 
        !            18: #include <stdio.h>
        !            19: #include <errno.h>
        !            20: #include <sys/types.h>
        !            21: #include <sys/stat.h>
        !            22: #include <sys/file.h>
        !            23: #include <des.h>
        !            24: #include <krb.h>
        !            25: 
        !            26: #ifdef TKT_SHMEM
        !            27: #include <sys/param.h>
        !            28: #include <sys/ipc.h>
        !            29: #include <sys/shm.h>
        !            30: #endif /* TKT_SHMEM */
        !            31: 
        !            32: #define TOO_BIG -1
        !            33: #define TF_LCK_RETRY ((unsigned)2)     /* seconds to sleep before
        !            34:                                         * retry if ticket file is
        !            35:                                         * locked */
        !            36: extern  errno;
        !            37: extern int krb_debug;
        !            38: 
        !            39: #ifdef TKT_SHMEM
        !            40: char *krb_shm_addr = 0;
        !            41: static char *tmp_shm_addr = 0;
        !            42: static char krb_dummy_skey[8] = {0,0,0,0,0,0,0,0};
        !            43: 
        !            44: char *shmat();
        !            45: #endif /* TKT_SHMEM */
        !            46: 
        !            47: /*
        !            48:  * fd must be initialized to something that won't ever occur as a real
        !            49:  * file descriptor. Since open(2) returns only non-negative numbers as
        !            50:  * valid file descriptors, and tf_init always stuffs the return value
        !            51:  * from open in here even if it is an error flag, we must
        !            52:  *     a. Initialize fd to a negative number, to indicate that it is
        !            53:  *        not initially valid.
        !            54:  *     b. When checking for a valid fd, assume that negative values
        !            55:  *        are invalid (ie. when deciding whether tf_init has been
        !            56:  *        called.)
        !            57:  *     c. In tf_close, be sure it gets reinitialized to a negative
        !            58:  *        number. 
        !            59:  */
        !            60: static  fd = -1;
        !            61: static curpos;                         /* Position in tfbfr */
        !            62: static lastpos;                        /* End of tfbfr */
        !            63: static char tfbfr[BUFSIZ];             /* Buffer for ticket data */
        !            64: 
        !            65: static tf_gets(), tf_read();
        !            66: 
        !            67: /*
        !            68:  * This file contains routines for manipulating the ticket cache file.
        !            69:  *
        !            70:  * The ticket file is in the following format:
        !            71:  *
        !            72:  *      principal's name        (null-terminated string)
        !            73:  *      principal's instance    (null-terminated string)
        !            74:  *      CREDENTIAL_1
        !            75:  *      CREDENTIAL_2
        !            76:  *      ...
        !            77:  *      CREDENTIAL_n
        !            78:  *      EOF
        !            79:  *
        !            80:  *      Where "CREDENTIAL_x" consists of the following fixed-length
        !            81:  *      fields from the CREDENTIALS structure (see "krb.h"):
        !            82:  *
        !            83:  *              char            service[ANAME_SZ]
        !            84:  *              char            instance[INST_SZ]
        !            85:  *              char            realm[REALM_SZ]
        !            86:  *              C_Block         session
        !            87:  *              int             lifetime
        !            88:  *              int             kvno
        !            89:  *              KTEXT_ST        ticket_st
        !            90:  *              long            issue_date
        !            91:  *
        !            92:  * Short description of routines:
        !            93:  *
        !            94:  * tf_init() opens the ticket file and locks it.
        !            95:  *
        !            96:  * tf_get_pname() returns the principal's name.
        !            97:  *
        !            98:  * tf_get_pinst() returns the principal's instance (may be null).
        !            99:  *
        !           100:  * tf_get_cred() returns the next CREDENTIALS record.
        !           101:  *
        !           102:  * tf_save_cred() appends a new CREDENTIAL record to the ticket file.
        !           103:  *
        !           104:  * tf_close() closes the ticket file and releases the lock.
        !           105:  *
        !           106:  * tf_gets() returns the next null-terminated string.  It's an internal
        !           107:  * routine used by tf_get_pname(), tf_get_pinst(), and tf_get_cred().
        !           108:  *
        !           109:  * tf_read() reads a given number of bytes.  It's an internal routine
        !           110:  * used by tf_get_cred().
        !           111:  */
        !           112: 
        !           113: /*
        !           114:  * tf_init() should be called before the other ticket file routines.
        !           115:  * It takes the name of the ticket file to use, "tf_name", and a
        !           116:  * read/write flag "rw" as arguments. 
        !           117:  *
        !           118:  * It tries to open the ticket file, checks the mode, and if everything
        !           119:  * is okay, locks the file.  If it's opened for reading, the lock is
        !           120:  * shared.  If it's opened for writing, the lock is exclusive. 
        !           121:  *
        !           122:  * Returns KSUCCESS if all went well, otherwise one of the following: 
        !           123:  *
        !           124:  * NO_TKT_FIL   - file wasn't there
        !           125:  * TKT_FIL_ACC  - file was in wrong mode, etc.
        !           126:  * TKT_FIL_LCK  - couldn't lock the file, even after a retry
        !           127:  */
        !           128: 
        !           129: tf_init(tf_name, rw)
        !           130:     char   *tf_name;
        !           131: {
        !           132:     int     wflag;
        !           133:     uid_t   me, getuid();
        !           134:     struct stat stat_buf;
        !           135: #ifdef TKT_SHMEM
        !           136:     char shmidname[MAXPATHLEN]; 
        !           137:     FILE *sfp;
        !           138:     int shmid;
        !           139: #endif
        !           140: 
        !           141:     switch (rw) {
        !           142:     case R_TKT_FIL:
        !           143:        wflag = 0;
        !           144:        break;
        !           145:     case W_TKT_FIL:
        !           146:        wflag = 1;
        !           147:        break;
        !           148:     default:
        !           149:        if (krb_debug) fprintf(stderr, "tf_init: illegal parameter\n");
        !           150:        return TKT_FIL_ACC;
        !           151:     }
        !           152:     if (lstat(tf_name, &stat_buf) < 0)
        !           153:        switch (errno) {
        !           154:        case ENOENT:
        !           155:            return NO_TKT_FIL;
        !           156:        default:
        !           157:            return TKT_FIL_ACC;
        !           158:        }
        !           159:     me = getuid();
        !           160:     if ((stat_buf.st_uid != me && me != 0) ||
        !           161:        ((stat_buf.st_mode & S_IFMT) != S_IFREG))
        !           162:        return TKT_FIL_ACC;
        !           163: #ifdef TKT_SHMEM
        !           164:     (void) strcpy(shmidname, tf_name);
        !           165:     (void) strcat(shmidname, ".shm");
        !           166:     if (stat(shmidname,&stat_buf) < 0)
        !           167:        return(TKT_FIL_ACC);
        !           168:     if ((stat_buf.st_uid != me && me != 0) ||
        !           169:        ((stat_buf.st_mode & S_IFMT) != S_IFREG))
        !           170:        return TKT_FIL_ACC;
        !           171: #endif /* TKT_SHMEM */
        !           172: 
        !           173:     /*
        !           174:      * If "wflag" is set, open the ticket file in append-writeonly mode
        !           175:      * and lock the ticket file in exclusive mode.  If unable to lock
        !           176:      * the file, sleep and try again.  If we fail again, return with the
        !           177:      * proper error message. 
        !           178:      */
        !           179: 
        !           180:     curpos = sizeof(tfbfr);
        !           181: 
        !           182: #ifdef TKT_SHMEM
        !           183:     sfp = fopen(shmidname, "r");       /* only need read/write on the
        !           184:                                           actual tickets */
        !           185:     if (sfp == 0)
        !           186:        return TKT_FIL_ACC;
        !           187:     shmid = -1;
        !           188:     {
        !           189:        char buf[BUFSIZ];
        !           190:        int val;                        /* useful for debugging fscanf */
        !           191:        /* We provide our own buffer here since some STDIO libraries
        !           192:           barf on unbuffered input with fscanf() */
        !           193: 
        !           194:        setbuf(sfp, buf);
        !           195:        if ((val = fscanf(sfp,"%d",&shmid)) != 1) {
        !           196:            (void) fclose(sfp);
        !           197:            return TKT_FIL_ACC;
        !           198:        }
        !           199:        if (shmid < 0) {
        !           200:            (void) fclose(sfp);
        !           201:            return TKT_FIL_ACC;
        !           202:        }
        !           203:        (void) fclose(sfp);
        !           204:     }
        !           205:     /*
        !           206:     * global krb_shm_addr is initialized to 0.  Ultrix bombs when you try and
        !           207:     * attach the same segment twice so we need this check.
        !           208:     */
        !           209:     if (!krb_shm_addr) {
        !           210:        if ((krb_shm_addr = shmat(shmid,0,0)) == -1){
        !           211:                if (krb_debug)
        !           212:                    fprintf(stderr,
        !           213:                            "cannot attach shared memory for segment %d\n",
        !           214:                            shmid);
        !           215:                krb_shm_addr = 0;       /* reset so we catch further errors */
        !           216:                return TKT_FIL_ACC;
        !           217:            }
        !           218:     }
        !           219:     tmp_shm_addr = krb_shm_addr;
        !           220: #endif /* TKT_SHMEM */
        !           221:     
        !           222:     if (wflag) {
        !           223:        fd = open(tf_name, O_RDWR, 0600);
        !           224:        if (fd < 0) {
        !           225:            return TKT_FIL_ACC;
        !           226:        }
        !           227:        if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
        !           228:            sleep(TF_LCK_RETRY);
        !           229:            if (flock(fd, LOCK_EX | LOCK_NB) < 0) {
        !           230:                (void) close(fd);
        !           231:                fd = -1;
        !           232:                return TKT_FIL_LCK;
        !           233:            }
        !           234:        }
        !           235:        return KSUCCESS;
        !           236:     }
        !           237:     /*
        !           238:      * Otherwise "wflag" is not set and the ticket file should be opened
        !           239:      * for read-only operations and locked for shared access. 
        !           240:      */
        !           241: 
        !           242:     fd = open(tf_name, O_RDONLY, 0600);
        !           243:     if (fd < 0) {
        !           244:        return TKT_FIL_ACC;
        !           245:     }
        !           246:     if (flock(fd, LOCK_SH | LOCK_NB) < 0) {
        !           247:        sleep(TF_LCK_RETRY);
        !           248:        if (flock(fd, LOCK_SH | LOCK_NB) < 0) {
        !           249:            (void) close(fd);
        !           250:            fd = -1;
        !           251:            return TKT_FIL_LCK;
        !           252:        }
        !           253:     }
        !           254:     return KSUCCESS;
        !           255: }
        !           256: 
        !           257: /*
        !           258:  * tf_get_pname() reads the principal's name from the ticket file. It
        !           259:  * should only be called after tf_init() has been called.  The
        !           260:  * principal's name is filled into the "p" parameter.  If all goes well,
        !           261:  * KSUCCESS is returned.  If tf_init() wasn't called, TKT_FIL_INI is
        !           262:  * returned.  If the name was null, or EOF was encountered, or the name
        !           263:  * was longer than ANAME_SZ, TKT_FIL_FMT is returned. 
        !           264:  */
        !           265: 
        !           266: tf_get_pname(p)
        !           267:     char   *p;
        !           268: {
        !           269:     if (fd < 0) {
        !           270:        if (krb_debug)
        !           271:            fprintf(stderr, "tf_get_pname called before tf_init.\n");
        !           272:        return TKT_FIL_INI;
        !           273:     }
        !           274:     if (tf_gets(p, ANAME_SZ) < 2)      /* can't be just a null */
        !           275:        return TKT_FIL_FMT;
        !           276:     return KSUCCESS;
        !           277: }
        !           278: 
        !           279: /*
        !           280:  * tf_get_pinst() reads the principal's instance from a ticket file.
        !           281:  * It should only be called after tf_init() and tf_get_pname() have been
        !           282:  * called.  The instance is filled into the "inst" parameter.  If all
        !           283:  * goes well, KSUCCESS is returned.  If tf_init() wasn't called,
        !           284:  * TKT_FIL_INI is returned.  If EOF was encountered, or the instance
        !           285:  * was longer than ANAME_SZ, TKT_FIL_FMT is returned.  Note that the
        !           286:  * instance may be null. 
        !           287:  */
        !           288: 
        !           289: tf_get_pinst(inst)
        !           290:     char   *inst;
        !           291: {
        !           292:     if (fd < 0) {
        !           293:        if (krb_debug)
        !           294:            fprintf(stderr, "tf_get_pinst called before tf_init.\n");
        !           295:        return TKT_FIL_INI;
        !           296:     }
        !           297:     if (tf_gets(inst, INST_SZ) < 1)
        !           298:        return TKT_FIL_FMT;
        !           299:     return KSUCCESS;
        !           300: }
        !           301: 
        !           302: /*
        !           303:  * tf_get_cred() reads a CREDENTIALS record from a ticket file and fills
        !           304:  * in the given structure "c".  It should only be called after tf_init(),
        !           305:  * tf_get_pname(), and tf_get_pinst() have been called. If all goes well,
        !           306:  * KSUCCESS is returned.  Possible error codes are: 
        !           307:  *
        !           308:  * TKT_FIL_INI  - tf_init wasn't called first
        !           309:  * TKT_FIL_FMT  - bad format
        !           310:  * EOF          - end of file encountered
        !           311:  */
        !           312: 
        !           313: tf_get_cred(c)
        !           314:     CREDENTIALS *c;
        !           315: {
        !           316:     KTEXT   ticket = &c->ticket_st;    /* pointer to ticket */
        !           317:     int     k_errno;
        !           318: 
        !           319:     if (fd < 0) {
        !           320:        if (krb_debug)
        !           321:            fprintf(stderr, "tf_get_cred called before tf_init.\n");
        !           322:        return TKT_FIL_INI;
        !           323:     }
        !           324:     if ((k_errno = tf_gets(c->service, SNAME_SZ)) < 2)
        !           325:        switch (k_errno) {
        !           326:        case TOO_BIG:
        !           327:        case 1:         /* can't be just a null */
        !           328:            tf_close();
        !           329:            return TKT_FIL_FMT;
        !           330:        case 0:
        !           331:            return EOF;
        !           332:        }
        !           333:     if ((k_errno = tf_gets(c->instance, INST_SZ)) < 1)
        !           334:        switch (k_errno) {
        !           335:        case TOO_BIG:
        !           336:            return TKT_FIL_FMT;
        !           337:        case 0:
        !           338:            return EOF;
        !           339:        }
        !           340:     if ((k_errno = tf_gets(c->realm, REALM_SZ)) < 2)
        !           341:        switch (k_errno) {
        !           342:        case TOO_BIG:
        !           343:        case 1:         /* can't be just a null */
        !           344:            tf_close();
        !           345:            return TKT_FIL_FMT;
        !           346:        case 0:
        !           347:            return EOF;
        !           348:        }
        !           349:     if (
        !           350:        tf_read((char *) (c->session), KEY_SZ) < 1 ||
        !           351:        tf_read((char *) &(c->lifetime), sizeof(c->lifetime)) < 1 ||
        !           352:        tf_read((char *) &(c->kvno), sizeof(c->kvno)) < 1 ||
        !           353:        tf_read((char *) &(ticket->length), sizeof(ticket->length))
        !           354:        < 1 ||
        !           355:     /* don't try to read a silly amount into ticket->dat */
        !           356:        ticket->length > MAX_KTXT_LEN ||
        !           357:        tf_read((char *) (ticket->dat), ticket->length) < 1 ||
        !           358:        tf_read((char *) &(c->issue_date), sizeof(c->issue_date)) < 1
        !           359:        ) {
        !           360:        tf_close();
        !           361:        return TKT_FIL_FMT;
        !           362:     }
        !           363: #ifdef TKT_SHMEM
        !           364:     bcopy(tmp_shm_addr,c->session,KEY_SZ);
        !           365:     tmp_shm_addr += KEY_SZ;
        !           366: #endif /* TKT_SHMEM */
        !           367:     return KSUCCESS;
        !           368: }
        !           369: 
        !           370: /*
        !           371:  * tf_close() closes the ticket file and sets "fd" to -1. If "fd" is
        !           372:  * not a valid file descriptor, it just returns.  It also clears the
        !           373:  * buffer used to read tickets.
        !           374:  *
        !           375:  * The return value is not defined.
        !           376:  */
        !           377: 
        !           378: tf_close()
        !           379: {
        !           380:     if (!(fd < 0)) {
        !           381: #ifdef TKT_SHMEM
        !           382:        if (shmdt(krb_shm_addr)) {
        !           383:            /* what kind of error? */
        !           384:            if (krb_debug)
        !           385:                fprintf(stderr, "shmdt 0x%x: errno %d",krb_shm_addr, errno);
        !           386:        } else {
        !           387:            krb_shm_addr = 0;
        !           388:        }
        !           389: #endif TKT_SHMEM
        !           390:        (void) flock(fd, LOCK_UN);
        !           391:        (void) close(fd);
        !           392:        fd = -1;                /* see declaration of fd above */
        !           393:     }
        !           394:     bzero(tfbfr, sizeof(tfbfr));
        !           395: }
        !           396: 
        !           397: /*
        !           398:  * tf_gets() is an internal routine.  It takes a string "s" and a count
        !           399:  * "n", and reads from the file until either it has read "n" characters,
        !           400:  * or until it reads a null byte. When finished, what has been read exists
        !           401:  * in "s". If it encounters EOF or an error, it closes the ticket file. 
        !           402:  *
        !           403:  * Possible return values are:
        !           404:  *
        !           405:  * n            the number of bytes read (including null terminator)
        !           406:  *              when all goes well
        !           407:  *
        !           408:  * 0            end of file or read error
        !           409:  *
        !           410:  * TOO_BIG      if "count" characters are read and no null is
        !           411:  *             encountered. This is an indication that the ticket
        !           412:  *             file is seriously ill.
        !           413:  */
        !           414: 
        !           415: static 
        !           416: tf_gets(s, n)
        !           417:     register char *s;
        !           418: {
        !           419:     register count;
        !           420: 
        !           421:     if (fd < 0) {
        !           422:        if (krb_debug)
        !           423:            fprintf(stderr, "tf_gets called before tf_init.\n");
        !           424:        return TKT_FIL_INI;
        !           425:     }
        !           426:     for (count = n - 1; count > 0; --count) {
        !           427:        if (curpos >= sizeof(tfbfr)) {
        !           428:            lastpos = read(fd, tfbfr, sizeof(tfbfr));
        !           429:            curpos = 0;
        !           430:        }
        !           431:        if (curpos == lastpos) {
        !           432:            tf_close();
        !           433:            return 0;
        !           434:        }
        !           435:        *s = tfbfr[curpos++];
        !           436:        if (*s++ == '\0')
        !           437:            return (n - count);
        !           438:     }
        !           439:     tf_close();
        !           440:     return TOO_BIG;
        !           441: }
        !           442: 
        !           443: /*
        !           444:  * tf_read() is an internal routine.  It takes a string "s" and a count
        !           445:  * "n", and reads from the file until "n" bytes have been read.  When
        !           446:  * finished, what has been read exists in "s".  If it encounters EOF or
        !           447:  * an error, it closes the ticket file.
        !           448:  *
        !           449:  * Possible return values are:
        !           450:  *
        !           451:  * n           the number of bytes read when all goes well
        !           452:  *
        !           453:  * 0           on end of file or read error
        !           454:  */
        !           455: 
        !           456: static
        !           457: tf_read(s, n)
        !           458:     register char *s;
        !           459:     register n;
        !           460: {
        !           461:     register count;
        !           462:     
        !           463:     for (count = n; count > 0; --count) {
        !           464:        if (curpos >= sizeof(tfbfr)) {
        !           465:            lastpos = read(fd, tfbfr, sizeof(tfbfr));
        !           466:            curpos = 0;
        !           467:        }
        !           468:        if (curpos == lastpos) {
        !           469:            tf_close();
        !           470:            return 0;
        !           471:        }
        !           472:        *s++ = tfbfr[curpos++];
        !           473:     }
        !           474:     return n;
        !           475: }
        !           476:      
        !           477: char   *tkt_string();
        !           478: 
        !           479: /*
        !           480:  * tf_save_cred() appends an incoming ticket to the end of the ticket
        !           481:  * file.  You must call tf_init() before calling tf_save_cred().
        !           482:  *
        !           483:  * The "service", "instance", and "realm" arguments specify the
        !           484:  * server's name; "session" contains the session key to be used with
        !           485:  * the ticket; "kvno" is the server key version number in which the
        !           486:  * ticket is encrypted, "ticket" contains the actual ticket, and
        !           487:  * "issue_date" is the time the ticket was requested (local host's time).
        !           488:  *
        !           489:  * Returns KSUCCESS if all goes well, TKT_FIL_INI if tf_init() wasn't
        !           490:  * called previously, and KFAILURE for anything else that went wrong.
        !           491:  */
        !           492: 
        !           493: tf_save_cred(service, instance, realm, session, lifetime, kvno,
        !           494:             ticket, issue_date)
        !           495:     char   *service;           /* Service name */
        !           496:     char   *instance;          /* Instance */
        !           497:     char   *realm;             /* Auth domain */
        !           498:     C_Block session;           /* Session key */
        !           499:     int     lifetime;          /* Lifetime */
        !           500:     int     kvno;              /* Key version number */
        !           501:     KTEXT   ticket;            /* The ticket itself */
        !           502:     long    issue_date;                /* The issue time */
        !           503: {
        !           504: 
        !           505:     off_t   lseek();
        !           506:     int     count;             /* count for write */
        !           507: #ifdef TKT_SHMEM
        !           508:     int            *skey_check;
        !           509: #endif /* TKT_SHMEM */
        !           510: 
        !           511:     if (fd < 0) {              /* fd is ticket file as set by tf_init */
        !           512:          if (krb_debug)
        !           513:              fprintf(stderr, "tf_save_cred called before tf_init.\n");
        !           514:          return TKT_FIL_INI;
        !           515:     }
        !           516:     /* Find the end of the ticket file */
        !           517:     (void) lseek(fd, 0L, 2);
        !           518: #ifdef TKT_SHMEM
        !           519:     /* scan to end of existing keys: pick first 'empty' slot.
        !           520:        we assume that no real keys will be completely zero (it's a weak
        !           521:        key under DES) */
        !           522: 
        !           523:     skey_check = (int *) krb_shm_addr;
        !           524: 
        !           525:     while (*skey_check && *(skey_check+1))
        !           526:        skey_check += 2;
        !           527:     tmp_shm_addr = (char *)skey_check;
        !           528: #endif /* TKT_SHMEM */
        !           529: 
        !           530:     /* Write the ticket and associated data */
        !           531:     /* Service */
        !           532:     count = strlen(service) + 1;
        !           533:     if (write(fd, service, count) != count)
        !           534:        goto bad;
        !           535:     /* Instance */
        !           536:     count = strlen(instance) + 1;
        !           537:     if (write(fd, instance, count) != count)
        !           538:        goto bad;
        !           539:     /* Realm */
        !           540:     count = strlen(realm) + 1;
        !           541:     if (write(fd, realm, count) != count)
        !           542:        goto bad;
        !           543:     /* Session key */
        !           544: #ifdef TKT_SHMEM
        !           545:     bcopy(session,tmp_shm_addr,8);
        !           546:     tmp_shm_addr+=8;
        !           547:     if (write(fd,krb_dummy_skey,8) != 8)
        !           548:        goto bad;
        !           549: #else /* ! TKT_SHMEM */
        !           550:     if (write(fd, (char *) session, 8) != 8)
        !           551:        goto bad;
        !           552: #endif /* TKT_SHMEM */
        !           553:     /* Lifetime */
        !           554:     if (write(fd, (char *) &lifetime, sizeof(int)) != sizeof(int))
        !           555:        goto bad;
        !           556:     /* Key vno */
        !           557:     if (write(fd, (char *) &kvno, sizeof(int)) != sizeof(int))
        !           558:        goto bad;
        !           559:     /* Tkt length */
        !           560:     if (write(fd, (char *) &(ticket->length), sizeof(int)) !=
        !           561:        sizeof(int))
        !           562:        goto bad;
        !           563:     /* Ticket */
        !           564:     count = ticket->length;
        !           565:     if (write(fd, (char *) (ticket->dat), count) != count)
        !           566:        goto bad;
        !           567:     /* Issue date */
        !           568:     if (write(fd, (char *) &issue_date, sizeof(long))
        !           569:        != sizeof(long))
        !           570:        goto bad;
        !           571: 
        !           572:     /* Actually, we should check each write for success */
        !           573:     return (KSUCCESS);
        !           574: bad:
        !           575:     return (KFAILURE);
        !           576: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.