Commit | Line | Data |
---|---|---|
805e021f CE |
1 | /* |
2 | * Copyright 2000, International Business Machines Corporation and others. | |
3 | * All Rights Reserved. | |
4 | * | |
5 | * This software has been released under the terms of the IBM Public | |
6 | * License. For details, see the LICENSE file in the top-level source | |
7 | * directory or online at http://www.openafs.org/dl/license10.html | |
8 | */ | |
9 | ||
10 | /* These routines provide a convenient interface to the AuthServer. */ | |
11 | ||
12 | #include <afsconfig.h> | |
13 | #include <afs/param.h> | |
14 | #include <afs/stds.h> | |
15 | ||
16 | #include <roken.h> | |
17 | #include <afs/opr.h> | |
18 | ||
19 | #ifdef IGNORE_SOME_GCC_WARNINGS | |
20 | # pragma GCC diagnostic warning "-Wstrict-prototypes" | |
21 | # pragma GCC diagnostic warning "-Wimplicit-function-declaration" | |
22 | #endif | |
23 | ||
24 | #include <hcrypto/des.h> | |
25 | ||
26 | #define UBIK_LEGACY_CALLITER 1 | |
27 | ||
28 | #include <afs/pthread_glock.h> | |
29 | #include <rx/rxkad.h> | |
30 | #include <rx/rxkad_convert.h> | |
31 | #include <afs/cellconfig.h> | |
32 | #include <ubik.h> | |
33 | #include <afs/auth.h> | |
34 | #include <afs/afsutil.h> | |
35 | ||
36 | #include "kauth.h" | |
37 | #include "kautils.h" | |
38 | ||
39 | static struct afsconf_dir *conf = 0; | |
40 | static struct afsconf_cell explicit_cell_server_list; | |
41 | static struct afsconf_cell debug_cell_server_list; | |
42 | static int explicit = 0; | |
43 | static int debug = 0; | |
44 | ||
45 | #ifdef ENCRYPTIONBLOCKSIZE | |
46 | #undef ENCRYPTIONBLOCKSIZE | |
47 | #endif | |
48 | #define ENCRYPTIONBLOCKSIZE (sizeof(DES_cblock)) | |
49 | ||
50 | /* Copy the specified list of servers into a specially know cell named | |
51 | "explicit". The cell can then be used to debug experimental servers. */ | |
52 | ||
53 | void | |
54 | ka_ExplicitCell(char *cell, afs_uint32 serverList[]) | |
55 | { | |
56 | int i; | |
57 | ||
58 | LOCK_GLOBAL_MUTEX; | |
59 | ka_ExpandCell(cell, explicit_cell_server_list.name, 0); | |
60 | for (i = 0; i < MAXHOSTSPERCELL; i++) | |
61 | if (serverList[i]) { | |
62 | explicit_cell_server_list.numServers = i + 1; | |
63 | explicit_cell_server_list.hostAddr[i].sin_family = AF_INET; | |
64 | explicit_cell_server_list.hostAddr[i].sin_addr.s_addr = | |
65 | serverList[i]; | |
66 | explicit_cell_server_list.hostName[i][0] = 0; | |
67 | explicit_cell_server_list.hostAddr[i].sin_port = | |
68 | htons(AFSCONF_KAUTHPORT); | |
69 | #ifdef STRUCT_SOCKADDR_HAS_SA_LEN | |
70 | explicit_cell_server_list.hostAddr[i].sin_len = | |
71 | sizeof(struct sockaddr_in); | |
72 | #endif | |
73 | explicit = 1; | |
74 | } else | |
75 | break; | |
76 | UNLOCK_GLOBAL_MUTEX; | |
77 | } | |
78 | ||
79 | static int | |
80 | myCellLookup(struct afsconf_dir *conf, char *cell, char *service, | |
81 | struct afsconf_cell *cellinfo) | |
82 | { | |
83 | if (debug) { | |
84 | *cellinfo = debug_cell_server_list; | |
85 | return 0; | |
86 | } else if (explicit | |
87 | && (strcmp(cell, explicit_cell_server_list.name) == 0)) { | |
88 | *cellinfo = explicit_cell_server_list; | |
89 | return 0; | |
90 | } | |
91 | /* call the real one */ | |
92 | else | |
93 | return afsconf_GetCellInfo(conf, cell, service, cellinfo); | |
94 | } | |
95 | ||
96 | afs_int32 | |
97 | ka_GetServers(char *cell, struct afsconf_cell * cellinfo) | |
98 | { | |
99 | afs_int32 code; | |
100 | char cellname[MAXKTCREALMLEN]; | |
101 | ||
102 | LOCK_GLOBAL_MUTEX; | |
103 | if (cell == NULL || strlen(cell) == 0) | |
104 | cell = NULL; | |
105 | else | |
106 | cell = lcstring(cellname, cell, sizeof(cellname)); | |
107 | ||
108 | if (!conf) { | |
109 | conf = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH); | |
110 | if (!conf) { | |
111 | UNLOCK_GLOBAL_MUTEX; | |
112 | return KANOCELLS; | |
113 | } | |
114 | } | |
115 | code = myCellLookup(conf, cell, AFSCONF_KAUTHSERVICE, cellinfo); | |
116 | UNLOCK_GLOBAL_MUTEX; | |
117 | return code; | |
118 | } | |
119 | ||
120 | afs_int32 | |
121 | ka_GetSecurity(int service, struct ktc_token * token, | |
122 | struct rx_securityClass ** scP, int *siP) | |
123 | { /* security class index */ | |
124 | LOCK_GLOBAL_MUTEX; | |
125 | *scP = 0; | |
126 | switch (service) { | |
127 | case KA_AUTHENTICATION_SERVICE: | |
128 | case KA_TICKET_GRANTING_SERVICE: | |
129 | no_security: | |
130 | *scP = rxnull_NewClientSecurityObject(); | |
131 | *siP = RX_SECIDX_NULL; | |
132 | break; | |
133 | case KA_MAINTENANCE_SERVICE: | |
134 | if (!token) | |
135 | goto no_security; | |
136 | *scP = | |
137 | rxkad_NewClientSecurityObject(rxkad_crypt, &token->sessionKey, | |
138 | token->kvno, token->ticketLen, | |
139 | token->ticket); | |
140 | *siP = RX_SECIDX_KAD; | |
141 | break; | |
142 | default: | |
143 | UNLOCK_GLOBAL_MUTEX; | |
144 | return KABADARGUMENT; | |
145 | } | |
146 | if (*scP == 0) { | |
147 | printf("Failed gettting security object\n"); | |
148 | UNLOCK_GLOBAL_MUTEX; | |
149 | return KARXFAIL; | |
150 | } | |
151 | UNLOCK_GLOBAL_MUTEX; | |
152 | return 0; | |
153 | } | |
154 | ||
155 | afs_int32 | |
156 | ka_SingleServerConn(char *cell, char *server, /* name of server to contact */ | |
157 | int service, struct ktc_token * token, | |
158 | struct ubik_client ** conn) | |
159 | { | |
160 | afs_int32 code; | |
161 | struct rx_connection *serverconns[2]; | |
162 | struct rx_securityClass *sc; | |
163 | int si; /* security class index */ | |
164 | struct afsconf_cell cellinfo; /* for cell auth server list */ | |
165 | int i; | |
166 | int match; | |
167 | char sname[MAXHOSTCHARS]; | |
168 | int snamel; | |
169 | ||
170 | LOCK_GLOBAL_MUTEX; | |
171 | code = ka_GetServers(cell, &cellinfo); | |
172 | if (code) { | |
173 | UNLOCK_GLOBAL_MUTEX; | |
174 | return code; | |
175 | } | |
176 | ||
177 | lcstring(sname, server, sizeof(sname)); | |
178 | snamel = strlen(sname); | |
179 | match = -1; | |
180 | for (i = 0; i < cellinfo.numServers; i++) { | |
181 | if (strncmp(cellinfo.hostName[i], sname, snamel) == 0) { | |
182 | if (match >= 0) { | |
183 | UNLOCK_GLOBAL_MUTEX; | |
184 | return KANOCELLS; | |
185 | } else | |
186 | match = i; | |
187 | } | |
188 | } | |
189 | if (match < 0) { | |
190 | UNLOCK_GLOBAL_MUTEX; | |
191 | return KANOCELLS; | |
192 | } | |
193 | ||
194 | code = rx_Init(0); | |
195 | if (code) { | |
196 | UNLOCK_GLOBAL_MUTEX; | |
197 | return code; | |
198 | } | |
199 | ||
200 | code = ka_GetSecurity(service, token, &sc, &si); | |
201 | if (code) { | |
202 | UNLOCK_GLOBAL_MUTEX; | |
203 | return code; | |
204 | } | |
205 | #ifdef AFS_PTHREAD_ENV | |
206 | serverconns[0] = | |
207 | rx_GetCachedConnection(cellinfo.hostAddr[match].sin_addr.s_addr, | |
208 | cellinfo.hostAddr[match].sin_port, service, sc, | |
209 | si); | |
210 | #else | |
211 | serverconns[0] = | |
212 | rx_NewConnection(cellinfo.hostAddr[match].sin_addr.s_addr, | |
213 | cellinfo.hostAddr[match].sin_port, service, sc, si); | |
214 | #endif | |
215 | serverconns[1] = 0; /* terminate list */ | |
216 | ||
217 | /* next, pass list of server rx_connections (in serverconns), and a place | |
218 | * to put the returned client structure that we'll use in all of our rpc | |
219 | * calls (via ubik_Call) */ | |
220 | *conn = 0; | |
221 | code = ubik_ClientInit(serverconns, conn); | |
222 | rxs_Release(sc); | |
223 | UNLOCK_GLOBAL_MUTEX; | |
224 | if (code) | |
225 | return KAUBIKINIT; | |
226 | return 0; | |
227 | } | |
228 | ||
229 | afs_int32 | |
230 | ka_AuthSpecificServersConn(int service, struct ktc_token * token, | |
231 | struct afsconf_cell * cellinfo, | |
232 | struct ubik_client ** conn) | |
233 | { | |
234 | afs_int32 code; | |
235 | struct rx_connection *serverconns[MAXSERVERS]; | |
236 | struct rx_securityClass *sc; | |
237 | int si; /* security class index */ | |
238 | int i; | |
239 | ||
240 | LOCK_GLOBAL_MUTEX; | |
241 | code = rx_Init(0); | |
242 | if (code) { | |
243 | UNLOCK_GLOBAL_MUTEX; | |
244 | return code; | |
245 | } | |
246 | ||
247 | code = ka_GetSecurity(service, token, &sc, &si); | |
248 | if (code) { | |
249 | UNLOCK_GLOBAL_MUTEX; | |
250 | return code; | |
251 | } | |
252 | ||
253 | for (i = 0; i < cellinfo->numServers; i++) | |
254 | #ifdef AFS_PTHREAD_ENV | |
255 | serverconns[i] = | |
256 | rx_GetCachedConnection(cellinfo->hostAddr[i].sin_addr.s_addr, | |
257 | cellinfo->hostAddr[i].sin_port, service, | |
258 | sc, si); | |
259 | #else | |
260 | serverconns[i] = | |
261 | rx_NewConnection(cellinfo->hostAddr[i].sin_addr.s_addr, | |
262 | cellinfo->hostAddr[i].sin_port, service, sc, si); | |
263 | #endif | |
264 | serverconns[cellinfo->numServers] = 0; /* terminate list */ | |
265 | ||
266 | /* next, pass list of server rx_connections (in serverconns), and a place | |
267 | * to put the returned client structure that we'll use in all of our rpc | |
268 | * calls (via ubik_Call) */ | |
269 | *conn = 0; | |
270 | code = ubik_ClientInit(serverconns, conn); | |
271 | rxs_Release(sc); | |
272 | UNLOCK_GLOBAL_MUTEX; | |
273 | if (code) | |
274 | return KAUBIKINIT; | |
275 | return 0; | |
276 | } | |
277 | ||
278 | afs_int32 | |
279 | ka_AuthServerConn(char *cell, int service, struct ktc_token * token, | |
280 | struct ubik_client ** conn) | |
281 | { | |
282 | afs_int32 code; | |
283 | struct rx_connection *serverconns[MAXSERVERS]; | |
284 | struct rx_securityClass *sc; | |
285 | int si; /* security class index */ | |
286 | int i; | |
287 | struct afsconf_cell cellinfo; /* for cell auth server list */ | |
288 | ||
289 | LOCK_GLOBAL_MUTEX; | |
290 | code = ka_GetServers(cell, &cellinfo); | |
291 | if (code) { | |
292 | UNLOCK_GLOBAL_MUTEX; | |
293 | return code; | |
294 | } | |
295 | ||
296 | code = rx_Init(0); | |
297 | if (code) { | |
298 | UNLOCK_GLOBAL_MUTEX; | |
299 | return code; | |
300 | } | |
301 | ||
302 | code = ka_GetSecurity(service, token, &sc, &si); | |
303 | if (code) { | |
304 | UNLOCK_GLOBAL_MUTEX; | |
305 | return code; | |
306 | } | |
307 | ||
308 | for (i = 0; i < cellinfo.numServers; i++) | |
309 | #ifdef AFS_PTHREAD_ENV | |
310 | serverconns[i] = | |
311 | rx_GetCachedConnection(cellinfo.hostAddr[i].sin_addr.s_addr, | |
312 | cellinfo.hostAddr[i].sin_port, service, sc, | |
313 | si); | |
314 | #else | |
315 | serverconns[i] = | |
316 | rx_NewConnection(cellinfo.hostAddr[i].sin_addr.s_addr, | |
317 | cellinfo.hostAddr[i].sin_port, service, sc, si); | |
318 | #endif | |
319 | serverconns[cellinfo.numServers] = 0; /* terminate list */ | |
320 | ||
321 | /* next, pass list of server rx_connections (in serverconns), and a place | |
322 | * to put the returned client structure that we'll use in all of our rpc | |
323 | * calls (via ubik_Call) */ | |
324 | *conn = 0; | |
325 | code = ubik_ClientInit(serverconns, conn); | |
326 | rxs_Release(sc); | |
327 | UNLOCK_GLOBAL_MUTEX; | |
328 | if (code) | |
329 | return KAUBIKINIT; | |
330 | return 0; | |
331 | } | |
332 | ||
333 | static afs_int32 | |
334 | CheckTicketAnswer(ka_BBS * oanswer, afs_int32 challenge, | |
335 | struct ktc_token *token, struct ktc_principal *caller, | |
336 | struct ktc_principal *server, char *label, | |
337 | afs_int32 * pwexpires) | |
338 | { | |
339 | struct ka_ticketAnswer *answer; | |
340 | unsigned char tempc; | |
341 | ||
342 | answer = (struct ka_ticketAnswer *)oanswer->SeqBody; | |
343 | ||
344 | if (challenge != ntohl(answer->challenge)) | |
345 | return KABADPROTOCOL; | |
346 | memcpy(&token->sessionKey, &answer->sessionKey, | |
347 | sizeof(token->sessionKey)); | |
348 | token->startTime = ntohl(answer->startTime); | |
349 | token->endTime = ntohl(answer->endTime); | |
350 | token->kvno = (short)ntohl(answer->kvno); | |
351 | token->ticketLen = ntohl(answer->ticketLen); | |
352 | ||
353 | if (tkt_CheckTimes(token->startTime, token->endTime, time(0)) < 0) | |
354 | return KABADPROTOCOL; | |
355 | if ((token->ticketLen < MINKTCTICKETLEN) | |
356 | || (token->ticketLen > MAXKTCTICKETLEN)) | |
357 | return KABADPROTOCOL; | |
358 | ||
359 | { | |
360 | char *strings = answer->name; | |
361 | int len; | |
362 | #undef chkstr | |
363 | #define chkstr(field) \ | |
364 | len = strlen (strings); \ | |
365 | if (len > MAXKTCNAMELEN) return KABADPROTOCOL;\ | |
366 | if ((field) && strcmp (field, strings)) return KABADPROTOCOL;\ | |
367 | strings += len+1 | |
368 | ||
369 | #define chknostr() \ | |
370 | len = strlen(strings); \ | |
371 | if (len > MAXKTCNAMELEN) return KABADPROTOCOL; \ | |
372 | strings += len+1 | |
373 | ||
374 | if (caller) { | |
375 | chkstr(caller->name); | |
376 | chkstr(caller->instance); | |
377 | chkstr(caller->cell); | |
378 | } else { | |
379 | chknostr(); | |
380 | chknostr(); | |
381 | chknostr(); | |
382 | } | |
383 | if (server) { | |
384 | chkstr(server->name); | |
385 | chkstr(server->instance); | |
386 | } else { | |
387 | chknostr(); | |
388 | chknostr(); | |
389 | } | |
390 | ||
391 | if (oanswer->SeqLen - | |
392 | ((strings - oanswer->SeqBody) + token->ticketLen + KA_LABELSIZE) | |
393 | >= (ENCRYPTIONBLOCKSIZE + 12) | |
394 | ) | |
395 | return KABADPROTOCOL; | |
396 | ||
397 | memcpy(token->ticket, strings, token->ticketLen); | |
398 | strings += token->ticketLen; | |
399 | if (memcmp(strings, label, KA_LABELSIZE) != 0) | |
400 | return KABADPROTOCOL; | |
401 | ||
402 | if (pwexpires) { | |
403 | afs_int32 temp; | |
404 | strings += KA_LABELSIZE; | |
405 | temp = round_up_to_ebs((strings - oanswer->SeqBody)); | |
406 | ||
407 | if (oanswer->SeqLen > temp) { | |
408 | strings = oanswer->SeqBody + temp; | |
409 | memcpy(&temp, strings, sizeof(afs_int32)); | |
410 | tempc = ntohl(temp) >> 24; | |
411 | /* don't forget this if you add any more fields! | |
412 | * strings += sizeof(afs_int32); | |
413 | */ | |
414 | } else { | |
415 | tempc = 255; | |
416 | } | |
417 | *pwexpires = tempc; | |
418 | } | |
419 | ||
420 | } | |
421 | return 0; | |
422 | } | |
423 | ||
424 | /* call this instead of stub and we'll guarantee to find a host that's up. | |
425 | * this doesn't handle UNOTSYNC very well, should use ubik_Call if you care | |
426 | */ | |
427 | static afs_int32 | |
428 | kawrap_ubik_Call(int (*aproc) (), struct ubik_client *aclient, | |
429 | afs_int32 aflags, void *p1, void *p2, void *p3, void *p4, | |
430 | void *p5, void *p6, void *p7, void *p8) | |
431 | { | |
432 | afs_int32 code, lcode; | |
433 | int count; | |
434 | int pass; | |
435 | ||
436 | /* First pass only checks servers known running. Second checks all. | |
437 | * Once we've cycled through all the servers and still nothing, return | |
438 | * error code from the last server tried. | |
439 | */ | |
440 | for (pass = 0, aflags |= UPUBIKONLY; pass < 2; | |
441 | pass++, aflags &= ~UPUBIKONLY) { | |
442 | code = 0; | |
443 | count = 0; | |
444 | do { /* Cycle through the servers */ | |
445 | lcode = code; | |
446 | code = | |
447 | ubik_CallIter(aproc, aclient, aflags, &count, (long) p1, | |
448 | (long) p2, (long) p3, (long) p4, | |
449 | (long) p5, (long) p6, (long) p7, | |
450 | (long) p8, 0, 0, 0, 0, 0, 0, 0, 0); | |
451 | } while ((code == UNOQUORUM) || (code == UNOTSYNC) | |
452 | || (code == KALOCKED) || (code == -1)); | |
453 | ||
454 | if (code != UNOSERVERS) | |
455 | break; | |
456 | } | |
457 | ||
458 | /* If cycled through all the servers, return the last error code */ | |
459 | if ((code == UNOSERVERS) && lcode) { | |
460 | code = lcode; | |
461 | } | |
462 | return code; | |
463 | } | |
464 | ||
465 | /* This is the interface to the AuthServer RPC routine Authenticate. It | |
466 | formats the request packet, calls the encryption routine on the answer, | |
467 | calls Authenticate, and decrypts the response. The response is checked for | |
468 | correctness and its contents are copied into the token. */ | |
469 | ||
470 | /* Errors: | |
471 | KABADKEY = the key failed when converted to a key schedule. Probably bad | |
472 | parity. | |
473 | KAUBIKCALL - the call to Ubik returned an error, probably a communication | |
474 | failure such as timeout. | |
475 | KABADPROTOCOL - the returned packet was in error. Since a packet was | |
476 | returned it can be presumed that the AuthServer correctly interpreted | |
477 | the response. This may indicate an inauthentic AuthServer. | |
478 | <other> - errors generated by the server process are returned directly. | |
479 | */ | |
480 | ||
481 | afs_int32 | |
482 | ka_Authenticate(char *name, char *instance, char *cell, struct ubik_client * conn, /* Ubik connection to the AuthServer in | |
483 | * the desired cell */ | |
484 | int service, /* ticket granting or admin service */ | |
485 | struct ktc_encryptionKey * key, Date start, Date end, /* ticket lifetime */ | |
486 | struct ktc_token * token, afs_int32 * pwexpires) | |
487 | { /* days until it expires */ | |
488 | afs_int32 code; | |
489 | DES_key_schedule schedule; | |
490 | Date request_time; | |
491 | struct ka_gettgtRequest request; | |
492 | struct ka_gettgtAnswer answer_old; | |
493 | struct ka_ticketAnswer answer; | |
494 | ka_CBS arequest; | |
495 | ka_BBS oanswer; | |
496 | char *req_label; | |
497 | char *ans_label; | |
498 | int version; | |
499 | ||
500 | LOCK_GLOBAL_MUTEX; | |
501 | if ((code = DES_key_sched(ktc_to_cblock(key), &schedule))) { | |
502 | UNLOCK_GLOBAL_MUTEX; | |
503 | return KABADKEY; | |
504 | } | |
505 | ||
506 | if (service == KA_MAINTENANCE_SERVICE) { | |
507 | req_label = KA_GETADM_REQ_LABEL; | |
508 | ans_label = KA_GETADM_ANS_LABEL; | |
509 | } else if (service == KA_TICKET_GRANTING_SERVICE) { | |
510 | req_label = KA_GETTGT_REQ_LABEL; | |
511 | ans_label = KA_GETTGT_ANS_LABEL; | |
512 | } else { | |
513 | UNLOCK_GLOBAL_MUTEX; | |
514 | return KABADARGUMENT; | |
515 | } | |
516 | ||
517 | request_time = time(0); | |
518 | request.time = htonl(request_time); | |
519 | memcpy(request.label, req_label, sizeof(request.label)); | |
520 | arequest.SeqLen = sizeof(request); | |
521 | arequest.SeqBody = (char *)&request; | |
522 | DES_pcbc_encrypt(arequest.SeqBody, arequest.SeqBody, arequest.SeqLen, | |
523 | &schedule, ktc_to_cblockptr(key), ENCRYPT); | |
524 | ||
525 | oanswer.MaxSeqLen = sizeof(answer); | |
526 | oanswer.SeqLen = 0; | |
527 | oanswer.SeqBody = (char *)&answer; | |
528 | ||
529 | version = 2; | |
530 | code = | |
531 | kawrap_ubik_Call(KAA_AuthenticateV2, conn, 0, name, instance, | |
532 | (void*)(uintptr_t)start, (void*)(uintptr_t)end, &arequest, &oanswer, 0, 0); | |
533 | if (code == RXGEN_OPCODE) { | |
534 | oanswer.MaxSeqLen = sizeof(answer); | |
535 | oanswer.SeqBody = (char *)&answer; | |
536 | version = 1; | |
537 | code = | |
538 | ubik_KAA_Authenticate(conn, 0, name, instance, start, end, | |
539 | &arequest, &oanswer); | |
540 | if (code == RXGEN_OPCODE) { | |
541 | oanswer.MaxSeqLen = sizeof(answer_old); | |
542 | oanswer.SeqBody = (char *)&answer_old; | |
543 | version = 0; | |
544 | code = | |
545 | ubik_KAA_Authenticate_old(conn, 0, name, instance, | |
546 | start, end, &arequest, &oanswer); | |
547 | } | |
548 | if (code == RXGEN_OPCODE) { | |
549 | code = KAOLDINTERFACE; | |
550 | } | |
551 | } | |
552 | if (code) { | |
553 | UNLOCK_GLOBAL_MUTEX; | |
554 | if ((code >= KAMINERROR) && (code <= KAMAXERROR)) | |
555 | return code; | |
556 | return KAUBIKCALL; | |
557 | } | |
558 | DES_pcbc_encrypt(oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen, | |
559 | &schedule, ktc_to_cblockptr(key), DECRYPT); | |
560 | ||
561 | switch (version) { | |
562 | case 1: | |
563 | case 2: | |
564 | { | |
565 | struct ktc_principal caller; | |
566 | strcpy(caller.name, name); | |
567 | strcpy(caller.instance, instance); | |
568 | strcpy(caller.cell, ""); | |
569 | code = | |
570 | CheckTicketAnswer(&oanswer, request_time + 1, token, &caller, | |
571 | 0, ans_label, pwexpires); | |
572 | if (code) { | |
573 | UNLOCK_GLOBAL_MUTEX; | |
574 | return code; | |
575 | } | |
576 | } | |
577 | break; | |
578 | case 0: | |
579 | answer_old.time = ntohl(answer_old.time); | |
580 | answer_old.ticket_len = ntohl(answer_old.ticket_len); | |
581 | if ((answer_old.time != request_time + 1) | |
582 | || (answer_old.ticket_len < MINKTCTICKETLEN) | |
583 | || (answer_old.ticket_len > MAXKTCTICKETLEN)) { | |
584 | UNLOCK_GLOBAL_MUTEX; | |
585 | return KABADPROTOCOL; | |
586 | } | |
587 | { | |
588 | char *label = ((char *)answer_old.ticket) + answer_old.ticket_len; | |
589 | ||
590 | if (strncmp(label, ans_label, sizeof(answer_old.label))) { | |
591 | UNLOCK_GLOBAL_MUTEX; | |
592 | return KABADPROTOCOL; | |
593 | } | |
594 | token->startTime = start; | |
595 | token->endTime = end; | |
596 | token->kvno = ntohl(answer_old.kvno); | |
597 | token->ticketLen = answer_old.ticket_len; | |
598 | memcpy(token->ticket, answer_old.ticket, sizeof(token->ticket)); | |
599 | memcpy(&token->sessionKey, &answer_old.sessionkey, | |
600 | sizeof(struct ktc_encryptionKey)); | |
601 | } | |
602 | break; | |
603 | default: | |
604 | UNLOCK_GLOBAL_MUTEX; | |
605 | return KAINTERNALERROR; | |
606 | } | |
607 | ||
608 | UNLOCK_GLOBAL_MUTEX; | |
609 | return 0; | |
610 | } | |
611 | ||
612 | afs_int32 | |
613 | ka_GetToken(char *name, char *instance, char *cell, char *cname, char *cinst, struct ubik_client * conn, /* Ubik conn to cell's AuthServer */ | |
614 | Date start, Date end, /* desired ticket lifetime */ | |
615 | struct ktc_token * auth_token, char *auth_domain, | |
616 | struct ktc_token * token) | |
617 | { | |
618 | struct ka_getTicketTimes times; | |
619 | struct ka_getTicketAnswer answer_old; | |
620 | struct ka_ticketAnswer answer; | |
621 | afs_int32 code; | |
622 | ka_CBS aticket; | |
623 | ka_CBS atimes; | |
624 | ka_BBS oanswer; | |
625 | char *strings; | |
626 | int len; | |
627 | DES_key_schedule schedule; | |
628 | int version; | |
629 | afs_int32 pwexpires; | |
630 | ||
631 | LOCK_GLOBAL_MUTEX; | |
632 | aticket.SeqLen = auth_token->ticketLen; | |
633 | aticket.SeqBody = auth_token->ticket; | |
634 | ||
635 | code = DES_key_sched(ktc_to_cblock(&auth_token->sessionKey), &schedule); | |
636 | if (code) { | |
637 | UNLOCK_GLOBAL_MUTEX; | |
638 | return KABADKEY; | |
639 | } | |
640 | ||
641 | times.start = htonl(start); | |
642 | times.end = htonl(end); | |
643 | DES_ecb_encrypt((DES_cblock *)×, (DES_cblock *)×, &schedule, | |
644 | ENCRYPT); | |
645 | ||
646 | atimes.SeqLen = sizeof(times); | |
647 | atimes.SeqBody = (char *)× | |
648 | ||
649 | oanswer.SeqLen = 0; | |
650 | oanswer.MaxSeqLen = sizeof(answer); | |
651 | oanswer.SeqBody = (char *)&answer; | |
652 | ||
653 | version = 1; | |
654 | code = | |
655 | ubik_KAT_GetTicket(conn, 0, auth_token->kvno, auth_domain, | |
656 | &aticket, name, instance, &atimes, &oanswer); | |
657 | if (code == RXGEN_OPCODE) { | |
658 | oanswer.SeqLen = 0; /* this may be set by first call */ | |
659 | oanswer.MaxSeqLen = sizeof(answer_old); | |
660 | oanswer.SeqBody = (char *)&answer_old; | |
661 | version = 0; | |
662 | code = | |
663 | ubik_KAT_GetTicket_old(conn, 0, auth_token->kvno, | |
664 | auth_domain, &aticket, name, instance, &atimes, | |
665 | &oanswer); | |
666 | if (code == RXGEN_OPCODE) { | |
667 | code = KAOLDINTERFACE; | |
668 | } | |
669 | } | |
670 | if (code) { | |
671 | UNLOCK_GLOBAL_MUTEX; | |
672 | if ((code >= KAMINERROR) && (code <= KAMAXERROR)) | |
673 | return code; | |
674 | return KAUBIKCALL; | |
675 | } | |
676 | ||
677 | DES_pcbc_encrypt(oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen, | |
678 | &schedule, ktc_to_cblockptr(&auth_token->sessionKey), | |
679 | DECRYPT); | |
680 | ||
681 | switch (version) { | |
682 | case 1: | |
683 | { | |
684 | struct ktc_principal server; | |
685 | strcpy(server.name, name); | |
686 | strcpy(server.instance, instance); | |
687 | code = | |
688 | CheckTicketAnswer(&oanswer, 0, token, 0, &server, | |
689 | KA_GETTICKET_ANS_LABEL, &pwexpires); | |
690 | if (code) { | |
691 | UNLOCK_GLOBAL_MUTEX; | |
692 | return code; | |
693 | } | |
694 | } | |
695 | break; | |
696 | case 0: | |
697 | token->startTime = ntohl(answer_old.startTime); | |
698 | token->endTime = ntohl(answer_old.endTime); | |
699 | token->ticketLen = ntohl(answer_old.ticketLen); | |
700 | token->kvno = ntohl(answer_old.kvno); | |
701 | memcpy(&token->sessionKey, &answer_old.sessionKey, | |
702 | sizeof(token->sessionKey)); | |
703 | ||
704 | if (tkt_CheckTimes(token->startTime, token->endTime, time(0)) < 0) { | |
705 | UNLOCK_GLOBAL_MUTEX; | |
706 | return KABADPROTOCOL; | |
707 | } | |
708 | if ((token->ticketLen < MINKTCTICKETLEN) | |
709 | || (token->ticketLen > MAXKTCTICKETLEN)) { | |
710 | UNLOCK_GLOBAL_MUTEX; | |
711 | return KABADPROTOCOL; | |
712 | } | |
713 | strings = answer_old.name; | |
714 | len = strlen(strings); /* check client name */ | |
715 | if ((len < 1) || (len > MAXKTCNAMELEN)) { | |
716 | UNLOCK_GLOBAL_MUTEX; | |
717 | return KABADPROTOCOL; | |
718 | } | |
719 | strings += len + 1; /* check client instance */ | |
720 | len = strlen(strings); | |
721 | if ((len < 0) || (len > MAXKTCNAMELEN)) { | |
722 | UNLOCK_GLOBAL_MUTEX; | |
723 | return KABADPROTOCOL; | |
724 | } | |
725 | strings += len + 1; | |
726 | len = strlen(strings); /* check client cell */ | |
727 | if ((len < 0) || (len > MAXKTCNAMELEN)) { | |
728 | UNLOCK_GLOBAL_MUTEX; | |
729 | return KABADPROTOCOL; | |
730 | } | |
731 | strings += len + 1; | |
732 | len = strlen(strings); /* check server name */ | |
733 | if ((len < 1) || (len > MAXKTCNAMELEN) || strcmp(name, strings)) { | |
734 | UNLOCK_GLOBAL_MUTEX; | |
735 | return KABADPROTOCOL; | |
736 | } | |
737 | strings += len + 1; | |
738 | len = strlen(strings); /* check server instance */ | |
739 | if ((len < 0) || (len > MAXKTCNAMELEN) || strcmp(instance, strings)) { | |
740 | UNLOCK_GLOBAL_MUTEX; | |
741 | return KABADPROTOCOL; | |
742 | } | |
743 | strings += len + 1; | |
744 | ||
745 | if ((strings - oanswer.SeqBody + token->ticketLen) - oanswer.SeqLen >= | |
746 | ENCRYPTIONBLOCKSIZE) { | |
747 | UNLOCK_GLOBAL_MUTEX; | |
748 | return KABADPROTOCOL; | |
749 | } | |
750 | memcpy(token->ticket, strings, token->ticketLen); | |
751 | ||
752 | break; | |
753 | default: | |
754 | UNLOCK_GLOBAL_MUTEX; | |
755 | return KAINTERNALERROR; | |
756 | } | |
757 | ||
758 | UNLOCK_GLOBAL_MUTEX; | |
759 | return 0; | |
760 | } | |
761 | ||
762 | afs_int32 | |
763 | ka_ChangePassword(char *name, char *instance, struct ubik_client * conn, /* Ubik connection to the AuthServer in | |
764 | * the desired cell */ | |
765 | struct ktc_encryptionKey * oldkey, | |
766 | struct ktc_encryptionKey * newkey) | |
767 | { | |
768 | afs_int32 code; | |
769 | ||
770 | LOCK_GLOBAL_MUTEX; | |
771 | code = | |
772 | ubik_KAM_SetPassword(conn, UBIK_CALL_NEW, name, instance, 0, *(EncryptionKey *)newkey); | |
773 | UNLOCK_GLOBAL_MUTEX; | |
774 | return code; | |
775 | } |