1 #include "dat.h" 2 3 static char secstore[100]; /* server name */ 4 5 /* bind in the default network and cs */ 6 static int 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 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 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* 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 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 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 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 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* 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* 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* 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 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 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 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* 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 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 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* 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* 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 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 520 hasname(Attr *a0, Attr *a1, char *name) 521 { 522 return _findattr(a0, name) || _findattr(a1, name); 523 } 524 525 static int 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 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 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 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* 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 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* 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 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 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* 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* 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 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* 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* 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* 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 887 setmalloctaghere(void *v) 888 { 889 setmalloctag(v, getcallerpc(&v)); 890 } 891 892 Attr* 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 944 toosmall(Fsstate *fss, uint n) 945 { 946 fss->rpc.nwant = n; 947 return RpcToosmall; 948 } 949 950 void 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 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 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