static int wepwrite(Fsstate *fss, void *va, uint n) { char *data = va; State *s; char dev[64]; int fd, cfd; int rv; char *p; /* get the device */ if(n > sizeof(dev)-5){ werrstr("device too long"); return RpcErrstr; } memmove(dev, data, n); dev[n] = 0; s = fss->ps; /* legal? */ if(dev[0] != '#' || dev[1] != 'l'){ werrstr("%s not an ether device", dev); return RpcErrstr; } strcat(dev, "!0"); fd = dial(dev, 0, 0, &cfd); if(fd < 0) return RpcErrstr; /* flavor it with passwords, essid, and turn on wep */ rv = RpcErrstr; p = _strfindattr(s->key->privattr, "!key1"); if(p != nil) if(fprint(cfd, "key1 %s", p) < 0) goto out; p = _strfindattr(s->key->privattr, "!key2"); if(p != nil) if(fprint(cfd, "key2 %s", p) < 0) goto out; p = _strfindattr(s->key->privattr, "!key3"); if(p != nil) if(fprint(cfd, "key3 %s", p) < 0) goto out; p = _strfindattr(fss->attr, "essid"); if(p != nil) if(fprint(cfd, "essid %s", p) < 0) goto out; if(fprint(cfd, "crypt on") < 0) goto out; rv = RpcOk; out: close(fd); close(cfd); return rv; }
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; }
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; }
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; 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; }
int auth_respond(void *chal, uint nchal, char *user, uint nuser, void *resp, uint nresp, AuthGetkey *getkey, char *fmt, ...) { char *p, *s; va_list arg; int afd; AuthRpc *rpc; Attr *a; if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0) return -1; if((rpc = auth_allocrpc(afd)) == nil){ close(afd); return -1; } quotefmtinstall(); /* just in case */ va_start(arg, fmt); p = vsmprint(fmt, arg); va_end(arg); if(p==nil || dorpc(rpc, "start", p, strlen(p), getkey) != ARok || dorpc(rpc, "write", chal, nchal, getkey) != ARok || dorpc(rpc, "read", nil, 0, getkey) != ARok){ free(p); close(afd); auth_freerpc(rpc); return -1; } free(p); if(rpc->narg < nresp) nresp = rpc->narg; memmove(resp, rpc->arg, nresp); if((a = auth_attr(rpc)) != nil && (s = _strfindattr(a, "user")) != nil && strlen(s) < nuser) strcpy(user, s); else if(nuser > 0) user[0] = '\0'; _freeattr(a); close(afd); auth_freerpc(rpc); return nresp; }
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; }
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; } }