1 #include "dat.h"
2
3 static char secstore[100]; /* server name */
4
5 /* bind in the default network and cs */
6 static int
bindnetcs(void)7 bindnetcs(void)
8 {
9 int srvfd;
10
11 if(access("/net/tcp", AEXIST) < 0)
12 bind("#I", "/net", MBEFORE);
13
14 if(access("/net/cs", AEXIST) < 0){
15 if((srvfd = open("#s/cs", ORDWR)) >= 0){
16 if(mount(srvfd, -1, "/net", MBEFORE, "") >= 0)
17 return 0;
18 close(srvfd);
19 }
20 return -1;
21 }
22 return 0;
23 }
24
25 int
_authdial(char * net,char * authdom)26 _authdial(char *net, char *authdom)
27 {
28 int fd, vanilla;
29
30 vanilla = net==nil || strcmp(net, "/net")==0;
31
32 if(!vanilla || bindnetcs()>=0)
33 return authdial(net, authdom);
34
35 /*
36 * If we failed to mount /srv/cs, assume that
37 * we're still bootstrapping the system and dial
38 * the one auth server passed to us on the command line.
39 * In normal operation, it is important *not* to do this,
40 * because the bootstrap auth server is only good for
41 * a single auth domain.
42 *
43 * The ticket request code should really check the
44 * remote authentication domain too.
45 */
46
47 /* use the auth server passed to us as an arg */
48 if(authaddr == nil)
49 return -1;
50 fd = dial(netmkaddr(authaddr, "tcp", "567"), 0, 0, 0);
51 if(fd >= 0)
52 return fd;
53 return dial(netmkaddr(authaddr, "il", "566"), 0, 0, 0);
54 }
55
56 int
secdial(void)57 secdial(void)
58 {
59 char *p, buf[80], *f[3];
60 int fd, nf;
61
62 p = secstore; /* take it from writehostowner, if set there */
63 if(*p == 0) /* else use the authserver */
64 p = "$auth";
65
66 if(bindnetcs() >= 0)
67 return dial(netmkaddr(p, "net", "secstore"), 0, 0, 0);
68
69 /* translate $auth ourselves.
70 * authaddr is something like il!host!566 or tcp!host!567.
71 * extract host, accounting for a change of format to something
72 * like il!host or tcp!host or host.
73 */
74 if(strcmp(p, "$auth")==0){
75 if(authaddr == nil)
76 return -1;
77 safecpy(buf, authaddr, sizeof buf);
78 nf = getfields(buf, f, nelem(f), 0, "!");
79 switch(nf){
80 default:
81 return -1;
82 case 1:
83 p = f[0];
84 break;
85 case 2:
86 case 3:
87 p = f[1];
88 break;
89 }
90 }
91 fd = dial(netmkaddr(p, "tcp", "5356"), 0, 0, 0);
92 if(fd >= 0)
93 return fd;
94 return -1;
95 }
96 /*
97 * prompt user for a key. don't care about memory leaks, runs standalone
98 */
99 static Attr*
promptforkey(char * params)100 promptforkey(char *params)
101 {
102 char *v;
103 int fd;
104 Attr *a, *attr;
105 char *def;
106
107 fd = open("/dev/cons", ORDWR);
108 if(fd < 0)
109 sysfatal("opening /dev/cons: %r");
110
111 attr = _parseattr(params);
112 fprint(fd, "\n!Adding key:");
113 for(a=attr; a; a=a->next)
114 if(a->type != AttrQuery && a->name[0] != '!')
115 fprint(fd, " %q=%q", a->name, a->val);
116 fprint(fd, "\n");
117
118 for(a=attr; a; a=a->next){
119 v = a->name;
120 if(a->type != AttrQuery || v[0]=='!')
121 continue;
122 def = nil;
123 if(strcmp(v, "user") == 0)
124 def = getuser();
125 a->val = readcons(v, def, 0);
126 if(a->val == nil)
127 sysfatal("user terminated key input");
128 a->type = AttrNameval;
129 }
130 for(a=attr; a; a=a->next){
131 v = a->name;
132 if(a->type != AttrQuery || v[0]!='!')
133 continue;
134 def = nil;
135 if(strcmp(v+1, "user") == 0)
136 def = getuser();
137 a->val = readcons(v+1, def, 1);
138 if(a->val == nil)
139 sysfatal("user terminated key input");
140 a->type = AttrNameval;
141 }
142 fprint(fd, "!\n");
143 close(fd);
144 return attr;
145 }
146
147 /*
148 * send a key to the mounted factotum
149 */
150 static int
sendkey(Attr * attr)151 sendkey(Attr *attr)
152 {
153 int fd, rv;
154 char buf[1024];
155
156 fd = open("/mnt/factotum/ctl", ORDWR);
157 if(fd < 0)
158 sysfatal("opening /mnt/factotum/ctl: %r");
159 rv = fprint(fd, "key %A\n", attr);
160 read(fd, buf, sizeof buf);
161 close(fd);
162 return rv;
163 }
164
165 /* askuser */
166 void
askuser(char * params)167 askuser(char *params)
168 {
169 Attr *attr;
170
171 attr = promptforkey(params);
172 if(attr == nil)
173 sysfatal("no key supplied");
174 if(sendkey(attr) < 0)
175 sysfatal("sending key to factotum: %r");
176 }
177
178 ulong conftaggen;
179 int
canusekey(Fsstate * fss,Key * k)180 canusekey(Fsstate *fss, Key *k)
181 {
182 int i;
183
184 if(_strfindattr(k->attr, "confirm")){
185 for(i=0; i<fss->nconf; i++)
186 if(fss->conf[i].key == k)
187 return fss->conf[i].canuse;
188 if(fss->nconf%16 == 0)
189 fss->conf = erealloc(fss->conf, (fss->nconf+16)*(sizeof(fss->conf[0])));
190 fss->conf[fss->nconf].key = k;
191 k->ref++;
192 fss->conf[fss->nconf].canuse = -1;
193 fss->conf[fss->nconf].tag = conftaggen++;
194 fss->nconf++;
195 return -1;
196 }
197 return 1;
198 }
199
200 /* closekey */
201 void
closekey(Key * k)202 closekey(Key *k)
203 {
204 if(k == nil)
205 return;
206 if(--k->ref != 0)
207 return;
208 if(k->proto && k->proto->closekey)
209 (*k->proto->closekey)(k);
210 _freeattr(k->attr);
211 _freeattr(k->privattr);
212 k->attr = (void*)~1;
213 k->privattr = (void*)~1;
214 k->proto = nil;
215 free(k);
216 }
217
218 static uchar*
pstring(uchar * p,uchar * e,char * s)219 pstring(uchar *p, uchar *e, char *s)
220 {
221 uint n;
222
223 if(p == nil)
224 return nil;
225 if(s == nil)
226 s = "";
227 n = strlen(s);
228 if(p+n+BIT16SZ >= e)
229 return nil;
230 PBIT16(p, n);
231 p += BIT16SZ;
232 memmove(p, s, n);
233 p += n;
234 return p;
235 }
236
237 static uchar*
pcarray(uchar * p,uchar * e,uchar * s,uint n)238 pcarray(uchar *p, uchar *e, uchar *s, uint n)
239 {
240 if(p == nil)
241 return nil;
242 if(s == nil){
243 if(n > 0)
244 sysfatal("pcarray");
245 s = (uchar*)"";
246 }
247 if(p+n+BIT16SZ >= e)
248 return nil;
249 PBIT16(p, n);
250 p += BIT16SZ;
251 memmove(p, s, n);
252 p += n;
253 return p;
254 }
255
256 uchar*
convAI2M(AuthInfo * ai,uchar * p,int n)257 convAI2M(AuthInfo *ai, uchar *p, int n)
258 {
259 uchar *e = p+n;
260
261 p = pstring(p, e, ai->cuid);
262 p = pstring(p, e, ai->suid);
263 p = pstring(p, e, ai->cap);
264 p = pcarray(p, e, ai->secret, ai->nsecret);
265 return p;
266 }
267
268 int
failure(Fsstate * s,char * fmt,...)269 failure(Fsstate *s, char *fmt, ...)
270 {
271 char e[ERRMAX];
272 va_list arg;
273
274 if(fmt == nil)
275 rerrstr(s->err, sizeof(s->err));
276 else {
277 va_start(arg, fmt);
278 vsnprint(e, sizeof e, fmt, arg);
279 va_end(arg);
280 strecpy(s->err, s->err+sizeof(s->err), e);
281 werrstr(e);
282 }
283 flog("%d: failure %s", s->seqnum, s->err);
284 return RpcFailure;
285 }
286
287 static int
hasqueries(Attr * a)288 hasqueries(Attr *a)
289 {
290 for(; a; a=a->next)
291 if(a->type == AttrQuery)
292 return 1;
293 return 0;
294 }
295
296 char *ignored[] = {
297 "role",
298 "disabled",
299 };
300
301 static int
ignoreattr(char * s)302 ignoreattr(char *s)
303 {
304 int i;
305
306 for(i=0; i<nelem(ignored); i++)
307 if(strcmp(ignored[i], s)==0)
308 return 1;
309 return 0;
310 }
311
312 Keyinfo*
mkkeyinfo(Keyinfo * k,Fsstate * fss,Attr * attr)313 mkkeyinfo(Keyinfo *k, Fsstate *fss, Attr *attr)
314 {
315 memset(k, 0, sizeof *k);
316 k->fss = fss;
317 k->user = fss->sysuser;
318 if(attr)
319 k->attr = attr;
320 else
321 k->attr = fss->attr;
322 return k;
323 }
324
325 int
findkey(Key ** ret,Keyinfo * ki,char * fmt,...)326 findkey(Key **ret, Keyinfo *ki, char *fmt, ...)
327 {
328 int i, s, nmatch;
329 char buf[1024], *p, *who;
330 va_list arg;
331 Attr *a, *attr0, *attr1, *attr2, *attr3, **l;
332 Key *k;
333
334 *ret = nil;
335
336 who = ki->user;
337 attr0 = ki->attr;
338 if(fmt){
339 va_start(arg, fmt);
340 vseprint(buf, buf+sizeof buf, fmt, arg);
341 va_end(arg);
342 attr1 = _parseattr(buf);
343 }else
344 attr1 = nil;
345
346 if(who && strcmp(who, owner) == 0)
347 who = nil;
348
349 if(who){
350 snprint(buf, sizeof buf, "owner=%q", who);
351 attr2 = _parseattr(buf);
352 attr3 = _parseattr("owner=*");
353 }else
354 attr2 = attr3 = nil;
355
356 p = _strfindattr(attr0, "proto");
357 if(p == nil)
358 p = _strfindattr(attr1, "proto");
359 if(p && findproto(p) == nil){
360 werrstr("unknown protocol %s", p);
361 _freeattr(attr1);
362 _freeattr(attr2);
363 _freeattr(attr3);
364 return failure(ki->fss, nil);
365 }
366
367 nmatch = 0;
368 for(i=0; i<ring->nkey; i++){
369 k = ring->key[i];
370 if(_strfindattr(k->attr, "disabled") && !ki->usedisabled)
371 continue;
372 if(matchattr(attr0, k->attr, k->privattr) && matchattr(attr1, k->attr, k->privattr)){
373 /* check ownership */
374 if(!matchattr(attr2, k->attr, nil) && !matchattr(attr3, k->attr, nil))
375 continue;
376 if(nmatch++ < ki->skip)
377 continue;
378 if(!ki->noconf){
379 switch(canusekey(ki->fss, k)){
380 case -1:
381 _freeattr(attr1);
382 return RpcConfirm;
383 case 0:
384 continue;
385 case 1:
386 break;
387 }
388 }
389 _freeattr(attr1);
390 _freeattr(attr2);
391 _freeattr(attr3);
392 k->ref++;
393 *ret = k;
394 return RpcOk;
395 }
396 }
397 flog("%d: no key matches %A %A %A %A", ki->fss->seqnum, attr0, attr1, attr2, attr3);
398 werrstr("no key matches %A %A", attr0, attr1);
399 _freeattr(attr2);
400 _freeattr(attr3);
401 s = RpcFailure;
402 if(askforkeys && who==nil && (hasqueries(attr0) || hasqueries(attr1))){
403 if(nmatch == 0){
404 attr0 = _copyattr(attr0);
405 for(l=&attr0; *l; l=&(*l)->next)
406 ;
407 *l = attr1;
408 for(l=&attr0; *l; ){
409 if(ignoreattr((*l)->name)){
410 a = *l;
411 *l = (*l)->next;
412 a->next = nil;
413 _freeattr(a);
414 }else
415 l = &(*l)->next;
416 }
417 attr0 = sortattr(attr0);
418 snprint(ki->fss->keyinfo, sizeof ki->fss->keyinfo, "%A", attr0);
419 _freeattr(attr0);
420 attr1 = nil; /* attr1 was linked to attr0 */
421 }else
422 ki->fss->keyinfo[0] = '\0';
423 s = RpcNeedkey;
424 }
425 _freeattr(attr1);
426 if(s == RpcFailure)
427 return failure(ki->fss, nil); /* loads error string */
428 return s;
429 }
430
431 int
findp9authkey(Key ** k,Fsstate * fss)432 findp9authkey(Key **k, Fsstate *fss)
433 {
434 char *dom;
435 Keyinfo ki;
436
437 /*
438 * We don't use fss->attr here because we don't
439 * care about what the user name is set to, for instance.
440 */
441 mkkeyinfo(&ki, fss, nil);
442 ki.attr = nil;
443 ki.user = nil;
444 if(dom = _strfindattr(fss->attr, "dom"))
445 return findkey(k, &ki, "proto=p9sk1 dom=%q role=server user?", dom);
446 else
447 return findkey(k, &ki, "proto=p9sk1 role=server dom? user?");
448 }
449
450 Proto*
findproto(char * name)451 findproto(char *name)
452 {
453 int i;
454
455 for(i=0; prototab[i]; i++)
456 if(strcmp(name, prototab[i]->name) == 0)
457 return prototab[i];
458 return nil;
459 }
460
461 char*
getnvramkey(int flag,char ** secstorepw)462 getnvramkey(int flag, char **secstorepw)
463 {
464 char *s;
465 Nvrsafe safe;
466 char spw[CONFIGLEN+1];
467 int i;
468
469 memset(&safe, 0, sizeof safe);
470 /*
471 * readnvram can return -1 meaning nvram wasn't written,
472 * but safe still holds good data.
473 */
474 if(readnvram(&safe, flag)<0 && safe.authid[0]==0)
475 return nil;
476
477 /*
478 * we're using the config area to hold the secstore
479 * password. if there's anything there, return it.
480 */
481 memmove(spw, safe.config, CONFIGLEN);
482 spw[CONFIGLEN] = 0;
483 if(spw[0] != 0)
484 *secstorepw = estrdup(spw);
485
486 /*
487 * only use nvram key if it is non-zero
488 */
489 for(i = 0; i < DESKEYLEN; i++)
490 if(safe.machkey[i] != 0)
491 break;
492 if(i == DESKEYLEN)
493 return nil;
494
495 s = emalloc(512);
496 fmtinstall('H', encodefmt);
497 snprint(s, 512, "key proto=p9sk1 user=%q dom=%q !hex=%.*H !password=______",
498 safe.authid, safe.authdom, DESKEYLEN, safe.machkey);
499 writehostowner(safe.authid);
500
501 return s;
502 }
503
504 int
isclient(char * role)505 isclient(char *role)
506 {
507 if(role == nil){
508 werrstr("role not specified");
509 return -1;
510 }
511 if(strcmp(role, "server") == 0)
512 return 0;
513 if(strcmp(role, "client") == 0)
514 return 1;
515 werrstr("unknown role %q", role);
516 return -1;
517 }
518
519 static int
hasname(Attr * a0,Attr * a1,char * name)520 hasname(Attr *a0, Attr *a1, char *name)
521 {
522 return _findattr(a0, name) || _findattr(a1, name);
523 }
524
525 static int
hasnameval(Attr * a0,Attr * a1,char * name,char * val)526 hasnameval(Attr *a0, Attr *a1, char *name, char *val)
527 {
528 Attr *a;
529
530 for(a=_findattr(a0, name); a; a=_findattr(a->next, name))
531 if(strcmp(a->val, val) == 0)
532 return 1;
533 for(a=_findattr(a1, name); a; a=_findattr(a->next, name))
534 if(strcmp(a->val, val) == 0)
535 return 1;
536 return 0;
537 }
538
539 int
matchattr(Attr * pat,Attr * a0,Attr * a1)540 matchattr(Attr *pat, Attr *a0, Attr *a1)
541 {
542 int type;
543
544 for(; pat; pat=pat->next){
545 type = pat->type;
546 if(ignoreattr(pat->name))
547 type = AttrDefault;
548 switch(type){
549 case AttrQuery: /* name=something be present */
550 if(!hasname(a0, a1, pat->name))
551 return 0;
552 break;
553 case AttrNameval: /* name=val must be present */
554 if(!hasnameval(a0, a1, pat->name, pat->val))
555 return 0;
556 break;
557 case AttrDefault: /* name=val must be present if name=anything is present */
558 if(hasname(a0, a1, pat->name) && !hasnameval(a0, a1, pat->name, pat->val))
559 return 0;
560 break;
561 }
562 }
563 return 1;
564 }
565
566 void
memrandom(void * p,int n)567 memrandom(void *p, int n)
568 {
569 uchar *cp;
570
571 for(cp = (uchar*)p; n > 0; n--)
572 *cp++ = fastrand();
573 }
574
575 /*
576 * keep caphash fd open since opens of it could be disabled
577 */
578 static int caphashfd;
579
580 void
initcap(void)581 initcap(void)
582 {
583 caphashfd = open("#¤/caphash", OWRITE);
584 // if(caphashfd < 0)
585 // fprint(2, "%s: opening #¤/caphash: %r\n", argv0);
586 }
587
588 /*
589 * create a change uid capability
590 */
591 char*
mkcap(char * from,char * to)592 mkcap(char *from, char *to)
593 {
594 uchar rand[20];
595 char *cap;
596 char *key;
597 int nfrom, nto, ncap;
598 uchar hash[SHA1dlen];
599
600 if(caphashfd < 0)
601 return nil;
602
603 /* create the capability */
604 nto = strlen(to);
605 nfrom = strlen(from);
606 ncap = nfrom + 1 + nto + 1 + sizeof(rand)*3 + 1;
607 cap = emalloc(ncap);
608 snprint(cap, ncap, "%s@%s", from, to);
609 memrandom(rand, sizeof(rand));
610 key = cap+nfrom+1+nto+1;
611 enc64(key, sizeof(rand)*3, rand, sizeof(rand));
612
613 /* hash the capability */
614 hmac_sha1((uchar*)cap, strlen(cap), (uchar*)key, strlen(key), hash, nil);
615
616 /* give the kernel the hash */
617 key[-1] = '@';
618 if(write(caphashfd, hash, SHA1dlen) < 0){
619 free(cap);
620 return nil;
621 }
622
623 return cap;
624 }
625
626 int
phaseerror(Fsstate * s,char * op)627 phaseerror(Fsstate *s, char *op)
628 {
629 char tmp[32];
630
631 werrstr("protocol phase error: %s in state %s", op, phasename(s, s->phase, tmp));
632 return RpcPhase;
633 }
634
635 char*
phasename(Fsstate * fss,int phase,char * tmp)636 phasename(Fsstate *fss, int phase, char *tmp)
637 {
638 char *name;
639
640 if(fss->phase == Broken)
641 name = "Broken";
642 else if(phase == Established)
643 name = "Established";
644 else if(phase == Notstarted)
645 name = "Notstarted";
646 else if(phase < 0 || phase >= fss->maxphase
647 || (name = fss->phasename[phase]) == nil){
648 sprint(tmp, "%d", phase);
649 name = tmp;
650 }
651 return name;
652 }
653
654 static int
outin(char * prompt,char * def,int len)655 outin(char *prompt, char *def, int len)
656 {
657 char *s;
658
659 s = readcons(prompt, def, 0);
660 if(s == nil)
661 return -1;
662 if(s == nil)
663 sysfatal("s==nil???");
664 strncpy(def, s, len);
665 def[len-1] = 0;
666 free(s);
667 return strlen(def);
668 }
669
670 /*
671 * get host owner and set it
672 */
673 void
promptforhostowner(void)674 promptforhostowner(void)
675 {
676 char owner[64], *p;
677
678 /* hack for bitsy; can't prompt during boot */
679 if(p = getenv("user")){
680 writehostowner(p);
681 free(p);
682 return;
683 }
684 free(p);
685
686 strcpy(owner, "none");
687 do{
688 outin("user", owner, sizeof(owner));
689 } while(*owner == 0);
690 writehostowner(owner);
691 }
692
693 char*
estrappend(char * s,char * fmt,...)694 estrappend(char *s, char *fmt, ...)
695 {
696 char *t;
697 va_list arg;
698
699 va_start(arg, fmt);
700 t = vsmprint(fmt, arg);
701 if(t == nil)
702 sysfatal("out of memory");
703 va_end(arg);
704 s = erealloc(s, strlen(s)+strlen(t)+1);
705 strcat(s, t);
706 free(t);
707 return s;
708 }
709
710
711 /*
712 * prompt for a string with a possible default response
713 */
714 char*
readcons(char * prompt,char * def,int raw)715 readcons(char *prompt, char *def, int raw)
716 {
717 int fdin, fdout, ctl, n;
718 char line[10];
719 char *s;
720
721 fdin = open("/dev/cons", OREAD);
722 if(fdin < 0)
723 fdin = 0;
724 fdout = open("/dev/cons", OWRITE);
725 if(fdout < 0)
726 fdout = 1;
727 if(def != nil)
728 fprint(fdout, "%s[%s]: ", prompt, def);
729 else
730 fprint(fdout, "%s: ", prompt);
731 if(raw){
732 ctl = open("/dev/consctl", OWRITE);
733 if(ctl >= 0)
734 write(ctl, "rawon", 5);
735 } else
736 ctl = -1;
737 s = estrdup("");
738 for(;;){
739 n = read(fdin, line, 1);
740 if(n == 0){
741 Error:
742 close(fdin);
743 close(fdout);
744 if(ctl >= 0)
745 close(ctl);
746 free(s);
747 return nil;
748 }
749 if(n < 0)
750 goto Error;
751 if(line[0] == 0x7f)
752 goto Error;
753 if(n == 0 || line[0] == '\n' || line[0] == '\r'){
754 if(raw){
755 write(ctl, "rawoff", 6);
756 write(fdout, "\n", 1);
757 }
758 close(ctl);
759 close(fdin);
760 close(fdout);
761 if(*s == 0 && def != nil)
762 s = estrappend(s, "%s", def);
763 return s;
764 }
765 if(line[0] == '\b'){
766 if(strlen(s) > 0)
767 s[strlen(s)-1] = 0;
768 } else if(line[0] == 0x15) { /* ^U: line kill */
769 if(def != nil)
770 fprint(fdout, "\n%s[%s]: ", prompt, def);
771 else
772 fprint(fdout, "\n%s: ", prompt);
773
774 s[0] = 0;
775 } else {
776 s = estrappend(s, "%c", line[0]);
777 }
778 }
779 }
780
781 /*
782 * Insert a key into the keyring.
783 * If the public attributes are identical to some other key, replace that one.
784 */
785 int
replacekey(Key * kn,int before)786 replacekey(Key *kn, int before)
787 {
788 int i;
789 Key *k;
790
791 for(i=0; i<ring->nkey; i++){
792 k = ring->key[i];
793 if(matchattr(kn->attr, k->attr, nil) && matchattr(k->attr, kn->attr, nil)){
794 closekey(k);
795 kn->ref++;
796 ring->key[i] = kn;
797 return 0;
798 }
799 }
800 if(ring->nkey%16 == 0)
801 ring->key = erealloc(ring->key, (ring->nkey+16)*sizeof(ring->key[0]));
802 kn->ref++;
803 if(before){
804 memmove(ring->key+1, ring->key, ring->nkey*sizeof ring->key[0]);
805 ring->key[0] = kn;
806 ring->nkey++;
807 }else
808 ring->key[ring->nkey++] = kn;
809 return 0;
810 }
811
812 char*
safecpy(char * to,char * from,int n)813 safecpy(char *to, char *from, int n)
814 {
815 memset(to, 0, n);
816 if(n == 1)
817 return to;
818 if(from==nil)
819 sysfatal("safecpy called with from==nil, pc=%#p",
820 getcallerpc(&to));
821 strncpy(to, from, n-1);
822 return to;
823 }
824
825 Attr*
setattr(Attr * a,char * fmt,...)826 setattr(Attr *a, char *fmt, ...)
827 {
828 char buf[1024];
829 va_list arg;
830 Attr *b;
831
832 va_start(arg, fmt);
833 vseprint(buf, buf+sizeof buf, fmt, arg);
834 va_end(arg);
835 b = _parseattr(buf);
836 a = setattrs(a, b);
837 setmalloctag(a, getcallerpc(&a));
838 _freeattr(b);
839 return a;
840 }
841
842 /*
843 * add attributes in list b to list a. If any attributes are in
844 * both lists, replace those in a by those in b.
845 */
846 Attr*
setattrs(Attr * a,Attr * b)847 setattrs(Attr *a, Attr *b)
848 {
849 int found;
850 Attr **l, *freea;
851
852 for(; b; b=b->next){
853 found = 0;
854 for(l=&a; *l; ){
855 if(strcmp(b->name, (*l)->name) == 0){
856 switch(b->type){
857 case AttrNameval:
858 if(!found){
859 found = 1;
860 free((*l)->val);
861 (*l)->val = estrdup(b->val);
862 (*l)->type = AttrNameval;
863 l = &(*l)->next;
864 }else{
865 freea = *l;
866 *l = (*l)->next;
867 freea->next = nil;
868 _freeattr(freea);
869 }
870 break;
871 case AttrQuery:
872 goto continue2;
873 }
874 }else
875 l = &(*l)->next;
876 }
877 if(found == 0){
878 *l = _mkattr(b->type, b->name, b->val, nil);
879 setmalloctag(*l, getcallerpc(&a));
880 }
881 continue2:;
882 }
883 return a;
884 }
885
886 void
setmalloctaghere(void * v)887 setmalloctaghere(void *v)
888 {
889 setmalloctag(v, getcallerpc(&v));
890 }
891
892 Attr*
sortattr(Attr * a)893 sortattr(Attr *a)
894 {
895 int i;
896 Attr *anext, *a0, *a1, **l;
897
898 if(a == nil || a->next == nil)
899 return a;
900
901 /* cut list in halves */
902 a0 = nil;
903 a1 = nil;
904 i = 0;
905 for(; a; a=anext){
906 anext = a->next;
907 if(i++%2){
908 a->next = a0;
909 a0 = a;
910 }else{
911 a->next = a1;
912 a1 = a;
913 }
914 }
915
916 /* sort */
917 a0 = sortattr(a0);
918 a1 = sortattr(a1);
919
920 /* merge */
921 l = &a;
922 while(a0 || a1){
923 if(a1==nil){
924 anext = a0;
925 a0 = a0->next;
926 }else if(a0==nil){
927 anext = a1;
928 a1 = a1->next;
929 }else if(strcmp(a0->name, a1->name) < 0){
930 anext = a0;
931 a0 = a0->next;
932 }else{
933 anext = a1;
934 a1 = a1->next;
935 }
936 *l = anext;
937 l = &(*l)->next;
938 }
939 *l = nil;
940 return a;
941 }
942
943 int
toosmall(Fsstate * fss,uint n)944 toosmall(Fsstate *fss, uint n)
945 {
946 fss->rpc.nwant = n;
947 return RpcToosmall;
948 }
949
950 void
writehostowner(char * owner)951 writehostowner(char *owner)
952 {
953 int fd;
954 char *s;
955
956 if((s = strchr(owner,'@')) != nil){
957 *s++ = 0;
958 strncpy(secstore, s, (sizeof secstore)-1);
959 }
960 fd = open("#c/hostowner", OWRITE);
961 if(fd >= 0){
962 if(fprint(fd, "%s", owner) < 0)
963 fprint(2, "factotum: setting #c/hostowner to %q: %r\n",
964 owner);
965 close(fd);
966 }
967 }
968
969 int
attrnamefmt(Fmt * fmt)970 attrnamefmt(Fmt *fmt)
971 {
972 char *b, buf[1024], *ebuf;
973 Attr *a;
974
975 ebuf = buf+sizeof buf;
976 b = buf;
977 strcpy(buf, " ");
978 for(a=va_arg(fmt->args, Attr*); a; a=a->next){
979 if(a->name == nil)
980 continue;
981 b = seprint(b, ebuf, " %q?", a->name);
982 }
983 return fmtstrcpy(fmt, buf+1);
984 }
985
986 void
disablekey(Key * k)987 disablekey(Key *k)
988 {
989 Attr *a;
990
991 if(sflag) /* not on servers */
992 return;
993 for(a=k->attr; a; a=a->next){
994 if(a->type==AttrNameval && strcmp(a->name, "disabled") == 0)
995 return;
996 if(a->next == nil)
997 break;
998 }
999 if(a)
1000 a->next = _mkattr(AttrNameval, "disabled", "by.factotum", nil);
1001 else
1002 k->attr = _mkattr(AttrNameval, "disabled", "by.factotum", nil); /* not reached: always a proto attribute */
1003 }
1004