| #include "std.h" |
| #include "dat.h" |
| #include <9pclient.h> |
| |
| int extrafactotumdir; |
| int debug; |
| int trysecstore = 1; |
| char *factname = "factotum"; |
| char *service = "factotum"; |
| char *owner; |
| char *authaddr; |
| void gflag(char*); |
| |
| void |
| usage(void) |
| { |
| fprint(2, "usage: factotum [-Dd] [-a authaddr] [-m mtpt] [-s service]\n"); |
| fprint(2, " or factotum -g keypattern\n"); |
| fprint(2, " or factotum -g 'badkeyattr\\nmsg\\nkeypattern'\n"); |
| threadexitsall("usage"); |
| } |
| |
| void |
| threadmain(int argc, char *argv[]) |
| { |
| char *mtpt; |
| char err[ERRMAX]; |
| |
| /* mtpt = "/mnt"; */ |
| mtpt = nil; |
| owner = getuser(); |
| quotefmtinstall(); |
| fmtinstall('A', attrfmt); |
| fmtinstall('H', encodefmt); |
| fmtinstall('N', attrnamefmt); |
| |
| if(argc == 3 && strcmp(argv[1], "-g") == 0){ |
| gflag(argv[2]); |
| threadexitsall(nil); |
| } |
| |
| ARGBEGIN{ |
| default: |
| usage(); |
| case 'D': |
| chatty9p++; |
| break; |
| case 'a': |
| authaddr = EARGF(usage()); |
| break; |
| case 'd': |
| debug = 1; |
| break; |
| case 'g': |
| usage(); |
| case 'm': |
| mtpt = EARGF(usage()); |
| break; |
| case 's': |
| service = EARGF(usage()); |
| break; |
| case 'n': |
| trysecstore = 0; |
| break; |
| case 'x': |
| extrafactotumdir = 1; |
| break; |
| }ARGEND |
| |
| if(argc != 0) |
| usage(); |
| |
| if(trysecstore && havesecstore()){ |
| while(secstorefetch() < 0){ |
| rerrstr(err, sizeof err); |
| if(strcmp(err, "cancel") == 0) |
| break; |
| fprint(2, "secstorefetch: %r\n"); |
| fprint(2, "Enter an empty password to quit.\n"); |
| } |
| } |
| |
| rfork(RFNOTEG); |
| |
| fsinit0(); |
| threadpostmountsrv(&fs, service, mtpt, MBEFORE); |
| threadexits(nil); |
| } |
| |
| /* |
| * prompt user for a key. don't care about memory leaks, runs standalone |
| */ |
| static Attr* |
| promptforkey(int fd, char *params) |
| { |
| char *v; |
| Attr *a, *attr; |
| char *def; |
| |
| attr = _parseattr(params); |
| fprint(fd, "!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 rv; |
| char buf[8192]; |
| CFid *fid; |
| |
| fid = nsopen("factotum", nil, "ctl", OWRITE); |
| if(fid == nil) |
| sysfatal("opening factotum/ctl: %r"); |
| snprint(buf, sizeof buf, "key %A\n", attr); |
| rv = fswrite(fid, buf, strlen(buf)); |
| fsclose(fid); |
| return rv; |
| } |
| |
| static void |
| askuser(int fd, char *params) |
| { |
| Attr *attr; |
| |
| attr = promptforkey(fd, params); |
| if(attr == nil) |
| sysfatal("no key supplied"); |
| if(sendkey(attr) < 0) |
| sysfatal("sending key to factotum: %r"); |
| } |
| |
| void |
| gflag(char *s) |
| { |
| char *f[4]; |
| int nf; |
| int fd; |
| |
| if((fd = open("/dev/tty", ORDWR)) < 0) |
| sysfatal("open /dev/tty: %r"); |
| |
| nf = getfields(s, f, nelem(f), 0, "\n"); |
| if(nf == 1){ /* needkey or old badkey */ |
| fprint(fd, "\n"); |
| askuser(fd, s); |
| threadexitsall(nil); |
| } |
| if(nf == 3){ /* new badkey */ |
| fprint(fd, "\n"); |
| fprint(fd, "!replace: %s\n", f[0]); |
| fprint(fd, "!because: %s\n", f[1]); |
| askuser(fd, f[2]); |
| threadexitsall(nil); |
| } |
| usage(); |
| } |