2 * p9cr - one-sided challenge/response authentication
11 * Note that this is the protocol between factotum and the local
12 * program, not between the two factotums. The information
13 * exchanged here is wrapped in other protocols by the local
20 /* shared with auth dialing routines */
21 typedef struct ServerState ServerState;
38 extern Proto p9cr, vnc;
39 static int p9response(char*, uchar*, uchar*);
40 // static int vncresponse(char*, uchar*, uchar*);
41 static int p9crchal(ServerState *s, int, char*, uchar*, int);
42 static int p9crresp(ServerState*, uchar*, int);
47 if(!strfindattr(k->attr, "user") || !strfindattr(k->privattr, "!password")){
48 werrstr("need user and !password attributes");
57 char *pw, *res, *user;
58 int astype, challen, resplen, ntry, ret;
61 uchar chal[MAXCHAL+1], resp[MAXRESP];
62 int (*response)(char*, uchar*, uchar*);
69 if(c->proto == &p9cr){
72 response = p9response;
73 attr = _mkattr(AttrNameval, "proto", "p9sk1", _delattr(_copyattr(attr), "proto"));
74 }else if(c->proto == &vnc){
77 // response = vncresponse;
85 c->state = "find key";
86 k = keyfetch(c, "%A %s", attr, c->proto->keyprompt);
93 c->attr = addattrs(copyattr(attr), k->attr);
95 if((pw = strfindattr(k->privattr, "!password")) == nil){
96 werrstr("key has no !password (cannot happen)");
99 if((user = strfindattr(k->attr, "user")) == nil){
100 werrstr("key has no user (cannot happen)");
104 if(convprint(c, "%s", user) < 0)
107 if(convread(c, chal, challen) < 0)
111 if((resplen = (*response)(pw, chal, resp)) < 0)
114 if(convwrite(c, resp, resplen) < 0)
117 if(convreadm(c, &res) < 0)
120 if(strcmp(res, "ok") == 0)
123 if((k = keyreplace(c, k, "%s", res)) == nil){
124 c->state = "auth failed";
130 werrstr("succeeded");
143 uchar chal[MAXCHAL], *resp, *resp1;
146 int astype, ret, challen, resplen;
152 memset(&s, 0, sizeof s);
155 if(c->proto == &p9cr){
158 }else if(c->proto == &vnc){
162 werrstr("bad proto");
166 c->state = "find key";
167 if((s.k = plan9authkey(c->attr)) == nil)
170 a = copyattr(s.k->attr);
171 a = delattr(a, "proto");
172 c->attr = addattrs(c->attr, a);
175 c->state = "authdial";
176 s.hostid = strfindattr(s.k->attr, "user");
177 s.dom = strfindattr(s.k->attr, "dom");
178 if((s.asfd = xioauthdial(nil, s.dom)) < 0){
179 werrstr("authdial %s: %r", s.dom);
184 c->state = "read user";
185 if(convreadm(c, &user) < 0)
188 c->state = "authchal";
189 if(p9crchal(&s, astype, user, chal, challen) < 0)
192 c->state = "write challenge";
193 if(convwrite(c, chal, challen) < 0)
196 c->state = "read response";
197 if((resplen = convreadm(c, (char**)(void*)&resp)) < 0)
199 if(c->proto == &p9cr){
200 if(resplen > NETCHLEN){
201 convprint(c, "bad response too long");
204 resp1 = emalloc(NETCHLEN);
205 memset(resp1, 0, NETCHLEN);
206 memmove(resp1, resp, resplen);
212 c->state = "authwrite";
213 switch(p9crresp(&s, resp, resplen)){
215 fprint(2, "p9crresp: %r\n");
218 c->state = "write status";
219 if(convprint(c, "bad authentication failed") < 0)
223 c->state = "write status";
224 if(convprint(c, "ok") < 0)
236 c->attr = addcap(c->attr, c->sysuser, &s.t);
247 p9crchal(ServerState *s, int astype, char *user, uchar *chal, int challen)
249 char trbuf[TICKREQLEN];
253 memset(&tr, 0, sizeof tr);
257 if(strlen(s->hostid) >= sizeof tr.hostid){
258 werrstr("hostid too long");
261 strcpy(tr.hostid, s->hostid);
263 if(strlen(s->dom) >= sizeof tr.authdom){
264 werrstr("domain too long");
267 strcpy(tr.authdom, s->dom);
269 if(strlen(user) >= sizeof tr.uid){
270 werrstr("user name too long");
273 strcpy(tr.uid, user);
274 convTR2M(&tr, trbuf);
276 if(xiowrite(s->asfd, trbuf, TICKREQLEN) != TICKREQLEN)
279 if((n=xioasrdresp(s->asfd, chal, challen)) <= 0)
285 p9crresp(ServerState *s, uchar *resp, int resplen)
287 char tabuf[TICKETLEN+AUTHENTLEN];
292 if(xiowrite(s->asfd, resp, resplen) != resplen)
295 if(xioasrdresp(s->asfd, tabuf, TICKETLEN+AUTHENTLEN) != TICKETLEN+AUTHENTLEN)
298 convM2T(tabuf, &t, s->k->priv);
300 || memcmp(t.chal, tr.chal, sizeof tr.chal) != 0){
301 werrstr("key mismatch with auth server");
305 convM2A(tabuf+TICKETLEN, &a, t.key);
307 || memcmp(a.chal, tr.chal, sizeof a.chal) != 0
309 werrstr("key2 mismatch with auth server");
318 p9response(char *pw, uchar *chal, uchar *resp)
326 snprint((char*)buf, sizeof buf, "%d", atoi((char*)chal));
327 if(encrypt(key, buf, 8) < 0){
328 werrstr("can't encrypt response");
331 x = (buf[0]<<24)+(buf[1]<<16)+(buf[2]<<8)+buf[3];
332 return snprint((char*)resp, MAXRESP, "%.8lux", x);
337 vncresponse(char *pw, uchar *chal, uchar *resp)
341 memmove(resp, chal, MAXCHAL);
342 setupDESstate(&des, 0, nil); // XXX put key in for 0
343 desECBencrypt(resp, MAXCHAL, &des);
351 "client", p9crclient,
352 "server", p9crserver,
364 /* still need to implement vnc key generator */