Blame


1 2277c5d7 2004-03-21 devnull /*
2 2277c5d7 2004-03-21 devnull * p9sk1, p9sk2 - Plan 9 secret (private) key authentication.
3 2277c5d7 2004-03-21 devnull * p9sk2 is an incomplete flawed variant of p9sk1.
4 2277c5d7 2004-03-21 devnull *
5 2277c5d7 2004-03-21 devnull * Client protocol:
6 2277c5d7 2004-03-21 devnull * write challenge[challen] (p9sk1 only)
7 2277c5d7 2004-03-21 devnull * read tickreq[tickreqlen]
8 2277c5d7 2004-03-21 devnull * write ticket[ticketlen]
9 2277c5d7 2004-03-21 devnull * read authenticator[authentlen]
10 2277c5d7 2004-03-21 devnull *
11 2277c5d7 2004-03-21 devnull * Server protocol:
12 2277c5d7 2004-03-21 devnull * read challenge[challen] (p9sk1 only)
13 2277c5d7 2004-03-21 devnull * write tickreq[tickreqlen]
14 2277c5d7 2004-03-21 devnull * read ticket[ticketlen]
15 2277c5d7 2004-03-21 devnull * write authenticator[authentlen]
16 2277c5d7 2004-03-21 devnull */
17 2277c5d7 2004-03-21 devnull
18 2277c5d7 2004-03-21 devnull #include "std.h"
19 2277c5d7 2004-03-21 devnull #include "dat.h"
20 2277c5d7 2004-03-21 devnull
21 2277c5d7 2004-03-21 devnull static int gettickets(Ticketreq*, char*, Key*);
22 2277c5d7 2004-03-21 devnull
23 2277c5d7 2004-03-21 devnull #define max(a, b) ((a) > (b) ? (a) : (b))
24 2277c5d7 2004-03-21 devnull enum
25 2277c5d7 2004-03-21 devnull {
26 2277c5d7 2004-03-21 devnull MAXAUTH = max(TICKREQLEN, TICKETLEN+max(TICKETLEN, AUTHENTLEN))
27 2277c5d7 2004-03-21 devnull };
28 2277c5d7 2004-03-21 devnull
29 2277c5d7 2004-03-21 devnull static int
30 2277c5d7 2004-03-21 devnull p9skclient(Conv *c)
31 2277c5d7 2004-03-21 devnull {
32 2277c5d7 2004-03-21 devnull char *user;
33 2277c5d7 2004-03-21 devnull char cchal[CHALLEN];
34 2277c5d7 2004-03-21 devnull uchar secret[8];
35 2277c5d7 2004-03-21 devnull char buf[MAXAUTH];
36 2277c5d7 2004-03-21 devnull int speakfor, ret;
37 2277c5d7 2004-03-21 devnull Attr *a;
38 2277c5d7 2004-03-21 devnull Authenticator au;
39 2277c5d7 2004-03-21 devnull Key *k;
40 2277c5d7 2004-03-21 devnull Ticket t;
41 2277c5d7 2004-03-21 devnull Ticketreq tr;
42 2277c5d7 2004-03-21 devnull
43 2277c5d7 2004-03-21 devnull ret = -1;
44 2277c5d7 2004-03-21 devnull a = nil;
45 2277c5d7 2004-03-21 devnull k = nil;
46 2277c5d7 2004-03-21 devnull
47 2277c5d7 2004-03-21 devnull /* p9sk1: send client challenge */
48 2277c5d7 2004-03-21 devnull if(c->proto == &p9sk1){
49 2277c5d7 2004-03-21 devnull c->state = "write challenge";
50 2277c5d7 2004-03-21 devnull memrandom(cchal, CHALLEN);
51 2277c5d7 2004-03-21 devnull if(convwrite(c, cchal, CHALLEN) < 0)
52 2277c5d7 2004-03-21 devnull goto out;
53 2277c5d7 2004-03-21 devnull }
54 2277c5d7 2004-03-21 devnull
55 2277c5d7 2004-03-21 devnull /* read ticket request */
56 2277c5d7 2004-03-21 devnull c->state = "read tickreq";
57 2277c5d7 2004-03-21 devnull if(convread(c, buf, TICKREQLEN) < 0)
58 2277c5d7 2004-03-21 devnull goto out;
59 2277c5d7 2004-03-21 devnull convM2TR(buf, &tr);
60 2277c5d7 2004-03-21 devnull
61 2277c5d7 2004-03-21 devnull /* p9sk2: use server challenge as client challenge */
62 2277c5d7 2004-03-21 devnull if(c->proto == &p9sk2)
63 2277c5d7 2004-03-21 devnull memmove(cchal, tr.chal, CHALLEN);
64 2277c5d7 2004-03-21 devnull
65 2277c5d7 2004-03-21 devnull /*
66 2277c5d7 2004-03-21 devnull * find a key.
67 2277c5d7 2004-03-21 devnull *
68 2277c5d7 2004-03-21 devnull * if the user is the factotum owner, any key will do.
69 2277c5d7 2004-03-21 devnull * if not, then if we have a speakfor key,
70 2277c5d7 2004-03-21 devnull * we will only vouch for the user's local identity.
71 2277c5d7 2004-03-21 devnull *
72 2277c5d7 2004-03-21 devnull * this logic is duplicated in p9any.c
73 2277c5d7 2004-03-21 devnull */
74 2277c5d7 2004-03-21 devnull user = strfindattr(c->attr, "user");
75 2277c5d7 2004-03-21 devnull a = delattr(copyattr(c->attr), "role");
76 2277c5d7 2004-03-21 devnull a = addattr(a, "proto=p9sk1");
77 2277c5d7 2004-03-21 devnull
78 2277c5d7 2004-03-21 devnull if(strcmp(c->sysuser, owner) == 0){
79 2277c5d7 2004-03-21 devnull speakfor = 0;
80 2277c5d7 2004-03-21 devnull a = addattr(a, "proto=p9sk1 user? dom=%q", tr.authdom);
81 2277c5d7 2004-03-21 devnull }else if(user==nil || strcmp(c->sysuser, user)==0){
82 2277c5d7 2004-03-21 devnull speakfor = 1;
83 2277c5d7 2004-03-21 devnull a = delattr(a, "user");
84 2277c5d7 2004-03-21 devnull a = addattr(a, "proto=p9sk1 user? dom=%q role=speakfor", tr.authdom);
85 2277c5d7 2004-03-21 devnull }else{
86 2277c5d7 2004-03-21 devnull werrstr("will not authenticate for %q as %q", c->sysuser, user);
87 2277c5d7 2004-03-21 devnull goto out;
88 2277c5d7 2004-03-21 devnull }
89 2277c5d7 2004-03-21 devnull
90 2277c5d7 2004-03-21 devnull for(;;){
91 2277c5d7 2004-03-21 devnull c->state = "find key";
92 2277c5d7 2004-03-21 devnull k = keyfetch(c, "%A", a);
93 2277c5d7 2004-03-21 devnull if(k == nil)
94 2277c5d7 2004-03-21 devnull goto out;
95 2277c5d7 2004-03-21 devnull
96 2277c5d7 2004-03-21 devnull /* relay ticket request to auth server, get tickets */
97 2277c5d7 2004-03-21 devnull strcpy(tr.hostid, strfindattr(k->attr, "user"));
98 2277c5d7 2004-03-21 devnull if(speakfor)
99 2277c5d7 2004-03-21 devnull strcpy(tr.uid, c->sysuser);
100 2277c5d7 2004-03-21 devnull else
101 2277c5d7 2004-03-21 devnull strcpy(tr.uid, tr.hostid);
102 2277c5d7 2004-03-21 devnull
103 2277c5d7 2004-03-21 devnull c->state = "get tickets";
104 2277c5d7 2004-03-21 devnull if(gettickets(&tr, buf, k) < 0)
105 2277c5d7 2004-03-21 devnull goto out;
106 2277c5d7 2004-03-21 devnull
107 2277c5d7 2004-03-21 devnull convM2T(buf, &t, k->priv);
108 2277c5d7 2004-03-21 devnull if(t.num == AuthTc)
109 2277c5d7 2004-03-21 devnull break;
110 2277c5d7 2004-03-21 devnull
111 2277c5d7 2004-03-21 devnull /* we don't agree with the auth server about the key; try again */
112 2277c5d7 2004-03-21 devnull c->state = "replace key";
113 2277c5d7 2004-03-21 devnull if((k = keyreplace(c, k, "key mismatch with auth server")) == nil){
114 2277c5d7 2004-03-21 devnull werrstr("key mismatch with auth server");
115 2277c5d7 2004-03-21 devnull goto out;
116 2277c5d7 2004-03-21 devnull }
117 2277c5d7 2004-03-21 devnull }
118 2277c5d7 2004-03-21 devnull
119 2277c5d7 2004-03-21 devnull /* send second ticket and authenticator to server */
120 2277c5d7 2004-03-21 devnull c->state = "write ticket+auth";
121 2277c5d7 2004-03-21 devnull memmove(buf, buf+TICKETLEN, TICKETLEN);
122 2277c5d7 2004-03-21 devnull au.num = AuthAc;
123 2277c5d7 2004-03-21 devnull memmove(au.chal, tr.chal, CHALLEN);
124 2277c5d7 2004-03-21 devnull au.id = 0;
125 2277c5d7 2004-03-21 devnull convA2M(&au, buf+TICKETLEN, t.key);
126 2277c5d7 2004-03-21 devnull if(convwrite(c, buf, TICKETLEN+AUTHENTLEN) < 0)
127 2277c5d7 2004-03-21 devnull goto out;
128 2277c5d7 2004-03-21 devnull
129 2277c5d7 2004-03-21 devnull /* read authenticator from server */
130 2277c5d7 2004-03-21 devnull c->state = "read auth";
131 2277c5d7 2004-03-21 devnull if(convread(c, buf, AUTHENTLEN) < 0)
132 2277c5d7 2004-03-21 devnull goto out;
133 2277c5d7 2004-03-21 devnull convM2A(buf, &au, t.key);
134 2277c5d7 2004-03-21 devnull if(au.num != AuthAs || memcmp(au.chal, cchal, CHALLEN) != 0 || au.id != 0){
135 2277c5d7 2004-03-21 devnull werrstr("server lies through his teeth");
136 2277c5d7 2004-03-21 devnull goto out;
137 2277c5d7 2004-03-21 devnull }
138 2277c5d7 2004-03-21 devnull
139 2277c5d7 2004-03-21 devnull /* success */
140 2277c5d7 2004-03-21 devnull c->attr = addcap(c->attr, c->sysuser, &t);
141 2277c5d7 2004-03-21 devnull des56to64((uchar*)t.key, secret);
142 2277c5d7 2004-03-21 devnull c->attr = addattr(c->attr, "secret=%.8H", secret);
143 2277c5d7 2004-03-21 devnull ret = 0;
144 2277c5d7 2004-03-21 devnull
145 2277c5d7 2004-03-21 devnull out:
146 2277c5d7 2004-03-21 devnull freeattr(a);
147 2277c5d7 2004-03-21 devnull keyclose(k);
148 2277c5d7 2004-03-21 devnull return ret;
149 2277c5d7 2004-03-21 devnull }
150 2277c5d7 2004-03-21 devnull
151 2277c5d7 2004-03-21 devnull static int
152 2277c5d7 2004-03-21 devnull p9skserver(Conv *c)
153 2277c5d7 2004-03-21 devnull {
154 2277c5d7 2004-03-21 devnull char cchal[CHALLEN], buf[MAXAUTH];
155 2277c5d7 2004-03-21 devnull uchar secret[8];
156 2277c5d7 2004-03-21 devnull int ret;
157 2277c5d7 2004-03-21 devnull Attr *a;
158 2277c5d7 2004-03-21 devnull Authenticator au;
159 2277c5d7 2004-03-21 devnull Key *k;
160 2277c5d7 2004-03-21 devnull Ticketreq tr;
161 2277c5d7 2004-03-21 devnull Ticket t;
162 2277c5d7 2004-03-21 devnull
163 2277c5d7 2004-03-21 devnull ret = -1;
164 2277c5d7 2004-03-21 devnull
165 2277c5d7 2004-03-21 devnull a = addattr(copyattr(c->attr), "user? dom?");
166 2277c5d7 2004-03-21 devnull a = addattr(a, "user? dom? proto=p9sk1");
167 2277c5d7 2004-03-21 devnull if((k = keyfetch(c, "%A", a)) == nil)
168 2277c5d7 2004-03-21 devnull goto out;
169 2277c5d7 2004-03-21 devnull
170 2277c5d7 2004-03-21 devnull /* p9sk1: read client challenge */
171 2277c5d7 2004-03-21 devnull if(c->proto == &p9sk1){
172 2277c5d7 2004-03-21 devnull if(convread(c, cchal, CHALLEN) < 0)
173 2277c5d7 2004-03-21 devnull goto out;
174 2277c5d7 2004-03-21 devnull }
175 2277c5d7 2004-03-21 devnull
176 2277c5d7 2004-03-21 devnull /* send ticket request */
177 2277c5d7 2004-03-21 devnull memset(&tr, 0, sizeof tr);
178 2277c5d7 2004-03-21 devnull tr.type = AuthTreq;
179 2277c5d7 2004-03-21 devnull strcpy(tr.authid, strfindattr(k->attr, "user"));
180 2277c5d7 2004-03-21 devnull strcpy(tr.authdom, strfindattr(k->attr, "dom"));
181 2277c5d7 2004-03-21 devnull memrandom(tr.chal, sizeof tr.chal);
182 2277c5d7 2004-03-21 devnull convTR2M(&tr, buf);
183 2277c5d7 2004-03-21 devnull if(convwrite(c, buf, TICKREQLEN) < 0)
184 2277c5d7 2004-03-21 devnull goto out;
185 2277c5d7 2004-03-21 devnull
186 2277c5d7 2004-03-21 devnull /* p9sk2: use server challenge as client challenge */
187 2277c5d7 2004-03-21 devnull if(c->proto == &p9sk2)
188 2277c5d7 2004-03-21 devnull memmove(cchal, tr.chal, sizeof tr.chal);
189 2277c5d7 2004-03-21 devnull
190 2277c5d7 2004-03-21 devnull /* read ticket+authenticator */
191 2277c5d7 2004-03-21 devnull if(convread(c, buf, TICKETLEN+AUTHENTLEN) < 0)
192 2277c5d7 2004-03-21 devnull goto out;
193 2277c5d7 2004-03-21 devnull
194 2277c5d7 2004-03-21 devnull convM2T(buf, &t, k->priv);
195 2277c5d7 2004-03-21 devnull if(t.num != AuthTs || memcmp(t.chal, tr.chal, CHALLEN) != 0){
196 2277c5d7 2004-03-21 devnull /* BUG badkey */
197 2277c5d7 2004-03-21 devnull werrstr("key mismatch with auth server");
198 2277c5d7 2004-03-21 devnull goto out;
199 2277c5d7 2004-03-21 devnull }
200 2277c5d7 2004-03-21 devnull
201 2277c5d7 2004-03-21 devnull convM2A(buf+TICKETLEN, &au, t.key);
202 2277c5d7 2004-03-21 devnull if(au.num != AuthAc || memcmp(au.chal, tr.chal, CHALLEN) != 0 || au.id != 0){
203 2277c5d7 2004-03-21 devnull werrstr("client lies through his teeth");
204 2277c5d7 2004-03-21 devnull goto out;
205 2277c5d7 2004-03-21 devnull }
206 2277c5d7 2004-03-21 devnull
207 2277c5d7 2004-03-21 devnull /* send authenticator */
208 2277c5d7 2004-03-21 devnull au.num = AuthAs;
209 2277c5d7 2004-03-21 devnull memmove(au.chal, cchal, CHALLEN);
210 2277c5d7 2004-03-21 devnull convA2M(&au, buf, t.key);
211 2277c5d7 2004-03-21 devnull if(convwrite(c, buf, AUTHENTLEN) < 0)
212 2277c5d7 2004-03-21 devnull goto out;
213 2277c5d7 2004-03-21 devnull
214 2277c5d7 2004-03-21 devnull /* success */
215 2277c5d7 2004-03-21 devnull c->attr = addcap(c->attr, c->sysuser, &t);
216 2277c5d7 2004-03-21 devnull des56to64((uchar*)t.key, secret);
217 2277c5d7 2004-03-21 devnull c->attr = addattr(c->attr, "secret=%.8H", secret);
218 2277c5d7 2004-03-21 devnull ret = 0;
219 2277c5d7 2004-03-21 devnull
220 2277c5d7 2004-03-21 devnull out:
221 2277c5d7 2004-03-21 devnull freeattr(a);
222 2277c5d7 2004-03-21 devnull keyclose(k);
223 2277c5d7 2004-03-21 devnull return ret;
224 2277c5d7 2004-03-21 devnull }
225 2277c5d7 2004-03-21 devnull
226 2277c5d7 2004-03-21 devnull int
227 2277c5d7 2004-03-21 devnull _asgetticket(int fd, char *trbuf, char *tbuf)
228 2277c5d7 2004-03-21 devnull {
229 2277c5d7 2004-03-21 devnull if(write(fd, trbuf, TICKREQLEN) < 0){
230 2277c5d7 2004-03-21 devnull close(fd);
231 2277c5d7 2004-03-21 devnull return -1;
232 2277c5d7 2004-03-21 devnull }
233 2277c5d7 2004-03-21 devnull return _asrdresp(fd, tbuf, 2*TICKETLEN);
234 2277c5d7 2004-03-21 devnull }
235 2277c5d7 2004-03-21 devnull static int
236 2277c5d7 2004-03-21 devnull getastickets(Ticketreq *tr, char *buf)
237 2277c5d7 2004-03-21 devnull {
238 2277c5d7 2004-03-21 devnull int asfd;
239 2277c5d7 2004-03-21 devnull int ret;
240 2277c5d7 2004-03-21 devnull
241 2277c5d7 2004-03-21 devnull if((asfd = xioauthdial(nil, tr->authdom)) < 0)
242 2277c5d7 2004-03-21 devnull return -1;
243 2277c5d7 2004-03-21 devnull convTR2M(tr, buf);
244 2277c5d7 2004-03-21 devnull ret = xioasgetticket(asfd, buf, buf);
245 2277c5d7 2004-03-21 devnull xioclose(asfd);
246 2277c5d7 2004-03-21 devnull return ret;
247 2277c5d7 2004-03-21 devnull }
248 2277c5d7 2004-03-21 devnull
249 2277c5d7 2004-03-21 devnull static int
250 2277c5d7 2004-03-21 devnull mktickets(Ticketreq *tr, char *buf, Key *k)
251 2277c5d7 2004-03-21 devnull {
252 2277c5d7 2004-03-21 devnull Ticket t;
253 2277c5d7 2004-03-21 devnull
254 2277c5d7 2004-03-21 devnull if(strcmp(tr->authid, tr->hostid) != 0)
255 2277c5d7 2004-03-21 devnull return -1;
256 2277c5d7 2004-03-21 devnull
257 2277c5d7 2004-03-21 devnull memset(&t, 0, sizeof t);
258 2277c5d7 2004-03-21 devnull memmove(t.chal, tr->chal, CHALLEN);
259 2277c5d7 2004-03-21 devnull strcpy(t.cuid, tr->uid);
260 2277c5d7 2004-03-21 devnull strcpy(t.suid, tr->uid);
261 2277c5d7 2004-03-21 devnull memrandom(t.key, DESKEYLEN);
262 2277c5d7 2004-03-21 devnull t.num = AuthTc;
263 2277c5d7 2004-03-21 devnull convT2M(&t, buf, k->priv);
264 2277c5d7 2004-03-21 devnull t.num = AuthTs;
265 2277c5d7 2004-03-21 devnull convT2M(&t, buf+TICKETLEN, k->priv);
266 2277c5d7 2004-03-21 devnull return 0;
267 2277c5d7 2004-03-21 devnull }
268 2277c5d7 2004-03-21 devnull
269 2277c5d7 2004-03-21 devnull static int
270 2277c5d7 2004-03-21 devnull gettickets(Ticketreq *tr, char *buf, Key *k)
271 2277c5d7 2004-03-21 devnull {
272 2277c5d7 2004-03-21 devnull if(getastickets(tr, buf) == 0)
273 2277c5d7 2004-03-21 devnull return 0;
274 2277c5d7 2004-03-21 devnull if(mktickets(tr, buf, k) == 0)
275 2277c5d7 2004-03-21 devnull return 0;
276 2277c5d7 2004-03-21 devnull werrstr("gettickets: %r");
277 2277c5d7 2004-03-21 devnull return -1;
278 2277c5d7 2004-03-21 devnull }
279 2277c5d7 2004-03-21 devnull
280 2277c5d7 2004-03-21 devnull static int
281 2277c5d7 2004-03-21 devnull p9sk1check(Key *k)
282 2277c5d7 2004-03-21 devnull {
283 2277c5d7 2004-03-21 devnull char *user, *dom, *pass;
284 2277c5d7 2004-03-21 devnull Ticketreq tr;
285 2277c5d7 2004-03-21 devnull
286 2277c5d7 2004-03-21 devnull user = strfindattr(k->attr, "user");
287 2277c5d7 2004-03-21 devnull dom = strfindattr(k->attr, "dom");
288 2277c5d7 2004-03-21 devnull if(user==nil || dom==nil){
289 2277c5d7 2004-03-21 devnull werrstr("need user and dom attributes");
290 2277c5d7 2004-03-21 devnull return -1;
291 2277c5d7 2004-03-21 devnull }
292 2277c5d7 2004-03-21 devnull if(strlen(user) >= sizeof tr.authid){
293 2277c5d7 2004-03-21 devnull werrstr("user name too long");
294 2277c5d7 2004-03-21 devnull return -1;
295 2277c5d7 2004-03-21 devnull }
296 2277c5d7 2004-03-21 devnull if(strlen(dom) >= sizeof tr.authdom){
297 2277c5d7 2004-03-21 devnull werrstr("auth dom name too long");
298 2277c5d7 2004-03-21 devnull return -1;
299 2277c5d7 2004-03-21 devnull }
300 2277c5d7 2004-03-21 devnull
301 2277c5d7 2004-03-21 devnull k->priv = emalloc(DESKEYLEN);
302 2277c5d7 2004-03-21 devnull if(pass = strfindattr(k->privattr, "!password"))
303 2277c5d7 2004-03-21 devnull passtokey(k->priv, pass);
304 2277c5d7 2004-03-21 devnull else if(pass = strfindattr(k->privattr, "!hex")){
305 2277c5d7 2004-03-21 devnull if(hexparse(pass, k->priv, 7) < 0){
306 2277c5d7 2004-03-21 devnull werrstr("malformed !hex key data");
307 2277c5d7 2004-03-21 devnull return -1;
308 2277c5d7 2004-03-21 devnull }
309 2277c5d7 2004-03-21 devnull }else{
310 2277c5d7 2004-03-21 devnull werrstr("need !password or !hex attribute");
311 2277c5d7 2004-03-21 devnull return -1;
312 2277c5d7 2004-03-21 devnull }
313 2277c5d7 2004-03-21 devnull
314 2277c5d7 2004-03-21 devnull return 0;
315 2277c5d7 2004-03-21 devnull }
316 2277c5d7 2004-03-21 devnull
317 2277c5d7 2004-03-21 devnull static void
318 2277c5d7 2004-03-21 devnull p9sk1close(Key *k)
319 2277c5d7 2004-03-21 devnull {
320 2277c5d7 2004-03-21 devnull free(k->priv);
321 2277c5d7 2004-03-21 devnull k->priv = nil;
322 2277c5d7 2004-03-21 devnull }
323 2277c5d7 2004-03-21 devnull
324 2277c5d7 2004-03-21 devnull static Role
325 2277c5d7 2004-03-21 devnull p9sk1roles[] =
326 2277c5d7 2004-03-21 devnull {
327 2277c5d7 2004-03-21 devnull "client", p9skclient,
328 2277c5d7 2004-03-21 devnull "server", p9skserver,
329 2277c5d7 2004-03-21 devnull 0
330 2277c5d7 2004-03-21 devnull };
331 2277c5d7 2004-03-21 devnull
332 2277c5d7 2004-03-21 devnull static Role
333 2277c5d7 2004-03-21 devnull p9sk2roles[] =
334 2277c5d7 2004-03-21 devnull {
335 2277c5d7 2004-03-21 devnull "client", p9skclient,
336 2277c5d7 2004-03-21 devnull "server", p9skserver,
337 2277c5d7 2004-03-21 devnull 0
338 2277c5d7 2004-03-21 devnull };
339 2277c5d7 2004-03-21 devnull
340 2277c5d7 2004-03-21 devnull Proto p9sk1 = {
341 2277c5d7 2004-03-21 devnull .name= "p9sk1",
342 2277c5d7 2004-03-21 devnull .roles= p9sk1roles,
343 2277c5d7 2004-03-21 devnull .checkkey= p9sk1check,
344 2277c5d7 2004-03-21 devnull .closekey= p9sk1close,
345 2277c5d7 2004-03-21 devnull .keyprompt= "user? dom? !password?",
346 2277c5d7 2004-03-21 devnull };
347 2277c5d7 2004-03-21 devnull
348 2277c5d7 2004-03-21 devnull Proto p9sk2 = {
349 2277c5d7 2004-03-21 devnull .name= "p9sk2",
350 2277c5d7 2004-03-21 devnull .roles= p9sk2roles,
351 2277c5d7 2004-03-21 devnull };
352 2277c5d7 2004-03-21 devnull