Annotation of lucent/sys/src/9/port/auth.c, revision 1.1

1.1     ! root        1: #include       "u.h"
        !             2: #include       "../port/lib.h"
        !             3: #include       "mem.h"
        !             4: #include       "dat.h"
        !             5: #include       "fns.h"
        !             6: #include       "io.h"
        !             7: #include       "../port/error.h"
        !             8: 
        !             9: typedef struct Crypt   Crypt;
        !            10: struct Crypt
        !            11: {
        !            12:        Crypt           *next;
        !            13:        Ticket          t;
        !            14:        Authenticator   a;
        !            15:        char            tbuf[TICKETLEN];        /* remote ticket */
        !            16: };
        !            17: 
        !            18: typedef struct Session Session;
        !            19: struct Session
        !            20: {
        !            21:        Lock;
        !            22:        QLock   send;
        !            23:        Crypt   *cache;                 /* cache of tickets */
        !            24:        char    cchal[CHALLEN];         /* client challenge */
        !            25:        char    schal[CHALLEN];         /* server challenge */
        !            26:        char    authid[NAMELEN];        /* server encryption uid */
        !            27:        char    authdom[DOMLEN];        /* server encryption domain */
        !            28:        ulong   cid;                    /* challenge id */
        !            29:        int     valid;
        !            30: };
        !            31: 
        !            32: struct
        !            33: {
        !            34:        Lock;
        !            35:        Crypt           *free;
        !            36: } cryptalloc;
        !            37: 
        !            38: char   eve[NAMELEN] = "bootes";
        !            39: char   evekey[DESKEYLEN];
        !            40: char   hostdomain[DOMLEN];
        !            41: 
        !            42: /*
        !            43:  *  return true if current user is eve
        !            44:  */
        !            45: int
        !            46: iseve(void)
        !            47: {
        !            48:        return strcmp(eve, u->p->user) == 0;
        !            49: }
        !            50: 
        !            51: /*
        !            52:  * crypt entries are allocated from a pool rather than allocated using malloc so
        !            53:  * the memory can be protected from reading by devproc. The base and top of the
        !            54:  * crypt arena is stored in palloc for devproc.
        !            55:  */
        !            56: Crypt*
        !            57: newcrypt(void)
        !            58: {
        !            59:        Crypt *c;
        !            60: 
        !            61:        lock(&cryptalloc);
        !            62:        if(cryptalloc.free) {
        !            63:                c = cryptalloc.free;
        !            64:                cryptalloc.free = c->next;
        !            65:                unlock(&cryptalloc);
        !            66:                memset(c, 0, sizeof(Crypt));
        !            67:                return c;
        !            68:        }
        !            69: 
        !            70:        cryptalloc.free = xalloc(sizeof(Crypt)*conf.nproc);
        !            71:        if(cryptalloc.free == 0)
        !            72:                panic("newcrypt");
        !            73: 
        !            74:        for(c = cryptalloc.free; c < cryptalloc.free+conf.nproc-1; c++)
        !            75:                c->next = c+1;
        !            76: 
        !            77:        palloc.cmembase = (ulong)cryptalloc.free;
        !            78:        palloc.cmemtop = palloc.cmembase+(sizeof(Crypt)*conf.nproc);
        !            79:        unlock(&cryptalloc);
        !            80:        return newcrypt();
        !            81: }
        !            82: 
        !            83: void
        !            84: freecrypt(Crypt *c)
        !            85: {
        !            86:        lock(&cryptalloc);
        !            87:        c->next = cryptalloc.free;
        !            88:        cryptalloc.free = c;
        !            89:        unlock(&cryptalloc);
        !            90: }
        !            91: 
        !            92: /*
        !            93:  *  return the info received in the session message on this channel.
        !            94:  *  if no session message has been exchanged, do it.
        !            95:  */
        !            96: long
        !            97: sysfsession(ulong *arg)
        !            98: {
        !            99:        int i, n;
        !           100:        Chan *c;
        !           101:        Crypt *cp;
        !           102:        Session *s;
        !           103:        Ticketreq tr;
        !           104:        Fcall f;
        !           105:        char buf[MAXMSG];
        !           106: 
        !           107:        validaddr(arg[1], TICKREQLEN, 1);
        !           108:        c = fdtochan(arg[0], OWRITE, 0, 1);
        !           109:        if(waserror()){
        !           110:                close(c);
        !           111:                nexterror();
        !           112:        }
        !           113: 
        !           114:        /* add a session structure to the channel if it has none */
        !           115:        lock(c);
        !           116:        s = c->session;
        !           117:        if(s == 0){
        !           118:                s = malloc(sizeof(Session));
        !           119:                if(s == 0){
        !           120:                        unlock(c);
        !           121:                        error(Enomem);
        !           122:                }
        !           123:                c->session = s;
        !           124:        }
        !           125:        unlock(c);
        !           126: 
        !           127:        qlock(&s->send);
        !           128:        if(s->valid == 0){
        !           129:                /*
        !           130:                 *  Exchange a session message with the server.
        !           131:                 */
        !           132:                for(i = 0; i < CHALLEN; i++)
        !           133:                        s->cchal[i] = nrand(256);
        !           134: 
        !           135:                f.tag = NOTAG;
        !           136:                f.type = Tsession;
        !           137:                memmove(f.chal, s->cchal, CHALLEN);
        !           138:                n = convS2M(&f, buf);
        !           139: 
        !           140:                /*
        !           141:                 *  If an error occurs reading or writing,
        !           142:                 *  this probably is a mount of a mount so turn off
        !           143:                 *  authentication.
        !           144:                 */
        !           145:                if(waserror())
        !           146:                        goto noauth;
        !           147: 
        !           148:                if((*devtab[c->type].write)(c, buf, n, 0) != n)
        !           149:                        error(Esession);
        !           150:                n = (*devtab[c->type].read)(c, buf, sizeof buf, 0);
        !           151:                /* OK is sometimes sent as a Datakit sign-on */
        !           152:                if(n == 2 && buf[0] == 'O' && buf[1] == 'K')
        !           153:                        n = (*devtab[c->type].read)(c, buf, sizeof buf, 0);
        !           154: 
        !           155:                poperror();
        !           156: 
        !           157:                if(convM2S(buf, &f, n) == 0){
        !           158:                        qunlock(&s->send);
        !           159:                        error(Esession);
        !           160:                }
        !           161:                switch(f.type){
        !           162:                case Rsession:
        !           163:                        memmove(s->schal, f.chal, CHALLEN);
        !           164:                        memmove(s->authid, f.authid, NAMELEN);
        !           165:                        memmove(s->authdom, f.authdom, DOMLEN);
        !           166:                        break;
        !           167:                case Rerror:
        !           168:                        qunlock(&s->send);
        !           169:                        error(f.ename);
        !           170:                default:
        !           171:                        qunlock(&s->send);
        !           172:                        error(Esession);
        !           173:                }
        !           174: noauth:
        !           175:                s->valid = 1;
        !           176:        }
        !           177:        qunlock(&s->send);
        !           178: 
        !           179:        /* 
        !           180:         *  If server requires no ticket, or user is "none", or a ticket
        !           181:         *  is already cached, zero the request type
        !           182:         */
        !           183:        tr.type = AuthTreq;
        !           184:        if(strcmp(u->p->user, "none") == 0 || s->authid[0] == 0)
        !           185:                tr.type = 0;
        !           186:        else{
        !           187:                lock(s);
        !           188:                for(cp = s->cache; cp; cp = cp->next)
        !           189:                        if(strcmp(cp->t.cuid, u->p->user) == 0){
        !           190:                                tr.type = 0;
        !           191:                                break;
        !           192:                        }
        !           193:                unlock(s);
        !           194:        }
        !           195: 
        !           196:        /*  create ticket request */
        !           197:        memmove(tr.chal, s->schal, CHALLEN);
        !           198:        memmove(tr.authid, s->authid, NAMELEN);
        !           199:        memmove(tr.authdom, s->authdom, DOMLEN);
        !           200:        memmove(tr.uid, u->p->user, NAMELEN);
        !           201:        memmove(tr.hostid, eve, NAMELEN);
        !           202:        convTR2M(&tr, (char*)arg[1]);
        !           203: 
        !           204:        close(c);
        !           205:        poperror();
        !           206:        return 0;
        !           207: }
        !           208: 
        !           209: /*
        !           210:  *  attach tickets to a session
        !           211:  */
        !           212: long
        !           213: sysfauth(ulong *arg)
        !           214: {
        !           215:        Chan *c;
        !           216:        char *ta;
        !           217:        Session *s;
        !           218:        Crypt *cp, *ncp, **l;
        !           219:        char tbuf[2*TICKETLEN];
        !           220: 
        !           221:        validaddr(arg[1], 2*TICKETLEN, 0);
        !           222:        c = fdtochan(arg[0], OWRITE, 0, 1);
        !           223:        s = c->session;
        !           224:        if(s == 0)
        !           225:                error("fauth must follow fsession");
        !           226:        cp = newcrypt();
        !           227:        if(waserror()){
        !           228:                freecrypt(cp);
        !           229:                nexterror();
        !           230:        }
        !           231: 
        !           232:        /*  ticket supplied, use it */
        !           233:        ta = (char*)arg[1];
        !           234:        memmove(tbuf, ta, 2*TICKETLEN);
        !           235:        convM2T(tbuf, &cp->t, evekey);
        !           236:        if(cp->t.num != AuthTc)
        !           237:                error("bad AuthTc in ticket");
        !           238:        if(strncmp(u->p->user, cp->t.cuid, NAMELEN) != 0)
        !           239:                error("bad uid in ticket");
        !           240:        if(memcmp(cp->t.chal, s->schal, CHALLEN) != 0)
        !           241:                error("bad chal in ticket");
        !           242:        memmove(cp->tbuf, tbuf+TICKETLEN, TICKETLEN);
        !           243: 
        !           244:        /* string onto local list, replace old version */
        !           245:        lock(s);
        !           246:        l = &s->cache;
        !           247:        for(ncp = s->cache; ncp; ncp = *l){
        !           248:                if(strcmp(ncp->t.cuid, u->p->user) == 0){
        !           249:                        *l = ncp->next;
        !           250:                        freecrypt(ncp);
        !           251:                        break;
        !           252:                }
        !           253:                l = &ncp->next;
        !           254:        }
        !           255:        cp->next = s->cache;
        !           256:        s->cache = cp;
        !           257:        unlock(s);
        !           258:        poperror();
        !           259:        return 0;
        !           260: }
        !           261: 
        !           262: /*
        !           263:  *  free a session created by fsession
        !           264:  */
        !           265: void
        !           266: freesession(Session *s)
        !           267: {
        !           268:        Crypt *cp, *next;
        !           269: 
        !           270:        for(cp = s->cache; cp; cp = next) {
        !           271:                next = cp->next;
        !           272:                freecrypt(cp);
        !           273:        }
        !           274:        free(s);
        !           275: }
        !           276: 
        !           277: /*
        !           278:  *  called by mattach() to fill in the Tattach message
        !           279:  */
        !           280: ulong
        !           281: authrequest(Session *s, Fcall *f)
        !           282: {
        !           283:        Crypt *cp;
        !           284:        ulong id, dofree;
        !           285: 
        !           286:        /* no authentication if user is "none" or if no ticket required by remote */
        !           287:        if(s == 0 || s->authid[0] == 0 || strcmp(u->p->user, "none") == 0){
        !           288:                memset(f->ticket, 0, TICKETLEN);
        !           289:                memset(f->auth, 0, AUTHENTLEN);
        !           290:                return 0;
        !           291:        }
        !           292: 
        !           293:        /* look for ticket in cache */
        !           294:        dofree = 0;
        !           295:        lock(s);
        !           296:        for(cp = s->cache; cp; cp = cp->next)
        !           297:                if(strcmp(cp->t.cuid, u->p->user) == 0)
        !           298:                        break;
        !           299: 
        !           300:        id = s->cid++;
        !           301:        unlock(s);
        !           302: 
        !           303:        if(cp == 0){
        !           304:                /*
        !           305:                 *  create a ticket using hostkey, this solves the
        !           306:                 *  chicken and egg problem
        !           307:                 */
        !           308:                cp = newcrypt();
        !           309:                cp->t.num = AuthTs;
        !           310:                memmove(cp->t.chal, s->schal, CHALLEN);
        !           311:                memmove(cp->t.cuid, u->p->user, NAMELEN);
        !           312:                memmove(cp->t.suid, u->p->user, NAMELEN);
        !           313:                memmove(cp->t.key, evekey, DESKEYLEN);
        !           314:                convT2M(&cp->t, f->ticket, evekey);
        !           315:                dofree = 1;
        !           316:        } else
        !           317:                memmove(f->ticket, cp->tbuf, TICKETLEN);
        !           318: 
        !           319:        /* create an authenticator */
        !           320:        memmove(cp->a.chal, s->schal, CHALLEN);
        !           321:        cp->a.num = AuthAc;
        !           322:        cp->a.id = id;
        !           323:        convA2M(&cp->a, f->auth, cp->t.key);
        !           324:        if(dofree)
        !           325:                freecrypt(cp);
        !           326:        return id;
        !           327: }
        !           328: 
        !           329: /*
        !           330:  *  called by mattach() to check the Rattach message
        !           331:  */
        !           332: void
        !           333: authreply(Session *s, ulong id, Fcall *f)
        !           334: {
        !           335:        Crypt *cp;
        !           336: 
        !           337:        if(s == 0)
        !           338:                return;
        !           339: 
        !           340:        lock(s);
        !           341:        for(cp = s->cache; cp; cp = cp->next)
        !           342:                if(strcmp(cp->t.cuid, u->p->user) == 0)
        !           343:                        break;
        !           344:        unlock(s);
        !           345: 
        !           346:        /* we're getting around authentication */
        !           347:        if(s == 0 || cp == 0 || s->authid[0] == 0 || strcmp(u->p->user, "none") == 0)
        !           348:                return;
        !           349: 
        !           350:        convM2A(f->rauth, &cp->a, cp->t.key);
        !           351:        if(cp->a.num != AuthAs){
        !           352:                print("bad encryption type\n");
        !           353:                error("server lies");
        !           354:        }
        !           355:        if(memcmp(cp->a.chal, s->cchal, sizeof(cp->a.chal))){
        !           356:                print("bad returned challenge\n");
        !           357:                error("server lies");
        !           358:        }       
        !           359:        if(cp->a.id != id){
        !           360:                print("bad returned id\n");
        !           361:                error("server lies");
        !           362:        }
        !           363: }
        !           364: 
        !           365: /*
        !           366:  *  called by devcons() for #c/authenticate
        !           367:  *
        !           368:  *  The protocol is
        !           369:  *     1) read ticket request from #c/authenticate
        !           370:  *     2) write ticket+authenticator to #c/authenticate. if it matches
        !           371:  *       the challenge the user is changed to the suid field of the ticket
        !           372:  *     3) read authenticator (to confirm this is the server advertised)
        !           373:  */
        !           374: long
        !           375: authread(Chan *c, char *a, int n)
        !           376: {
        !           377:        Crypt *cp;
        !           378:        int i;
        !           379:        Ticketreq tr;
        !           380: 
        !           381:        if(c->aux == 0){
        !           382:                /*
        !           383:                 *  first read returns a ticket request
        !           384:                 */
        !           385:                if(n != TICKREQLEN)
        !           386:                        error(Ebadarg);
        !           387:                c->aux = newcrypt();
        !           388:                cp = c->aux;
        !           389: 
        !           390:                memset(&tr, 0, sizeof(tr));
        !           391:                tr.type = AuthTreq;
        !           392:                strcpy(tr.hostid, eve);
        !           393:                strcpy(tr.authid, eve);
        !           394:                strcpy(tr.authdom, hostdomain);
        !           395:                strcpy(tr.uid, u->p->user);
        !           396:                for(i = 0; i < CHALLEN; i++)
        !           397:                        tr.chal[i] = nrand(256);
        !           398:                memmove(cp->a.chal, tr.chal, CHALLEN);
        !           399:                convTR2M(&tr, a);
        !           400:        } else {
        !           401:                /*
        !           402:                 *  subsequent read returns an authenticator
        !           403:                 */
        !           404:                if(n != AUTHENTLEN)
        !           405:                        error(Ebadarg);
        !           406:                cp = c->aux;
        !           407: 
        !           408:                cp->a.num = AuthAs;
        !           409:                memmove(cp->a.chal, cp->t.chal, CHALLEN);
        !           410:                cp->a.id = 0;
        !           411:                convA2M(&cp->a, cp->tbuf, cp->t.key);
        !           412:                memmove(a, cp->tbuf, AUTHENTLEN);
        !           413: 
        !           414:                freecrypt(cp);
        !           415:                c->aux = 0;
        !           416:        }
        !           417:        return n;
        !           418: }
        !           419: 
        !           420: long
        !           421: authwrite(Chan *c, char *a, int n)
        !           422: {
        !           423:        Crypt *cp;
        !           424: 
        !           425:        if(n != TICKETLEN+AUTHENTLEN)
        !           426:                error(Ebadarg);
        !           427:        if(c->aux == 0)
        !           428:                error(Ebadarg);
        !           429:        cp = c->aux;
        !           430: 
        !           431:        memmove(cp->tbuf, a, TICKETLEN);
        !           432:        convM2T(cp->tbuf, &cp->t, evekey);
        !           433:        if(cp->t.num != AuthTs || memcmp(cp->a.chal, cp->t.chal, CHALLEN))
        !           434:                error(Eperm);
        !           435: 
        !           436:        memmove(cp->tbuf, a+TICKETLEN, AUTHENTLEN);
        !           437:        convM2A(cp->tbuf, &cp->a, cp->t.key);
        !           438:        if(cp->a.num != AuthAc || memcmp(cp->a.chal, cp->t.chal, CHALLEN))
        !           439:                error(Eperm);
        !           440: 
        !           441:        memmove(u->p->user, cp->t.suid, NAMELEN);
        !           442:        return n;
        !           443: }
        !           444: 
        !           445: /*
        !           446:  *  called by devcons() for #c/authcheck
        !           447:  *
        !           448:  *  a write of a ticket+authenticator [+challenge+id] succeeds if they match
        !           449:  */
        !           450: long
        !           451: authcheck(Chan *c, char *a, int n)
        !           452: {
        !           453:        Crypt *cp;
        !           454:        char *chal;
        !           455:        ulong id;
        !           456: 
        !           457:        if(n != TICKETLEN+AUTHENTLEN && n != TICKETLEN+AUTHENTLEN+CHALLEN+4)
        !           458:                error(Ebadarg);
        !           459:        if(c->aux == 0)
        !           460:                c->aux = newcrypt();
        !           461:        cp = c->aux;
        !           462: 
        !           463:        memmove(cp->tbuf, a, TICKETLEN);
        !           464:        convM2T(cp->tbuf, &cp->t, evekey);
        !           465:        if(cp->t.num != AuthTc)
        !           466:                error(Ebadarg);
        !           467:        if(strcmp(u->p->user, cp->t.cuid))
        !           468:                error(cp->t.cuid);
        !           469: 
        !           470:        memmove(cp->tbuf, a+TICKETLEN, AUTHENTLEN);
        !           471:        convM2A(cp->tbuf, &cp->a, cp->t.key);
        !           472:        if(n == TICKETLEN+AUTHENTLEN+CHALLEN+4){
        !           473:                uchar *p = (uchar *)&a[TICKETLEN+AUTHENTLEN+CHALLEN];
        !           474:                id = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
        !           475:                chal = &a[TICKETLEN+AUTHENTLEN];
        !           476:        }else{
        !           477:                id = 0;
        !           478:                chal = cp->t.chal;
        !           479:        }
        !           480:        if(cp->a.num != AuthAs || memcmp(chal, cp->a.chal, CHALLEN) || cp->a.id != id)
        !           481:                error(Eperm);
        !           482: 
        !           483:        return n;
        !           484: }
        !           485: 
        !           486: /*
        !           487:  *  called by devcons() for #c/authenticator
        !           488:  *
        !           489:  *  a read after a write of a ticket (or ticket+id) returns an authenticator
        !           490:  *  for that ticket.
        !           491:  */
        !           492: long
        !           493: authentwrite(Chan *c, char *a, int n)
        !           494: {
        !           495:        Crypt *cp;
        !           496: 
        !           497:        if(n != TICKETLEN && n != TICKETLEN+4)
        !           498:                error(Ebadarg);
        !           499:        if(c->aux == 0)
        !           500:                c->aux = newcrypt();
        !           501:        cp = c->aux;
        !           502: 
        !           503:        memmove(cp->tbuf, a, TICKETLEN);
        !           504:        convM2T(cp->tbuf, &cp->t, evekey);
        !           505:        if(cp->t.num != AuthTc || strcmp(cp->t.cuid, u->p->user)){
        !           506:                freecrypt(cp);
        !           507:                c->aux = 0;
        !           508:                error(Ebadarg);
        !           509:        }
        !           510:        if(n == TICKETLEN+4){
        !           511:                uchar *p = (uchar *)&a[TICKETLEN];
        !           512:                cp->a.id = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
        !           513:        }else
        !           514:                cp->a.id = 0;
        !           515: 
        !           516:        return n;
        !           517: }
        !           518: long
        !           519: authentread(Chan *c, char *a, int n)
        !           520: {
        !           521:        Crypt *cp;
        !           522: 
        !           523:        cp = c->aux;
        !           524:        if(cp == 0)
        !           525:                error("authenticator read must follow a write");
        !           526: 
        !           527:        cp->a.num = AuthAc;
        !           528:        memmove(cp->a.chal, cp->t.chal, CHALLEN);
        !           529:        convA2M(&cp->a, cp->tbuf, cp->t.key);
        !           530:        memmove(a, cp->tbuf, AUTHENTLEN);
        !           531: 
        !           532:        return n;
        !           533: }
        !           534: 
        !           535: void
        !           536: authclose(Chan *c)
        !           537: {
        !           538:        if(c->aux)
        !           539:                freecrypt(c->aux);
        !           540:        c->aux = 0;
        !           541: }
        !           542: 
        !           543: /*
        !           544:  *  called by devcons() for key device
        !           545:  */
        !           546: long
        !           547: keyread(char *a, int n, long offset)
        !           548: {
        !           549:        if(n<DESKEYLEN || offset != 0)
        !           550:                error(Ebadarg);
        !           551:        if(!cpuserver || !iseve())
        !           552:                error(Eperm);
        !           553:        memmove(a, evekey, DESKEYLEN);
        !           554:        return DESKEYLEN;
        !           555: }
        !           556: 
        !           557: long
        !           558: keywrite(char *a, int n)
        !           559: {
        !           560:        if(n != DESKEYLEN)
        !           561:                error(Ebadarg);
        !           562:        if(!iseve())
        !           563:                error(Eperm);
        !           564:        memmove(evekey, a, DESKEYLEN);
        !           565:        return DESKEYLEN;
        !           566: }
        !           567: 
        !           568: /*
        !           569:  *  called by devcons() for user device
        !           570:  *
        !           571:  *  anyone can become none
        !           572:  */
        !           573: long
        !           574: userwrite(char *a, int n)
        !           575: {
        !           576:        if(n >= NAMELEN)
        !           577:                error(Ebadarg);
        !           578:        if(strcmp(a, "none") != 0)
        !           579:                error(Eperm);
        !           580:        memset(u->p->user, 0, NAMELEN);
        !           581:        strcpy(u->p->user, "none");
        !           582:        return n;
        !           583: }
        !           584: 
        !           585: /*
        !           586:  *  called by devcons() for host owner/domain
        !           587:  *
        !           588:  *  writing hostowner also sets user
        !           589:  */
        !           590: long
        !           591: hostownerwrite(char *a, int n)
        !           592: {
        !           593:        char buf[NAMELEN];
        !           594: 
        !           595:        if(!iseve())
        !           596:                error(Eperm);
        !           597:        if(n >= NAMELEN)
        !           598:                error(Ebadarg);
        !           599:        memset(buf, 0, NAMELEN);
        !           600:        strncpy(buf, a, n);
        !           601:        if(buf[0] == 0)
        !           602:                error(Ebadarg);
        !           603:        memmove(eve, buf, NAMELEN);
        !           604:        memmove(u->p->user, buf, NAMELEN);
        !           605:        return n;
        !           606: }
        !           607: 
        !           608: long
        !           609: hostdomainwrite(char *a, int n)
        !           610: {
        !           611:        char buf[DOMLEN];
        !           612: 
        !           613:        if(!iseve())
        !           614:                error(Eperm);
        !           615:        if(n >= DOMLEN)
        !           616:                error(Ebadarg);
        !           617:        memset(buf, 0, DOMLEN);
        !           618:        strncpy(buf, a, n);
        !           619:        if(buf[0] == 0)
        !           620:                error(Ebadarg);
        !           621:        memmove(hostdomain, buf, DOMLEN);
        !           622:        return n;
        !           623: }
        !           624: 
        !           625: void
        !           626: wipekeys(void)
        !           627: {
        !           628:        memset(evekey, 0, sizeof(evekey));
        !           629:        memset((void*)palloc.cmembase, 0, palloc.cmemtop - palloc.cmembase);
        !           630: }

unix.superglobalmegacorp.com

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