123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002 |
- #include "dat.h"
- static char secstore[100]; /* server name */
- /* bind in the default network and cs */
- static int
- bindnetcs(void)
- {
- int srvfd;
- if(access("/net/tcp", AEXIST) < 0)
- bind("#I", "/net", MBEFORE);
- if(access("/net/cs", AEXIST) < 0){
- if((srvfd = open("#s/cs", ORDWR)) >= 0){
- if(mount(srvfd, -1, "/net", MBEFORE, "") >= 0)
- return 0;
- close(srvfd);
- }
- return -1;
- }
- return 0;
- }
- int
- _authdial(char *net, char *authdom)
- {
- int fd, vanilla;
- vanilla = net==nil || strcmp(net, "/net")==0;
- if(!vanilla || bindnetcs()>=0)
- return authdial(net, authdom);
- /*
- * If we failed to mount /srv/cs, assume that
- * we're still bootstrapping the system and dial
- * the one auth server passed to us on the command line.
- * In normal operation, it is important *not* to do this,
- * because the bootstrap auth server is only good for
- * a single auth domain.
- *
- * The ticket request code should really check the
- * remote authentication domain too.
- */
- /* use the auth sever passed to us as an arg */
- if(authaddr == nil)
- return -1;
- fd = dial(netmkaddr(authaddr, "il", "566"), 0, 0, 0);
- if(fd >= 0)
- return fd;
- return dial(netmkaddr(authaddr, "tcp", "567"), 0, 0, 0);
- }
- int
- secdial(void)
- {
- char *p, buf[80], *f[3];
- int fd, nf;
- p = secstore; /* take it from writehostowner, if set there */
- if(*p == 0) /* else use the authserver */
- p = "$auth";
- if(bindnetcs() >= 0)
- return dial(netmkaddr(p, "net", "secstore"), 0, 0, 0);
- /* translate $auth ourselves.
- * authaddr is something like il!host!566 or tcp!host!567.
- * extract host, accounting for a change of format to something
- * like il!host or tcp!host or host.
- */
- if(strcmp(p, "$auth")==0){
- if(authaddr == nil)
- return -1;
- safecpy(buf, authaddr, sizeof buf);
- nf = getfields(buf, f, nelem(f), 0, "!");
- switch(nf){
- default:
- return -1;
- case 1:
- p = f[0];
- break;
- case 2:
- case 3:
- p = f[1];
- break;
- }
- }
- fd = dial(netmkaddr(p, "tcp", "5356"), 0, 0, 0);
- if(fd >= 0)
- return fd;
- return -1;
- }
- /*
- * prompt user for a key. don't care about memory leaks, runs standalone
- */
- static Attr*
- promptforkey(char *params)
- {
- char *v;
- int fd;
- Attr *a, *attr;
- char *def;
- fd = open("/dev/cons", ORDWR);
- if(fd < 0)
- sysfatal("opening /dev/cons: %r");
- attr = _parseattr(params);
- fprint(fd, "\n!Adding key:");
- for(a=attr; a; a=a->next)
- if(a->type != AttrQuery && a->name[0] != '!')
- fprint(fd, " %q=%q", a->name, a->val);
- fprint(fd, "\n");
- for(a=attr; a; a=a->next){
- v = a->name;
- if(a->type != AttrQuery || v[0]=='!')
- continue;
- def = nil;
- if(strcmp(v, "user") == 0)
- def = getuser();
- a->val = readcons(v, def, 0);
- if(a->val == nil)
- sysfatal("user terminated key input");
- a->type = AttrNameval;
- }
- for(a=attr; a; a=a->next){
- v = a->name;
- if(a->type != AttrQuery || v[0]!='!')
- continue;
- def = nil;
- if(strcmp(v+1, "user") == 0)
- def = getuser();
- a->val = readcons(v+1, def, 1);
- if(a->val == nil)
- sysfatal("user terminated key input");
- a->type = AttrNameval;
- }
- fprint(fd, "!\n");
- close(fd);
- return attr;
- }
- /*
- * send a key to the mounted factotum
- */
- static int
- sendkey(Attr *attr)
- {
- int fd, rv;
- char buf[1024];
- fd = open("/mnt/factotum/ctl", ORDWR);
- if(fd < 0)
- sysfatal("opening /mnt/factotum/ctl: %r");
- rv = fprint(fd, "key %A\n", attr);
- read(fd, buf, sizeof buf);
- close(fd);
- return rv;
- }
- /* askuser */
- void
- askuser(char *params)
- {
- Attr *attr;
- attr = promptforkey(params);
- if(attr == nil)
- sysfatal("no key supplied");
- if(sendkey(attr) < 0)
- sysfatal("sending key to factotum: %r");
- }
- ulong conftaggen;
- int
- canusekey(Fsstate *fss, Key *k)
- {
- int i;
- if(_strfindattr(k->attr, "confirm")){
- for(i=0; i<fss->nconf; i++)
- if(fss->conf[i].key == k)
- return fss->conf[i].canuse;
- if(fss->nconf%16 == 0)
- fss->conf = erealloc(fss->conf, (fss->nconf+16)*(sizeof(fss->conf[0])));
- fss->conf[fss->nconf].key = k;
- k->ref++;
- fss->conf[fss->nconf].canuse = -1;
- fss->conf[fss->nconf].tag = conftaggen++;
- fss->nconf++;
- return -1;
- }
- return 1;
- }
- /* closekey */
- void
- closekey(Key *k)
- {
- if(k == nil)
- return;
- if(--k->ref != 0)
- return;
- if(k->proto && k->proto->closekey)
- (*k->proto->closekey)(k);
- _freeattr(k->attr);
- _freeattr(k->privattr);
- k->attr = (void*)~1;
- k->privattr = (void*)~1;
- k->proto = nil;
- free(k);
- }
- static uchar*
- pstring(uchar *p, uchar *e, char *s)
- {
- uint n;
- if(p == nil)
- return nil;
- if(s == nil)
- s = "";
- n = strlen(s);
- if(p+n+BIT16SZ >= e)
- return nil;
- PBIT16(p, n);
- p += BIT16SZ;
- memmove(p, s, n);
- p += n;
- return p;
- }
- static uchar*
- pcarray(uchar *p, uchar *e, uchar *s, uint n)
- {
- if(p == nil)
- return nil;
- if(s == nil){
- if(n > 0)
- sysfatal("pcarray");
- s = (uchar*)"";
- }
- if(p+n+BIT16SZ >= e)
- return nil;
- PBIT16(p, n);
- p += BIT16SZ;
- memmove(p, s, n);
- p += n;
- return p;
- }
- uchar*
- convAI2M(AuthInfo *ai, uchar *p, int n)
- {
- uchar *e = p+n;
- p = pstring(p, e, ai->cuid);
- p = pstring(p, e, ai->suid);
- p = pstring(p, e, ai->cap);
- p = pcarray(p, e, ai->secret, ai->nsecret);
- return p;
- }
- int
- failure(Fsstate *s, char *fmt, ...)
- {
- char e[ERRMAX];
- va_list arg;
- if(fmt == nil)
- rerrstr(s->err, sizeof(s->err));
- else {
- va_start(arg, fmt);
- snprint(e, sizeof e, fmt, arg);
- va_end(arg);
- strecpy(s->err, s->err+sizeof(s->err), e);
- errstr(e, sizeof e);
- }
- flog("%d: failure %s", s->seqnum, s->err);
- return RpcFailure;
- }
- static int
- hasqueries(Attr *a)
- {
- for(; a; a=a->next)
- if(a->type == AttrQuery)
- return 1;
- return 0;
- }
- char *ignored[] = {
- "role",
- "disabled",
- };
- static int
- ignoreattr(char *s)
- {
- int i;
- for(i=0; i<nelem(ignored); i++)
- if(strcmp(ignored[i], s)==0)
- return 1;
- return 0;
- }
- Keyinfo*
- mkkeyinfo(Keyinfo *k, Fsstate *fss, Attr *attr)
- {
- memset(k, 0, sizeof *k);
- k->fss = fss;
- k->user = fss->sysuser;
- if(attr)
- k->attr = attr;
- else
- k->attr = fss->attr;
- return k;
- }
- int
- findkey(Key **ret, Keyinfo *ki, char *fmt, ...)
- {
- int i, s, nmatch;
- char buf[1024], *p, *who;
- va_list arg;
- Attr *a, *attr0, *attr1, *attr2, *attr3, **l;
- Key *k;
- *ret = nil;
- who = ki->user;
- attr0 = ki->attr;
- if(fmt){
- va_start(arg, fmt);
- vseprint(buf, buf+sizeof buf, fmt, arg);
- va_end(arg);
- attr1 = _parseattr(buf);
- }else
- attr1 = nil;
- if(who && strcmp(who, owner) == 0)
- who = nil;
- if(who){
- snprint(buf, sizeof buf, "owner=%q", who);
- attr2 = _parseattr(buf);
- attr3 = _parseattr("owner=*");
- }else
- attr2 = attr3 = nil;
- p = _strfindattr(attr0, "proto");
- if(p == nil)
- p = _strfindattr(attr1, "proto");
- if(p && findproto(p) == nil){
- werrstr("unknown protocol %s", p);
- _freeattr(attr1);
- _freeattr(attr2);
- _freeattr(attr3);
- return failure(ki->fss, nil);
- }
- nmatch = 0;
- for(i=0; i<ring->nkey; i++){
- k = ring->key[i];
- if(_strfindattr(k->attr, "disabled") && !ki->usedisabled)
- continue;
- if(matchattr(attr0, k->attr, k->privattr) && matchattr(attr1, k->attr, k->privattr)){
- /* check ownership */
- if(!matchattr(attr2, k->attr, nil) && !matchattr(attr3, k->attr, nil))
- continue;
- if(nmatch++ < ki->skip)
- continue;
- if(!ki->noconf){
- switch(canusekey(ki->fss, k)){
- case -1:
- _freeattr(attr1);
- return RpcConfirm;
- case 0:
- continue;
- case 1:
- break;
- }
- }
- _freeattr(attr1);
- _freeattr(attr2);
- _freeattr(attr3);
- k->ref++;
- *ret = k;
- return RpcOk;
- }
- }
- flog("%d: no key matches %A %A %A %A", ki->fss->seqnum, attr0, attr1, attr2, attr3);
- werrstr("no key matches %A %A", attr0, attr1);
- _freeattr(attr2);
- _freeattr(attr3);
- s = RpcFailure;
- if(askforkeys && who==nil && (hasqueries(attr0) || hasqueries(attr1))){
- if(nmatch == 0){
- attr0 = _copyattr(attr0);
- for(l=&attr0; *l; l=&(*l)->next)
- ;
- *l = attr1;
- for(l=&attr0; *l; ){
- if(ignoreattr((*l)->name)){
- a = *l;
- *l = (*l)->next;
- a->next = nil;
- _freeattr(a);
- }else
- l = &(*l)->next;
- }
- attr0 = sortattr(attr0);
- snprint(ki->fss->keyinfo, sizeof ki->fss->keyinfo, "%A", attr0);
- _freeattr(attr0);
- attr1 = nil; /* attr1 was linked to attr0 */
- }else
- ki->fss->keyinfo[0] = '\0';
- s = RpcNeedkey;
- }
- _freeattr(attr1);
- if(s == RpcFailure)
- return failure(ki->fss, nil); /* loads error string */
- return s;
- }
- int
- findp9authkey(Key **k, Fsstate *fss)
- {
- char *dom;
- Keyinfo ki;
- /*
- * We don't use fss->attr here because we don't
- * care about what the user name is set to, for instance.
- */
- mkkeyinfo(&ki, fss, nil);
- ki.attr = nil;
- ki.user = nil;
- if(dom = _strfindattr(fss->attr, "dom"))
- return findkey(k, &ki, "proto=p9sk1 dom=%q role=server user?", dom);
- else
- return findkey(k, &ki, "proto=p9sk1 role=server dom? user?");
- }
- Proto*
- findproto(char *name)
- {
- int i;
- for(i=0; prototab[i]; i++)
- if(strcmp(name, prototab[i]->name) == 0)
- return prototab[i];
- return nil;
- }
- char*
- getnvramkey(int flag, char **secstorepw)
- {
- char *s;
- Nvrsafe safe;
- char spw[CONFIGLEN+1];
- int i;
- memset(&safe, 0, sizeof safe);
- /*
- * readnvram can return -1 meaning nvram wasn't written,
- * but safe still holds good data.
- */
- if(readnvram(&safe, flag)<0 && safe.authid[0]==0)
- return nil;
- /*
- * we're using the config area to hold the secstore
- * password. if there's anything there, return it.
- */
- memmove(spw, safe.config, CONFIGLEN);
- spw[CONFIGLEN] = 0;
- if(spw[0] != 0)
- *secstorepw = estrdup(spw);
- /*
- * only use nvram key if it is non-zero
- */
- for(i = 0; i < DESKEYLEN; i++)
- if(safe.machkey[i] != 0)
- break;
- if(i == DESKEYLEN)
- return nil;
- s = emalloc(512);
- fmtinstall('H', encodefmt);
- sprint(s, "key proto=p9sk1 user=%q dom=%q !hex=%.*H !password=______",
- safe.authid, safe.authdom, DESKEYLEN, safe.machkey);
- writehostowner(safe.authid);
- return s;
- }
- int
- isclient(char *role)
- {
- if(role == nil){
- werrstr("role not specified");
- return -1;
- }
- if(strcmp(role, "server") == 0)
- return 0;
- if(strcmp(role, "client") == 0)
- return 1;
- werrstr("unknown role %q", role);
- return -1;
- }
- static int
- hasname(Attr *a0, Attr *a1, char *name)
- {
- return _findattr(a0, name) || _findattr(a1, name);
- }
- static int
- hasnameval(Attr *a0, Attr *a1, char *name, char *val)
- {
- Attr *a;
- for(a=_findattr(a0, name); a; a=_findattr(a->next, name))
- if(strcmp(a->val, val) == 0)
- return 1;
- for(a=_findattr(a1, name); a; a=_findattr(a->next, name))
- if(strcmp(a->val, val) == 0)
- return 1;
- return 0;
- }
- int
- matchattr(Attr *pat, Attr *a0, Attr *a1)
- {
- int type;
- for(; pat; pat=pat->next){
- type = pat->type;
- if(ignoreattr(pat->name))
- type = AttrDefault;
- switch(type){
- case AttrQuery: /* name=something be present */
- if(!hasname(a0, a1, pat->name))
- return 0;
- break;
- case AttrNameval: /* name=val must be present */
- if(!hasnameval(a0, a1, pat->name, pat->val))
- return 0;
- break;
- case AttrDefault: /* name=val must be present if name=anything is present */
- if(hasname(a0, a1, pat->name) && !hasnameval(a0, a1, pat->name, pat->val))
- return 0;
- break;
- }
- }
- return 1;
- }
- void
- memrandom(void *p, int n)
- {
- uchar *cp;
- for(cp = (uchar*)p; n > 0; n--)
- *cp++ = fastrand();
- }
- /*
- * keep caphash fd open since opens of it could be disabled
- */
- static int caphashfd;
- void
- initcap(void)
- {
- caphashfd = open("#¤/caphash", OWRITE);
- // if(caphashfd < 0)
- // fprint(2, "%s: opening #¤/caphash: %r\n", argv0);
- }
- /*
- * create a change uid capability
- */
- char*
- mkcap(char *from, char *to)
- {
- uchar rand[20];
- char *cap;
- char *key;
- int nfrom, nto;
- uchar hash[SHA1dlen];
- if(caphashfd < 0)
- return nil;
- /* create the capability */
- nto = strlen(to);
- nfrom = strlen(from);
- cap = emalloc(nfrom+1+nto+1+sizeof(rand)*3+1);
- sprint(cap, "%s@%s", from, to);
- memrandom(rand, sizeof(rand));
- key = cap+nfrom+1+nto+1;
- enc64(key, sizeof(rand)*3, rand, sizeof(rand));
- /* hash the capability */
- hmac_sha1((uchar*)cap, strlen(cap), (uchar*)key, strlen(key), hash, nil);
- /* give the kernel the hash */
- key[-1] = '@';
- if(write(caphashfd, hash, SHA1dlen) < 0){
- free(cap);
- return nil;
- }
- return cap;
- }
- int
- phaseerror(Fsstate *s, char *op)
- {
- char tmp[32];
- werrstr("protocol phase error: %s in state %s", op, phasename(s, s->phase, tmp));
- return RpcPhase;
- }
- char*
- phasename(Fsstate *fss, int phase, char *tmp)
- {
- char *name;
- if(fss->phase == Broken)
- name = "Broken";
- else if(phase == Established)
- name = "Established";
- else if(phase == Notstarted)
- name = "Notstarted";
- else if(phase < 0 || phase >= fss->maxphase
- || (name = fss->phasename[phase]) == nil){
- sprint(tmp, "%d", phase);
- name = tmp;
- }
- return name;
- }
- static int
- outin(char *prompt, char *def, int len)
- {
- char *s;
- s = readcons(prompt, def, 0);
- if(s == nil)
- return -1;
- if(s == nil)
- sysfatal("s==nil???");
- strncpy(def, s, len);
- def[len-1] = 0;
- free(s);
- return strlen(def);
- }
- /*
- * get host owner and set it
- */
- void
- promptforhostowner(void)
- {
- char owner[64], *p;
- /* hack for bitsy; can't prompt during boot */
- if(p = getenv("user")){
- writehostowner(p);
- free(p);
- return;
- }
- free(p);
- strcpy(owner, "none");
- do{
- outin("user", owner, sizeof(owner));
- } while(*owner == 0);
- writehostowner(owner);
- }
- char*
- estrappend(char *s, char *fmt, ...)
- {
- char *t;
- va_list arg;
- va_start(arg, fmt);
- t = vsmprint(fmt, arg);
- if(t == nil)
- sysfatal("out of memory");
- va_end(arg);
- s = erealloc(s, strlen(s)+strlen(t)+1);
- strcat(s, t);
- free(t);
- return s;
- }
- /*
- * prompt for a string with a possible default response
- */
- char*
- readcons(char *prompt, char *def, int raw)
- {
- int fdin, fdout, ctl, n;
- char line[10];
- char *s;
- fdin = open("/dev/cons", OREAD);
- if(fdin < 0)
- fdin = 0;
- fdout = open("/dev/cons", OWRITE);
- if(fdout < 0)
- fdout = 1;
- if(def != nil)
- fprint(fdout, "%s[%s]: ", prompt, def);
- else
- fprint(fdout, "%s: ", prompt);
- if(raw){
- ctl = open("/dev/consctl", OWRITE);
- if(ctl >= 0)
- write(ctl, "rawon", 5);
- } else
- ctl = -1;
- s = estrdup("");
- for(;;){
- n = read(fdin, line, 1);
- if(n == 0){
- Error:
- close(fdin);
- close(fdout);
- if(ctl >= 0)
- close(ctl);
- free(s);
- return nil;
- }
- if(n < 0)
- goto Error;
- if(line[0] == 0x7f)
- goto Error;
- if(n == 0 || line[0] == '\n' || line[0] == '\r'){
- if(raw){
- write(ctl, "rawoff", 6);
- write(fdout, "\n", 1);
- }
- close(ctl);
- close(fdin);
- close(fdout);
- if(*s == 0 && def != nil)
- s = estrappend(s, "%s", def);
- return s;
- }
- if(line[0] == '\b'){
- if(strlen(s) > 0)
- s[strlen(s)-1] = 0;
- } else if(line[0] == 0x15) { /* ^U: line kill */
- if(def != nil)
- fprint(fdout, "\n%s[%s]: ", prompt, def);
- else
- fprint(fdout, "\n%s: ", prompt);
-
- s[0] = 0;
- } else {
- s = estrappend(s, "%c", line[0]);
- }
- }
- }
- /*
- * Insert a key into the keyring.
- * If the public attributes are identical to some other key, replace that one.
- */
- int
- replacekey(Key *kn, int before)
- {
- int i;
- Key *k;
- for(i=0; i<ring->nkey; i++){
- k = ring->key[i];
- if(matchattr(kn->attr, k->attr, nil) && matchattr(k->attr, kn->attr, nil)){
- closekey(k);
- kn->ref++;
- ring->key[i] = kn;
- return 0;
- }
- }
- if(ring->nkey%16 == 0)
- ring->key = erealloc(ring->key, (ring->nkey+16)*sizeof(ring->key[0]));
- kn->ref++;
- if(before){
- memmove(ring->key+1, ring->key, ring->nkey*sizeof ring->key[0]);
- ring->key[0] = kn;
- ring->nkey++;
- }else
- ring->key[ring->nkey++] = kn;
- return 0;
- }
- char*
- safecpy(char *to, char *from, int n)
- {
- memset(to, 0, n);
- if(n == 1)
- return to;
- if(from==nil)
- sysfatal("safecpy called with from==nil, pc=%#p\n",
- getcallerpc(&to));
- strncpy(to, from, n-1);
- return to;
- }
- Attr*
- setattr(Attr *a, char *fmt, ...)
- {
- char buf[1024];
- va_list arg;
- Attr *b;
- va_start(arg, fmt);
- vseprint(buf, buf+sizeof buf, fmt, arg);
- va_end(arg);
- b = _parseattr(buf);
- a = setattrs(a, b);
- setmalloctag(a, getcallerpc(&a));
- _freeattr(b);
- return a;
- }
- /*
- * add attributes in list b to list a. If any attributes are in
- * both lists, replace those in a by those in b.
- */
- Attr*
- setattrs(Attr *a, Attr *b)
- {
- int found;
- Attr **l, *freea;
- for(; b; b=b->next){
- found = 0;
- for(l=&a; *l; ){
- if(strcmp(b->name, (*l)->name) == 0){
- switch(b->type){
- case AttrNameval:
- if(!found){
- found = 1;
- free((*l)->val);
- (*l)->val = estrdup(b->val);
- (*l)->type = AttrNameval;
- l = &(*l)->next;
- }else{
- freea = *l;
- *l = (*l)->next;
- freea->next = nil;
- _freeattr(freea);
- }
- break;
- case AttrQuery:
- goto continue2;
- }
- }else
- l = &(*l)->next;
- }
- if(found == 0){
- *l = _mkattr(b->type, b->name, b->val, nil);
- setmalloctag(*l, getcallerpc(&a));
- }
- continue2:;
- }
- return a;
- }
- void
- setmalloctaghere(void *v)
- {
- setmalloctag(v, getcallerpc(&v));
- }
- Attr*
- sortattr(Attr *a)
- {
- int i;
- Attr *anext, *a0, *a1, **l;
- if(a == nil || a->next == nil)
- return a;
- /* cut list in halves */
- a0 = nil;
- a1 = nil;
- i = 0;
- for(; a; a=anext){
- anext = a->next;
- if(i++%2){
- a->next = a0;
- a0 = a;
- }else{
- a->next = a1;
- a1 = a;
- }
- }
- /* sort */
- a0 = sortattr(a0);
- a1 = sortattr(a1);
- /* merge */
- l = &a;
- while(a0 || a1){
- if(a1==nil){
- anext = a0;
- a0 = a0->next;
- }else if(a0==nil){
- anext = a1;
- a1 = a1->next;
- }else if(strcmp(a0->name, a1->name) < 0){
- anext = a0;
- a0 = a0->next;
- }else{
- anext = a1;
- a1 = a1->next;
- }
- *l = anext;
- l = &(*l)->next;
- }
- *l = nil;
- return a;
- }
- int
- toosmall(Fsstate *fss, uint n)
- {
- fss->rpc.nwant = n;
- return RpcToosmall;
- }
- void
- writehostowner(char *owner)
- {
- int fd;
- char *s;
- if((s = strchr(owner,'@')) != nil){
- *s++ = 0;
- strncpy(secstore, s, (sizeof secstore)-1);
- }
- fd = open("#c/hostowner", OWRITE);
- if(fd >= 0){
- if(fprint(fd, "%s", owner) < 0)
- fprint(2, "factotum: setting #c/hostowner to %q: %r\n",
- owner);
- close(fd);
- }
- }
- int
- attrnamefmt(Fmt *fmt)
- {
- char *b, buf[1024], *ebuf;
- Attr *a;
- ebuf = buf+sizeof buf;
- b = buf;
- strcpy(buf, " ");
- for(a=va_arg(fmt->args, Attr*); a; a=a->next){
- if(a->name == nil)
- continue;
- b = seprint(b, ebuf, " %q?", a->name);
- }
- return fmtstrcpy(fmt, buf+1);
- }
- void
- disablekey(Key *k)
- {
- Attr *a;
- if(sflag) /* not on servers */
- return;
- for(a=k->attr; a; a=a->next){
- if(a->type==AttrNameval && strcmp(a->name, "disabled") == 0)
- return;
- if(a->next == nil)
- break;
- }
- if(a)
- a->next = _mkattr(AttrNameval, "disabled", "by.factotum", nil);
- else
- k->attr = _mkattr(AttrNameval, "disabled", "by.factotum", nil); /* not reached: always a proto attribute */
- }
|