int needkeywrite(char *s) { char *t; ulong tag; Attr *a; Conv *c; a = _parseattr(s); if(a == nil){ werrstr("empty write"); return -1; } if((t = _strfindattr(a, "tag")) == nil){ werrstr("no tag"); freeattr(a); return -1; } tag = strtoul(t, 0, 0); for(c=conv; c; c=c->next) if(c->tag == tag){ nbsendul(c->keywait, 0); break; } if(c == nil){ werrstr("tag not found"); freeattr(a); return -1; } freeattr(a); return 0; }
Attr* auth_attr(AuthRpc *rpc) { if(auth_rpc(rpc, "attr", nil, 0) != ARok) return nil; return _parseattr(rpc->arg); }
int needkeywrite(char *s) { char *t; ulong tag; Attr *a; Req *r, **l; a = _parseattr(s); if(a == nil){ werrstr("empty write"); return -1; } if((t = _strfindattr(a, "tag")) == nil){ werrstr("no tag"); return -1; } tag = strtoul(t, 0, 0); r = nil; for(l=&needwait; *l; l=&(*l)->aux){ r = *l; if(r->tag == tag){ *l = r->aux; if(r->aux == nil) needlast = l; break; } } if(r == nil){ werrstr("tag not found"); return -1; } rpcread(r); return 0; }
int confirmwrite(char *s) { char *t, *ans; int allow, tagoff; ulong tag; Attr *a; Fsstate *fss; Req *r, **l; a = _parseattr(s); if(a == nil){ werrstr("empty write"); return -1; } if((t = _strfindattr(a, "tag")) == nil){ werrstr("no tag"); return -1; } tag = strtoul(t, 0, 0); if((ans = _strfindattr(a, "answer")) == nil){ werrstr("no answer"); return -1; } if(strcmp(ans, "yes") == 0) allow = 1; else if(strcmp(ans, "no") == 0) allow = 0; else{ werrstr("bad answer"); return -1; } r = nil; tagoff = -1; for(l=&cusewait; *l; l=&(*l)->aux){ r = *l; if(hastag(r->fid->aux, tag, &tagoff)){ *l = r->aux; if(r->aux == nil) cuselast = l; break; } } if(r == nil || tagoff == -1){ werrstr("tag not found"); return -1; } fss = r->fid->aux; fss->conf[tagoff].canuse = allow; rpcread(r); return 0; }
/* * 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; }
int confirmwrite(char *s) { char *t, *ans; int allow; ulong tag; Attr *a; Conv *c; a = _parseattr(s); if(a == nil){ werrstr("bad attr"); return -1; } if((t = _strfindattr(a, "tag")) == nil){ flog("bad confirm write: no tag"); werrstr("no tag"); return -1; } tag = strtoul(t, 0, 0); if((ans = _strfindattr(a, "answer")) == nil){ flog("bad confirm write: no answer"); werrstr("no answer"); return -1; } if(strcmp(ans, "yes") == 0) allow = 1; else if(strcmp(ans, "no") == 0) allow = 0; else{ flog("bad confirm write: bad answer"); werrstr("bad answer"); return -1; } for(c=conv; c; c=c->next){ if(tag == c->tag){ nbsendul(c->keywait, allow); break; } } if(c == nil){ werrstr("tag not found"); return -1; } return 0; }
void sshserverhandshake(Conn *c) { char *p, buf[128]; Biobuf *b; Attr *a; int i, afd; mpint *m; AuthRpc *rpc; RSApub *key; /* * BUG: should use `attr' to get the key attributes * after the read, but that's not implemented yet. */ if((b = Bopen("/mnt/factotum/ctl", OREAD)) == nil) sysfatal("open /mnt/factotum/ctl: %r"); while((p = Brdline(b, '\n')) != nil){ p[Blinelen(b)-1] = '\0'; if(strstr(p, " proto=rsa ") && strstr(p, " service=sshserve ")) break; } if(p == nil) sysfatal("no sshserve keys found in /mnt/factotum/ctl"); a = _parseattr(p); Bterm(b); key = emalloc(sizeof(*key)); if((p = _strfindattr(a, "n")) == nil) sysfatal("no n in sshserve key"); if((key->n = strtomp(p, &p, 16, nil)) == nil || *p != 0) sysfatal("bad n in sshserve key"); if((p = _strfindattr(a, "ek")) == nil) sysfatal("no ek in sshserve key"); if((key->ek = strtomp(p, &p, 16, nil)) == nil || *p != 0) sysfatal("bad ek in sshserve key"); _freeattr(a); if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0) sysfatal("open /mnt/factotum/rpc: %r"); if((rpc = auth_allocrpc(afd)) == nil) sysfatal("auth_allocrpc: %r"); p = "proto=rsa role=client service=sshserve"; if(auth_rpc(rpc, "start", p, strlen(p)) != ARok) sysfatal("auth_rpc start %s: %r", p); if(auth_rpc(rpc, "read", nil, 0) != ARok) sysfatal("auth_rpc read: %r"); m = strtomp(rpc->arg, nil, 16, nil); if(mpcmp(m, key->n) != 0) sysfatal("key in /mnt/factotum/ctl does not match rpc key"); mpfree(m); c->hostkey = key; /* send id string */ fprint(c->fd[0], "SSH-1.5-Plan9\n"); /* receive id string */ if(readstrnl(c->fd[0], buf, sizeof buf) < 0) sysfatal("reading server version: %r"); /* id string is "SSH-m.n-comment". We need m=1, n>=5. */ if(strncmp(buf, "SSH-", 4) != 0 || strtol(buf+4, &p, 10) != 1 || *p != '.' || strtol(p+1, &p, 10) < 5 || *p != '-') sysfatal("protocol mismatch; got %s, need SSH-1.x for x>=5", buf); for(i=0; i<COOKIELEN; i++) c->cookie[i] = fastrand(); calcsessid(c); send_ssh_smsg_public_key(c); recv_ssh_cmsg_session_key(c, rpc); auth_freerpc(rpc); close(afd); c->cstate = (*c->cipher->init)(c, 1); /* turns on encryption */ sendmsg(allocmsg(c, SSH_SMSG_SUCCESS, 0)); authsrvuser(c); }
RSApriv* getkey(int argc, char **argv, int needprivate, Attr **pa) { char *file, *s, *p; int sz; RSApriv *key; Biobuf *b; int regen; Attr *a; if(argc == 0) file = "#d/0"; else file = argv[0]; key = mallocz(sizeof(RSApriv), 1); if(key == nil) return nil; if((b = Bopen(file, OREAD)) == nil) { werrstr("open %s: %r", file); return nil; } s = Brdstr(b, '\n', 1); if(s == nil) { werrstr("read %s: %r", file); return nil; } if(strncmp(s, "key ", 4) != 0) { werrstr("bad key format"); return nil; } regen = 0; a = _parseattr(s+4); if(a == nil) { werrstr("empty key"); return nil; } if((p = _strfindattr(a, "proto")) == nil) { werrstr("no proto"); return nil; } if(strcmp(p, "rsa") != 0) { werrstr("proto not rsa"); return nil; } if((p = _strfindattr(a, "ek")) == nil) { werrstr("no ek"); return nil; } if((key->pub.ek = strtomp(p, &p, 16, nil)) == nil || *p != 0) { werrstr("bad ek"); return nil; } if((p = _strfindattr(a, "n")) == nil) { werrstr("no n"); return nil; } if((key->pub.n = strtomp(p, &p, 16, nil)) == nil || *p != 0) { werrstr("bad n"); return nil; } if((p = _strfindattr(a, "size")) == nil) fprint(2, "warning: missing size; will add\n"); else if((sz = strtol(p, &p, 10)) == 0 || *p != 0) fprint(2, "warning: bad size; will correct\n"); else if(sz != mpsignif(key->pub.n)) fprint(2, "warning: wrong size (got %d, expected %d); will correct\n", sz, mpsignif(key->pub.n)); if(!needprivate) goto call; if((p = _strfindattr(a, "!dk")) == nil) { werrstr("no !dk"); return nil; } if((key->dk = strtomp(p, &p, 16, nil)) == nil || *p != 0) { werrstr("bad !dk"); return nil; } if((p = _strfindattr(a, "!p")) == nil) { werrstr("no !p"); return nil; } if((key->p = strtomp(p, &p, 16, nil)) == nil || *p != 0) { werrstr("bad !p"); return nil; } if((p = _strfindattr(a, "!q")) == nil) { werrstr("no !q"); return nil; } if((key->q = strtomp(p, &p, 16, nil)) == nil || *p != 0) { werrstr("bad !q"); return nil; } if((p = _strfindattr(a, "!kp")) == nil) { fprint(2, "warning: no !kp\n"); regen = 1; goto regen; } if((key->kp = strtomp(p, &p, 16, nil)) == nil || *p != 0) { fprint(2, "warning: bad !kp\n"); regen = 1; goto regen; } if((p = _strfindattr(a, "!kq")) == nil) { fprint(2, "warning: no !kq\n"); regen = 1; goto regen; } if((key->kq = strtomp(p, &p, 16, nil)) == nil || *p != 0) { fprint(2, "warning: bad !kq\n"); regen = 1; goto regen; } if((p = _strfindattr(a, "!c2")) == nil) { fprint(2, "warning: no !c2\n"); regen = 1; goto regen; } if((key->c2 = strtomp(p, &p, 16, nil)) == nil || *p != 0) { fprint(2, "warning: bad !c2\n"); regen = 1; goto regen; } regen: if(regen) { RSApriv *k2; k2 = rsafill(key->pub.n, key->pub.ek, key->dk, key->p, key->q); if(k2 == nil) { werrstr("regenerating chinese-remainder parts failed: %r"); return nil; } key = k2; } call: a = _delattr(a, "ek"); a = _delattr(a, "n"); a = _delattr(a, "size"); a = _delattr(a, "!dk"); a = _delattr(a, "!p"); a = _delattr(a, "!q"); a = _delattr(a, "!c2"); a = _delattr(a, "!kp"); a = _delattr(a, "!kq"); if(pa) *pa = a; return key; }
DSApriv* getdsakey(int argc, char **argv, int needprivate, Attr **pa) { char *file, *s, *p; DSApriv *key; Biobuf *b; Attr *a; if(argc == 0) file = "#d/0"; else file = argv[0]; key = mallocz(sizeof(RSApriv), 1); if(key == nil) return nil; if((b = Bopen(file, OREAD)) == nil) { werrstr("open %s: %r", file); return nil; } s = Brdstr(b, '\n', 1); if(s == nil) { werrstr("read %s: %r", file); return nil; } if(strncmp(s, "key ", 4) != 0) { werrstr("bad key format"); return nil; } a = _parseattr(s+4); if(a == nil) { werrstr("empty key"); return nil; } if((p = _strfindattr(a, "proto")) == nil) { werrstr("no proto"); return nil; } if(strcmp(p, "dsa") != 0) { werrstr("proto not dsa"); return nil; } if((p = _strfindattr(a, "p")) == nil) { werrstr("no p"); return nil; } if((key->pub.p = strtomp(p, &p, 16, nil)) == nil || *p != 0) { werrstr("bad p"); return nil; } if((p = _strfindattr(a, "q")) == nil) { werrstr("no q"); return nil; } if((key->pub.q = strtomp(p, &p, 16, nil)) == nil || *p != 0) { werrstr("bad q"); return nil; } if((p = _strfindattr(a, "alpha")) == nil) { werrstr("no alpha"); return nil; } if((key->pub.alpha = strtomp(p, &p, 16, nil)) == nil || *p != 0) { werrstr("bad alpha"); return nil; } if((p = _strfindattr(a, "key")) == nil) { werrstr("no key="); return nil; } if((key->pub.key = strtomp(p, &p, 16, nil)) == nil || *p != 0) { werrstr("bad key="); return nil; } if(!needprivate) goto call; if((p = _strfindattr(a, "!secret")) == nil) { werrstr("no !secret"); return nil; } if((key->secret = strtomp(p, &p, 16, nil)) == nil || *p != 0) { werrstr("bad !secret"); return nil; } call: a = _delattr(a, "p"); a = _delattr(a, "q"); a = _delattr(a, "alpha"); a = _delattr(a, "key"); a = _delattr(a, "!secret"); if(pa) *pa = a; return key; }
int ctlwrite(char *a, int atzero) { char *p; int i, nmatch, ret; Attr *attr, **l, **lpriv, **lprotos, *pa, *priv, *protos; Key *k; Proto *proto; if(a[0] == '#' || a[0] == '\0') return 0; /* * it would be nice to emit a warning of some sort here. * we ignore all but the first line of the write. this helps * both with things like "echo delkey >/mnt/factotum/ctl" * and writes that (incorrectly) contain multiple key lines. */ if((p = strchr(a, '\n')) != nil){ if(p[1] != '\0'){ werrstr("multiline write not allowed"); return -1; } *p = '\0'; } if((p = strchr(a, ' ')) == nil) p = ""; else *p++ = '\0'; switch(classify(a, ctltab, nelem(ctltab))){ default: case Vunknown: werrstr("unknown verb"); return -1; case Vdebug: debug ^= 1; return 0; case Vdelkey: nmatch = 0; attr = _parseattr(p); for(pa=attr; pa; pa=pa->next){ if(pa->type != AttrQuery && pa->name[0]=='!'){ werrstr("only !private? patterns are allowed for private fields"); _freeattr(attr); return -1; } } for(i=0; i<ring->nkey; ){ if(matchattr(attr, ring->key[i]->attr, ring->key[i]->privattr)){ nmatch++; closekey(ring->key[i]); ring->nkey--; memmove(&ring->key[i], &ring->key[i+1], (ring->nkey-i)*sizeof(ring->key[0])); }else i++; } _freeattr(attr); if(nmatch == 0){ werrstr("found no keys to delete"); return -1; } return 0; case Vaddkey: attr = _parseattr(p); /* separate out proto= attributes */ lprotos = &protos; for(l=&attr; (*l); ){ if(strcmp((*l)->name, "proto") == 0){ *lprotos = *l; lprotos = &(*l)->next; *l = (*l)->next; }else l = &(*l)->next; } *lprotos = nil; if(protos == nil){ werrstr("key without protos"); _freeattr(attr); return -1; } /* separate out private attributes */ lpriv = &priv; for(l=&attr; (*l); ){ if((*l)->name[0] == '!'){ *lpriv = *l; lpriv = &(*l)->next; *l = (*l)->next; }else l = &(*l)->next; } *lpriv = nil; /* add keys */ ret = 0; for(pa=protos; pa; pa=pa->next){ if((proto = findproto(pa->val)) == nil){ werrstr("unknown proto %s", pa->val); ret = -1; continue; } if(proto->addkey == nil){ werrstr("proto %s doesn't take keys", proto->name); ret = -1; continue; } k = emalloc(sizeof(Key)); k->attr = _mkattr(AttrNameval, "proto", proto->name, _copyattr(attr)); k->privattr = _copyattr(priv); k->ref = 1; k->proto = proto; if(proto->addkey(k, atzero) < 0){ ret = -1; closekey(k); continue; } closekey(k); } _freeattr(attr); _freeattr(priv); _freeattr(protos); return ret; } }
void rpcread(Req *r) { Attr *attr; char *p; int ophase, ret; uint8_t *e; uint count; Fsstate *fss; Proto *proto; if(r->ifcall.count < 64){ respond(r, "rpc read too small"); return; } fss = r->fid->aux; if(!fss->pending){ respond(r, "no rpc pending"); return; } switch(fss->rpc.iverb){ default: case Vunknown: retstring(r, fss, "error unknown verb"); break; case Vstart: if(fss->phase != Notstarted){ flog("%d: implicit close due to second start; old attr '%A'", fss->seqnum, fss->attr); if(fss->proto && fss->ps) (*fss->proto->close)(fss); fss->ps = nil; fss->proto = nil; _freeattr(fss->attr); fss->attr = nil; fss->phase = Notstarted; } attr = _parseattr(fss->rpc.arg); if((p = _strfindattr(attr, "proto")) == nil){ retstring(r, fss, "error did not specify proto"); _freeattr(attr); break; } if((proto = findproto(p)) == nil){ snprint(fss->rpc.buf, Maxrpc, "error unknown protocol %q", p); retstring(r, fss, fss->rpc.buf); _freeattr(attr); break; } fss->attr = attr; fss->proto = proto; fss->seqnum = ++seqnum; ret = (*proto->init)(proto, fss); rpcstartlog(attr, fss, ret); if(ret != RpcOk){ _freeattr(fss->attr); fss->attr = nil; fss->phase = Notstarted; } retrpc(r, ret, fss); break; case Vread: if(fss->rpc.arg && fss->rpc.arg[0]){ retstring(r, fss, "error read needs no parameters"); break; } if(rdwrcheck(r, fss) < 0) break; count = r->ifcall.count - 3; ophase = fss->phase; ret = fss->proto->read(fss, (uint8_t*)r->ofcall.data+3, &count); rpcrdwrlog(fss, "read", count, ophase, ret); if(ret == RpcOk){ memmove(r->ofcall.data, "ok ", 3); if(count == 0) r->ofcall.count = 2; else r->ofcall.count = 3+count; fss->pending = 0; respond(r, nil); }else retrpc(r, ret, fss); break; case Vwrite: if(rdwrcheck(r, fss) < 0) break; ophase = fss->phase; ret = fss->proto->write(fss, fss->rpc.arg, fss->rpc.narg); rpcrdwrlog(fss, "write", fss->rpc.narg, ophase, ret); retrpc(r, ret, fss); break; case Vauthinfo: if(fss->phase != Established){ retstring(r, fss, "error authentication unfinished"); break; } if(!fss->haveai){ retstring(r, fss, "error no authinfo available"); break; } memmove(r->ofcall.data, "ok ", 3); fss->ai.cap = mkcap(r->fid->uid, fss->ai.suid); e = convAI2M(&fss->ai, (uint8_t*)r->ofcall.data+3, r->ifcall.count-3); free(fss->ai.cap); fss->ai.cap = nil; if(e == nil){ retstring(r, fss, "error read too small"); break; } r->ofcall.count = e - (uint8_t*)r->ofcall.data; fss->pending = 0; respond(r, nil); break; case Vattr: snprint(fss->rpc.buf, Maxrpc, "ok %A", fss->attr); retstring(r, fss, fss->rpc.buf); break; } }