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; }
Attr* _delattr(Attr *a, char *name) { Attr *fa; Attr **la; for(la=&a; *la; ) { if(strcmp((*la)->name, name) == 0) { fa = *la; *la = (*la)->next; fa->next = nil; _freeattr(fa); } else la=&(*la)->next; } return a; }
static Attr* cleanattr(Attr *a) { Attr *fa; Attr **la; for(la=&a; *la; ) { if((*la)->type==AttrQuery && _findattr(a, (*la)->name)) { fa = *la; *la = (*la)->next; fa->next = nil; _freeattr(fa); } else la=&(*la)->next; } return a; }
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); }
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; } }