1 #include "dat.h" 2 3 int askforkeys = 1; 4 char *authaddr; 5 int debug; 6 int doprivate = 1; 7 int gflag; 8 char *owner; 9 int kflag; 10 char *mtpt = "/mnt"; 11 Keyring *ring; 12 char *service; 13 int sflag; 14 int uflag; 15 16 extern Srv fs; 17 static void notifyf(void*, char*); 18 static void private(void); 19 20 char Easproto[] = "auth server protocol botch"; 21 char Ebadarg[] = "invalid argument"; 22 char Ebadkey[] = "bad key"; 23 char Enegotiation[] = "negotiation failed, no common protocols or keys"; 24 char Etoolarge[] = "rpc too large"; 25 26 Proto* 27 prototab[] = 28 { 29 &apop, 30 &chap, 31 &cram, 32 &httpdigest, 33 &mschap, 34 &p9any, 35 &p9cr, 36 &p9sk1, 37 &p9sk2, 38 &pass, 39 /* &srs, */ 40 &rsa, 41 &vnc, 42 &wep, 43 nil, 44 }; 45 46 void 47 usage(void) 48 { 49 fprint(2, "usage: %s [-DSdknpu] [-a authaddr] [-m mtpt] [-s service]\n", 50 argv0); 51 fprint(2, "or %s -g 'params'\n", argv0); 52 exits("usage"); 53 } 54 55 void 56 main(int argc, char **argv) 57 { 58 int i, trysecstore; 59 char err[ERRMAX], *s; 60 Dir d; 61 Proto *p; 62 char *secstorepw; 63 64 trysecstore = 1; 65 secstorepw = nil; 66 67 ARGBEGIN{ 68 case 'D': 69 chatty9p++; 70 break; 71 case 'S': /* server: read nvram, no prompting for keys */ 72 askforkeys = 0; 73 trysecstore = 0; 74 sflag = 1; 75 break; 76 case 'a': 77 authaddr = EARGF(usage()); 78 break; 79 case 'd': 80 debug = 1; 81 doprivate = 0; 82 break; 83 case 'g': /* get: prompt for key for name and domain */ 84 gflag = 1; 85 break; 86 case 'k': /* reinitialize nvram */ 87 kflag = 1; 88 break; 89 case 'm': /* set default mount point */ 90 mtpt = EARGF(usage()); 91 break; 92 case 'n': 93 trysecstore = 0; 94 break; 95 case 'p': 96 doprivate = 0; 97 break; 98 case 's': /* set service name */ 99 service = EARGF(usage()); 100 break; 101 case 'u': /* user: set hostowner */ 102 uflag = 1; 103 break; 104 default: 105 usage(); 106 }ARGEND 107 108 if(argc != 0 && !gflag) 109 usage(); 110 if(doprivate) 111 private(); 112 113 initcap(); 114 115 quotefmtinstall(); 116 fmtinstall('A', _attrfmt); 117 fmtinstall('N', attrnamefmt); 118 fmtinstall('H', encodefmt); 119 120 ring = emalloc(sizeof(*ring)); 121 notify(notifyf); 122 123 if(gflag){ 124 if(argc != 1) 125 usage(); 126 askuser(argv[0]); 127 exits(nil); 128 } 129 130 for(i=0; prototab[i]; i++){ 131 p = prototab[i]; 132 if(p->name == nil) 133 sysfatal("protocol %d has no name", i); 134 if(p->init == nil) 135 sysfatal("protocol %s has no init", p->name); 136 if(p->write == nil) 137 sysfatal("protocol %s has no write", p->name); 138 if(p->read == nil) 139 sysfatal("protocol %s has no read", p->name); 140 if(p->close == nil) 141 sysfatal("protocol %s has no close", p->name); 142 if(p->keyprompt == nil) 143 p->keyprompt = ""; 144 } 145 146 if(sflag){ 147 s = getnvramkey(kflag ? NVwrite : NVwriteonerr, &secstorepw); 148 if(s == nil) 149 fprint(2, "factotum warning: cannot read nvram: %r\n"); 150 else if(ctlwrite(s, 0) < 0) 151 fprint(2, "factotum warning: cannot add nvram key: %r\n"); 152 if(secstorepw != nil) 153 trysecstore = 1; 154 if (s != nil) { 155 memset(s, 0, strlen(s)); 156 free(s); 157 } 158 } else if(uflag) 159 promptforhostowner(); 160 owner = getuser(); 161 162 if(trysecstore){ 163 if(havesecstore() == 1){ 164 while(secstorefetch(secstorepw) < 0){ 165 rerrstr(err, sizeof err); 166 if(strcmp(err, "cancel") == 0) 167 break; 168 fprint(2, "factotum: secstorefetch: %r\n"); 169 fprint(2, "Enter an empty password to quit.\n"); 170 free(secstorepw); 171 secstorepw = nil; /* just try nvram pw once */ 172 } 173 }else{ 174 /* 175 rerrstr(err, sizeof err); 176 if(*err) 177 fprint(2, "factotum: havesecstore: %r\n"); 178 */ 179 } 180 } 181 182 postmountsrv(&fs, service, mtpt, MBEFORE); 183 if(service){ 184 nulldir(&d); 185 d.mode = 0666; 186 s = emalloc(10+strlen(service)); 187 strcpy(s, "/srv/"); 188 strcat(s, service); 189 if(dirwstat(s, &d) < 0) 190 fprint(2, "factotum warning: cannot chmod 666 %s: %r\n", s); 191 free(s); 192 } 193 exits(nil); 194 } 195 196 char *pmsg = "Warning! %s can't protect itself from debugging: %r\n"; 197 char *smsg = "Warning! %s can't turn off swapping: %r\n"; 198 199 /* don't allow other processes to debug us and steal keys */ 200 static void 201 private(void) 202 { 203 int fd; 204 char buf[64]; 205 206 snprint(buf, sizeof(buf), "#p/%d/ctl", getpid()); 207 fd = open(buf, OWRITE); 208 if(fd < 0){ 209 fprint(2, pmsg, argv0); 210 return; 211 } 212 if(fprint(fd, "private") < 0) 213 fprint(2, pmsg, argv0); 214 if(fprint(fd, "noswap") < 0) 215 fprint(2, smsg, argv0); 216 close(fd); 217 } 218 219 static void 220 notifyf(void*, char *s) 221 { 222 if(strncmp(s, "interrupt", 9) == 0) 223 noted(NCONT); 224 noted(NDFLT); 225 } 226 227 enum 228 { 229 Qroot, 230 Qfactotum, 231 Qrpc, 232 Qkeylist, 233 Qprotolist, 234 Qconfirm, 235 Qlog, 236 Qctl, 237 Qneedkey, 238 }; 239 240 Qid 241 mkqid(int type, int path) 242 { 243 Qid q; 244 245 q.type = type; 246 q.path = path; 247 q.vers = 0; 248 return q; 249 } 250 251 static void 252 fsattach(Req *r) 253 { 254 r->fid->qid = mkqid(QTDIR, Qroot); 255 r->ofcall.qid = r->fid->qid; 256 respond(r, nil); 257 } 258 259 static struct { 260 char *name; 261 int qidpath; 262 ulong perm; 263 } dirtab[] = { 264 "confirm", Qconfirm, 0600|DMEXCL, /* we know this is slot #0 below */ 265 "needkey", Qneedkey, 0600|DMEXCL, /* we know this is slot #1 below */ 266 "ctl", Qctl, 0644, 267 "rpc", Qrpc, 0666, 268 "proto", Qprotolist, 0444, 269 "log", Qlog, 0400|DMEXCL, 270 }; 271 static int inuse[nelem(dirtab)]; 272 int *confirminuse = &inuse[0]; 273 int *needkeyinuse = &inuse[1]; 274 275 static void 276 fillstat(Dir *dir, char *name, int type, int path, ulong perm) 277 { 278 dir->name = estrdup(name); 279 dir->uid = estrdup(owner); 280 dir->gid = estrdup(owner); 281 dir->mode = perm; 282 dir->length = 0; 283 dir->qid = mkqid(type, path); 284 dir->atime = time(0); 285 dir->mtime = time(0); 286 dir->muid = estrdup(""); 287 } 288 289 static int 290 rootdirgen(int n, Dir *dir, void*) 291 { 292 if(n > 0) 293 return -1; 294 fillstat(dir, "factotum", QTDIR, Qfactotum, DMDIR|0555); 295 return 0; 296 } 297 298 static int 299 fsdirgen(int n, Dir *dir, void*) 300 { 301 if(n >= nelem(dirtab)) 302 return -1; 303 fillstat(dir, dirtab[n].name, 0, dirtab[n].qidpath, dirtab[n].perm); 304 return 0; 305 } 306 307 static char* 308 fswalk1(Fid *fid, char *name, Qid *qid) 309 { 310 int i; 311 312 switch((ulong)fid->qid.path){ 313 default: 314 return "cannot happen"; 315 case Qroot: 316 if(strcmp(name, "factotum") == 0){ 317 *qid = mkqid(QTDIR, Qfactotum); 318 fid->qid = *qid; 319 return nil; 320 } 321 if(strcmp(name, "..") == 0){ 322 *qid = fid->qid; 323 return nil; 324 } 325 return "not found"; 326 case Qfactotum: 327 for(i=0; i<nelem(dirtab); i++) 328 if(strcmp(name, dirtab[i].name) == 0){ 329 *qid = mkqid(0, dirtab[i].qidpath); 330 fid->qid = *qid; 331 return nil; 332 } 333 if(strcmp(name, "..") == 0){ 334 *qid = mkqid(QTDIR, Qroot); 335 fid->qid = *qid; 336 return nil; 337 } 338 return "not found"; 339 } 340 } 341 342 static void 343 fsstat(Req *r) 344 { 345 int i; 346 ulong path; 347 348 path = r->fid->qid.path; 349 if(path == Qroot){ 350 fillstat(&r->d, "/", QTDIR, Qroot, 0555|DMDIR); 351 respond(r, nil); 352 return; 353 } 354 if(path == Qfactotum){ 355 fillstat(&r->d, "factotum", QTDIR, Qfactotum, 0555|DMDIR); 356 respond(r, nil); 357 return; 358 } 359 for(i=0; i<nelem(dirtab); i++) 360 if(dirtab[i].qidpath == path){ 361 fillstat(&r->d, dirtab[i].name, 0, dirtab[i].qidpath, dirtab[i].perm); 362 respond(r, nil); 363 return; 364 } 365 respond(r, "file not found"); 366 } 367 368 static void 369 fsopen(Req *r) 370 { 371 int i, *p, perm; 372 static int need[4] = {4, 2, 6, 1}; 373 int n; 374 Fsstate *fss; 375 376 p = nil; 377 for(i=0; i<nelem(dirtab); i++) 378 if(dirtab[i].qidpath == r->fid->qid.path) 379 break; 380 if(i < nelem(dirtab)){ 381 if(dirtab[i].perm & DMEXCL) 382 p = &inuse[i]; 383 if(strcmp(r->fid->uid, owner) == 0) 384 perm = dirtab[i].perm>>6; 385 else 386 perm = dirtab[i].perm; 387 }else 388 perm = 5; 389 390 n = need[r->ifcall.mode&3]; 391 if((r->ifcall.mode&~(3|OTRUNC)) || ((perm&n) != n)){ 392 respond(r, "permission denied"); 393 return; 394 } 395 if(p){ 396 if(*p){ 397 respond(r, "file in use"); 398 return; 399 } 400 (*p)++; 401 } 402 403 r->fid->aux = fss = emalloc(sizeof(Fsstate)); 404 fss->phase = Notstarted; 405 fss->sysuser = r->fid->uid; 406 fss->attr = nil; 407 strcpy(fss->err, "factotum/fs.c no error"); 408 respond(r, nil); 409 } 410 411 static void 412 fsdestroyfid(Fid *fid) 413 { 414 int i; 415 Fsstate *fss; 416 417 if(fid->omode != -1){ 418 for(i=0; i<nelem(dirtab); i++) 419 if(dirtab[i].qidpath == fid->qid.path) 420 if(dirtab[i].perm&DMEXCL) 421 inuse[i] = 0; 422 } 423 424 fss = fid->aux; 425 if(fss == nil) 426 return; 427 if(fss->ps) 428 (*fss->proto->close)(fss); 429 _freeattr(fss->attr); 430 free(fss); 431 } 432 433 static int 434 readlist(int off, int (*gen)(int, char*, uint, Fsstate*), Req *r, Fsstate *fss) 435 { 436 char *a, *ea; 437 int n; 438 439 a = r->ofcall.data; 440 ea = a+r->ifcall.count; 441 for(;;){ 442 n = (*gen)(off, a, ea-a, fss); 443 if(n == 0){ 444 r->ofcall.count = a - (char*)r->ofcall.data; 445 return off; 446 } 447 a += n; 448 off++; 449 } 450 } 451 452 static int 453 keylist(int i, char *a, uint n, Fsstate *fss) 454 { 455 char buf[512]; 456 Keyinfo ki; 457 Key *k; 458 459 k = nil; 460 mkkeyinfo(&ki, fss, nil); 461 ki.attr = nil; 462 ki.skip = i; 463 ki.usedisabled = 1; 464 if(findkey(&k, &ki, "") != RpcOk) 465 return 0; 466 snprint(buf, sizeof buf, "key %A %N\n", k->attr, k->privattr); 467 closekey(k); 468 strcpy(buf+sizeof buf-2, "\n"); /* if line is really long, just truncate */ 469 if(strlen(buf) > n) 470 return 0; 471 n = strlen(buf); 472 memmove(a, buf, n); 473 return n; 474 } 475 476 static int 477 protolist(int i, char *a, uint n, Fsstate *fss) 478 { 479 USED(fss); 480 481 if(i >= nelem(prototab)-1) 482 return 0; 483 if(strlen(prototab[i]->name)+1 > n) 484 return 0; 485 n = strlen(prototab[i]->name)+1; 486 memmove(a, prototab[i]->name, n-1); 487 a[n-1] = '\n'; 488 return n; 489 } 490 491 static void 492 fsread(Req *r) 493 { 494 Fsstate *s; 495 496 s = r->fid->aux; 497 switch((ulong)r->fid->qid.path){ 498 default: 499 respond(r, "bug in fsread"); 500 break; 501 case Qroot: 502 dirread9p(r, rootdirgen, nil); 503 respond(r, nil); 504 break; 505 case Qfactotum: 506 dirread9p(r, fsdirgen, nil); 507 respond(r, nil); 508 break; 509 case Qrpc: 510 rpcread(r); 511 break; 512 case Qneedkey: 513 needkeyread(r); 514 break; 515 case Qconfirm: 516 confirmread(r); 517 break; 518 case Qlog: 519 logread(r); 520 break; 521 case Qctl: 522 s->listoff = readlist(s->listoff, keylist, r, s); 523 respond(r, nil); 524 break; 525 case Qprotolist: 526 s->listoff = readlist(s->listoff, protolist, r, s); 527 respond(r, nil); 528 break; 529 } 530 } 531 532 static void 533 fswrite(Req *r) 534 { 535 int ret; 536 char err[ERRMAX], *s; 537 538 switch((ulong)r->fid->qid.path){ 539 default: 540 respond(r, "bug in fswrite"); 541 break; 542 case Qrpc: 543 rpcwrite(r); 544 break; 545 case Qneedkey: 546 case Qconfirm: 547 case Qctl: 548 s = emalloc(r->ifcall.count+1); 549 memmove(s, r->ifcall.data, r->ifcall.count); 550 s[r->ifcall.count] = '\0'; 551 switch((ulong)r->fid->qid.path){ 552 default: 553 abort(); 554 case Qneedkey: 555 ret = needkeywrite(s); 556 break; 557 case Qconfirm: 558 ret = confirmwrite(s); 559 break; 560 case Qctl: 561 ret = ctlwrite(s, 0); 562 break; 563 } 564 free(s); 565 if(ret < 0){ 566 rerrstr(err, sizeof err); 567 respond(r, err); 568 }else{ 569 r->ofcall.count = r->ifcall.count; 570 respond(r, nil); 571 } 572 break; 573 } 574 } 575 576 static void 577 fsflush(Req *r) 578 { 579 confirmflush(r->oldreq); 580 needkeyflush(r->oldreq); 581 logflush(r->oldreq); 582 respond(r, nil); 583 } 584 585 Srv fs = { 586 .attach= fsattach, 587 .walk1= fswalk1, 588 .open= fsopen, 589 .read= fsread, 590 .write= fswrite, 591 .stat= fsstat, 592 .flush= fsflush, 593 .destroyfid= fsdestroyfid, 594 }; 595 596