2 * Copyright 2000, International Business Machines Corporation and others.
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
10 /* These routines provide a convenient interface to the AuthServer. */
12 #include <afsconfig.h>
13 #include <afs/param.h>
19 #ifdef IGNORE_SOME_GCC_WARNINGS
20 # pragma GCC diagnostic warning "-Wstrict-prototypes"
21 # pragma GCC diagnostic warning "-Wimplicit-function-declaration"
24 #include <hcrypto/des.h>
26 #define UBIK_LEGACY_CALLITER 1
28 #include <afs/pthread_glock.h>
30 #include <afs/cellconfig.h>
33 #include <afs/afsutil.h>
39 #include "afs_usrops.h"
42 static struct afsconf_dir *conf = 0;
43 static struct afsconf_cell explicit_cell_server_list;
44 static struct afsconf_cell debug_cell_server_list;
45 static int explicit = 0;
48 #ifdef ENCRYPTIONBLOCKSIZE
49 #undef ENCRYPTIONBLOCKSIZE
51 #define ENCRYPTIONBLOCKSIZE (sizeof(DES_cblock))
53 /* Copy the specified list of servers into a specially know cell named
54 "explicit". The cell can then be used to debug experimental servers. */
57 ka_ExplicitCell(char *cell, afs_uint32 serverList[])
62 ka_ExpandCell(cell, explicit_cell_server_list.name, 0);
63 for (i = 0; i < MAXHOSTSPERCELL; i++)
65 explicit_cell_server_list.numServers = i + 1;
66 explicit_cell_server_list.hostAddr[i].sin_family = AF_INET;
67 explicit_cell_server_list.hostAddr[i].sin_addr.s_addr =
69 explicit_cell_server_list.hostName[i][0] = 0;
70 explicit_cell_server_list.hostAddr[i].sin_port =
71 htons(AFSCONF_KAUTHPORT);
72 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
73 explicit_cell_server_list.hostAddr[i].sin_len =
74 sizeof(struct sockaddr_in);
83 myCellLookup(struct afsconf_dir *conf, char *cell, char *service,
84 struct afsconf_cell *cellinfo)
87 *cellinfo = debug_cell_server_list;
90 && (strcmp(cell, explicit_cell_server_list.name) == 0)) {
91 *cellinfo = explicit_cell_server_list;
94 /* call the real one */
96 return afsconf_GetCellInfo(conf, cell, service, cellinfo);
100 ka_GetServers(char *cell, struct afsconf_cell * cellinfo)
103 char cellname[MAXKTCREALMLEN];
106 if (cell && !strlen(cell))
109 cell = lcstring(cellname, cell, sizeof(cellname));
115 conf = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
122 code = myCellLookup(conf, cell, AFSCONF_KAUTHSERVICE, cellinfo);
128 ka_GetSecurity(int service, struct ktc_token * token,
129 struct rx_securityClass ** scP, int *siP)
130 { /* security class index */
134 case KA_AUTHENTICATION_SERVICE:
135 case KA_TICKET_GRANTING_SERVICE:
137 *scP = rxnull_NewClientSecurityObject();
138 *siP = RX_SCINDEX_NULL;
140 case KA_MAINTENANCE_SERVICE:
144 rxkad_NewClientSecurityObject(rxkad_crypt, &token->sessionKey,
145 token->kvno, token->ticketLen,
147 *siP = RX_SCINDEX_KAD;
151 return KABADARGUMENT;
154 printf("Failed gettting security object\n");
163 ka_SingleServerConn(char *cell, char *server, /* name of server to contact */
164 int service, struct ktc_token * token,
165 struct ubik_client ** conn)
168 struct rx_connection *serverconns[2];
169 struct rx_securityClass *sc;
170 int si; /* security class index */
171 struct afsconf_cell cellinfo; /* for cell auth server list */
174 char sname[MAXHOSTCHARS];
178 code = ka_GetServers(cell, &cellinfo);
184 lcstring(sname, server, sizeof(sname));
185 snamel = strlen(sname);
187 for (i = 0; i < cellinfo.numServers; i++) {
188 if (strncmp(cellinfo.hostName[i], sname, snamel) == 0) {
207 code = ka_GetSecurity(service, token, &sc, &si);
212 #ifdef AFS_PTHREAD_ENV
214 rx_GetCachedConnection(cellinfo.hostAddr[match].sin_addr.s_addr,
215 cellinfo.hostAddr[match].sin_port, service, sc,
219 rx_NewConnection(cellinfo.hostAddr[match].sin_addr.s_addr,
220 cellinfo.hostAddr[match].sin_port, service, sc, si);
222 serverconns[1] = 0; /* terminate list */
224 /* next, pass list of server rx_connections (in serverconns), and a place
225 * to put the returned client structure that we'll use in all of our rpc
226 * calls (via ubik_Call) */
228 code = ubik_ClientInit(serverconns, conn);
237 ka_AuthSpecificServersConn(int service, struct ktc_token * token,
238 struct afsconf_cell * cellinfo,
239 struct ubik_client ** conn)
242 struct rx_connection *serverconns[MAXSERVERS];
243 struct rx_securityClass *sc;
244 int si; /* security class index */
254 code = ka_GetSecurity(service, token, &sc, &si);
260 for (i = 0; i < cellinfo->numServers; i++)
261 #ifdef AFS_PTHREAD_ENV
263 rx_GetCachedConnection(cellinfo->hostAddr[i].sin_addr.s_addr,
264 cellinfo->hostAddr[i].sin_port, service,
268 rx_NewConnection(cellinfo->hostAddr[i].sin_addr.s_addr,
269 cellinfo->hostAddr[i].sin_port, service, sc, si);
271 serverconns[cellinfo->numServers] = 0; /* terminate list */
273 /* next, pass list of server rx_connections (in serverconns), and a place
274 * to put the returned client structure that we'll use in all of our rpc
275 * calls (via ubik_Call) */
277 code = ubik_ClientInit(serverconns, conn);
286 ka_AuthServerConn(char *cell, int service, struct ktc_token * token,
287 struct ubik_client ** conn)
290 struct rx_connection *serverconns[MAXSERVERS];
291 struct rx_securityClass *sc;
292 int si; /* security class index */
294 struct afsconf_cell cellinfo; /* for cell auth server list */
297 code = ka_GetServers(cell, &cellinfo);
309 code = ka_GetSecurity(service, token, &sc, &si);
315 for (i = 0; i < cellinfo.numServers; i++)
316 #ifdef AFS_PTHREAD_ENV
318 rx_GetCachedConnection(cellinfo.hostAddr[i].sin_addr.s_addr,
319 cellinfo.hostAddr[i].sin_port, service, sc,
323 rx_NewConnection(cellinfo.hostAddr[i].sin_addr.s_addr,
324 cellinfo.hostAddr[i].sin_port, service, sc, si);
326 serverconns[cellinfo.numServers] = 0; /* terminate list */
328 /* next, pass list of server rx_connections (in serverconns), and a place
329 * to put the returned client structure that we'll use in all of our rpc
330 * calls (via ubik_Call) */
332 code = ubik_ClientInit(serverconns, conn);
341 CheckTicketAnswer(ka_BBS * oanswer, afs_int32 challenge,
342 struct ktc_token *token, struct ktc_principal *caller,
343 struct ktc_principal *server, char *label,
344 afs_int32 * pwexpires)
346 struct ka_ticketAnswer *answer;
349 answer = (struct ka_ticketAnswer *)oanswer->SeqBody;
351 if (challenge != ntohl(answer->challenge))
352 return KABADPROTOCOL;
353 memcpy(&token->sessionKey, &answer->sessionKey,
354 sizeof(token->sessionKey));
355 token->startTime = ntohl(answer->startTime);
356 token->endTime = ntohl(answer->endTime);
357 token->kvno = (short)ntohl(answer->kvno);
358 token->ticketLen = ntohl(answer->ticketLen);
360 if (tkt_CheckTimes(token->startTime, token->endTime, time(0)) < 0)
361 return KABADPROTOCOL;
362 if ((token->ticketLen < MINKTCTICKETLEN)
363 || (token->ticketLen > MAXKTCTICKETLEN))
364 return KABADPROTOCOL;
367 char *strings = answer->name;
370 #define chkstr(field) \
371 len = strlen (strings); \
372 if (len > MAXKTCNAMELEN) return KABADPROTOCOL;\
373 if ((field) && strcmp (field, strings)) return KABADPROTOCOL;\
377 len = strlen(strings); \
378 if (len > MAXKTCNAMELEN) return KABADPROTOCOL; \
382 chkstr(caller->name);
383 chkstr(caller->instance);
384 chkstr(caller->cell);
391 chkstr(server->name);
392 chkstr(server->instance);
398 if (oanswer->SeqLen -
399 ((strings - oanswer->SeqBody) + token->ticketLen + KA_LABELSIZE)
400 >= (ENCRYPTIONBLOCKSIZE + 12)
402 return KABADPROTOCOL;
404 memcpy(token->ticket, strings, token->ticketLen);
405 strings += token->ticketLen;
406 if (memcmp(strings, label, KA_LABELSIZE) != 0)
407 return KABADPROTOCOL;
411 strings += KA_LABELSIZE;
412 temp = round_up_to_ebs((strings - oanswer->SeqBody));
414 if (oanswer->SeqLen > temp) {
415 strings = oanswer->SeqBody + temp;
416 memcpy(&temp, strings, sizeof(afs_int32));
417 tempc = ntohl(temp) >> 24;
418 /* don't forget this if you add any more fields!
419 * strings += sizeof(afs_int32);
431 /* call this instead of stub and we'll guarantee to find a host that's up.
432 * this doesn't handle UNOTSYNC very well, should use ubik_Call if you care
435 kawrap_ubik_Call(int (*aproc) (), struct ubik_client *aclient,
436 afs_int32 aflags, void *p1, void *p2, void *p3, void *p4,
437 void *p5, void *p6, void *p7, void *p8)
439 afs_int32 code, lcode;
443 /* First pass only checks servers known running. Second checks all.
444 * Once we've cycled through all the servers and still nothing, return
445 * error code from the last server tried.
447 for (pass = 0, aflags |= UPUBIKONLY; pass < 2;
448 pass++, aflags &= ~UPUBIKONLY) {
451 do { /* Cycle through the servers */
454 ubik_CallIter(aproc, aclient, aflags, &count, (long) p1,
455 (long) p2, (long) p3, (long) p4,
456 (long) p5, (long) p6, (long) p7,
457 (long) p8, 0, 0, 0, 0, 0, 0, 0, 0);
458 } while ((code == UNOQUORUM) || (code == UNOTSYNC)
459 || (code == KALOCKED) || (code == -1));
461 if (code != UNOSERVERS)
465 /* If cycled through all the servers, return the last error code */
466 if ((code == UNOSERVERS) && lcode) {
472 /* This is the interface to the AuthServer RPC routine Authenticate. It
473 formats the request packet, calls the encryption routine on the answer,
474 calls Authenticate, and decrypts the response. The response is checked for
475 correctness and its contents are copied into the token. */
478 KABADKEY = the key failed when converted to a key schedule. Probably bad
480 KAUBIKCALL - the call to Ubik returned an error, probably a communication
481 failure such as timeout.
482 KABADPROTOCOL - the returned packet was in error. Since a packet was
483 returned it can be presumed that the AuthServer correctly interpreted
484 the response. This may indicate an inauthentic AuthServer.
485 <other> - errors generated by the server process are returned directly.
489 ka_Authenticate(char *name, char *instance, char *cell, struct ubik_client * conn, /* Ubik connection to the AuthServer in
490 * the desired cell */
491 int service, /* ticket granting or admin service */
492 struct ktc_encryptionKey * key, Date start, Date end, /* ticket lifetime */
493 struct ktc_token * token, afs_int32 * pwexpires)
494 { /* days until it expires */
496 DES_key_schedule schedule;
498 struct ka_gettgtRequest request;
499 struct ka_gettgtAnswer answer_old;
500 struct ka_ticketAnswer answer;
508 if ((code = DES_key_sched(ktc_to_cblock(key), &schedule))) {
513 if (service == KA_MAINTENANCE_SERVICE) {
514 req_label = KA_GETADM_REQ_LABEL;
515 ans_label = KA_GETADM_ANS_LABEL;
516 } else if (service == KA_TICKET_GRANTING_SERVICE) {
517 req_label = KA_GETTGT_REQ_LABEL;
518 ans_label = KA_GETTGT_ANS_LABEL;
521 return KABADARGUMENT;
524 request_time = time(0);
525 request.time = htonl(request_time);
526 memcpy(request.label, req_label, sizeof(request.label));
527 arequest.SeqLen = sizeof(request);
528 arequest.SeqBody = (char *)&request;
529 DES_pcbc_encrypt(arequest.SeqBody, arequest.SeqBody, arequest.SeqLen,
530 &schedule, ktc_to_cblockptr(key), ENCRYPT);
532 oanswer.MaxSeqLen = sizeof(answer);
534 oanswer.SeqBody = (char *)&answer;
538 kawrap_ubik_Call(KAA_AuthenticateV2, conn, 0, name, instance,
539 (void*)(uintptr_t)start, (void*)(uintptr_t)end, &arequest, &oanswer, 0, 0);
540 if (code == RXGEN_OPCODE) {
541 oanswer.MaxSeqLen = sizeof(answer);
542 oanswer.SeqBody = (char *)&answer;
545 ubik_KAA_Authenticate(conn, 0, name, instance, start, end,
546 &arequest, &oanswer);
547 if (code == RXGEN_OPCODE) {
548 oanswer.MaxSeqLen = sizeof(answer_old);
549 oanswer.SeqBody = (char *)&answer_old;
552 ubik_KAA_Authenticate_old(conn, 0, name, instance,
553 start, end, &arequest, &oanswer);
555 if (code == RXGEN_OPCODE) {
556 code = KAOLDINTERFACE;
561 if ((code >= KAMINERROR) && (code <= KAMAXERROR))
565 DES_pcbc_encrypt(oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen,
566 &schedule, ktc_to_cblockptr(key), DECRYPT);
572 struct ktc_principal caller;
573 strcpy(caller.name, name);
574 strcpy(caller.instance, instance);
575 strcpy(caller.cell, "");
577 CheckTicketAnswer(&oanswer, request_time + 1, token, &caller,
578 0, ans_label, pwexpires);
586 answer_old.time = ntohl(answer_old.time);
587 answer_old.ticket_len = ntohl(answer_old.ticket_len);
588 if ((answer_old.time != request_time + 1)
589 || (answer_old.ticket_len < MINKTCTICKETLEN)
590 || (answer_old.ticket_len > MAXKTCTICKETLEN)) {
592 return KABADPROTOCOL;
595 char *label = ((char *)answer_old.ticket) + answer_old.ticket_len;
597 if (strncmp(label, ans_label, sizeof(answer_old.label))) {
599 return KABADPROTOCOL;
601 token->startTime = start;
602 token->endTime = end;
603 token->kvno = ntohl(answer_old.kvno);
604 token->ticketLen = answer_old.ticket_len;
605 memcpy(token->ticket, answer_old.ticket, sizeof(token->ticket));
606 memcpy(&token->sessionKey, &answer_old.sessionkey,
607 sizeof(struct ktc_encryptionKey));
612 return KAINTERNALERROR;
620 ka_GetToken(char *name, char *instance, char *cell, char *cname, char *cinst, struct ubik_client * conn, /* Ubik conn to cell's AuthServer */
621 Date start, Date end, /* desired ticket lifetime */
622 struct ktc_token * auth_token, char *auth_domain,
623 struct ktc_token * token)
625 struct ka_getTicketTimes times;
626 struct ka_getTicketAnswer answer_old;
627 struct ka_ticketAnswer answer;
634 DES_key_schedule schedule;
639 aticket.SeqLen = auth_token->ticketLen;
640 aticket.SeqBody = auth_token->ticket;
642 code = DES_key_sched(ktc_to_cblock(&auth_token->sessionKey), &schedule);
648 times.start = htonl(start);
649 times.end = htonl(end);
650 DES_ecb_encrypt((DES_cblock *)×, (DES_cblock *)×, &schedule,
653 atimes.SeqLen = sizeof(times);
654 atimes.SeqBody = (char *)×
657 oanswer.MaxSeqLen = sizeof(answer);
658 oanswer.SeqBody = (char *)&answer;
662 ubik_KAT_GetTicket(conn, 0, auth_token->kvno, auth_domain,
663 &aticket, name, instance, &atimes, &oanswer);
664 if (code == RXGEN_OPCODE) {
665 oanswer.SeqLen = 0; /* this may be set by first call */
666 oanswer.MaxSeqLen = sizeof(answer_old);
667 oanswer.SeqBody = (char *)&answer_old;
670 ubik_KAT_GetTicket_old(conn, 0, auth_token->kvno,
671 auth_domain, &aticket, name, instance, &atimes,
673 if (code == RXGEN_OPCODE) {
674 code = KAOLDINTERFACE;
679 if ((code >= KAMINERROR) && (code <= KAMAXERROR))
684 DES_pcbc_encrypt(oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen,
685 &schedule, ktc_to_cblockptr(&auth_token->sessionKey),
691 struct ktc_principal server;
692 strcpy(server.name, name);
693 strcpy(server.instance, instance);
695 CheckTicketAnswer(&oanswer, 0, token, 0, &server,
696 KA_GETTICKET_ANS_LABEL, &pwexpires);
704 token->startTime = ntohl(answer_old.startTime);
705 token->endTime = ntohl(answer_old.endTime);
706 token->ticketLen = ntohl(answer_old.ticketLen);
707 token->kvno = ntohl(answer_old.kvno);
708 memcpy(&token->sessionKey, &answer_old.sessionKey,
709 sizeof(token->sessionKey));
711 if (tkt_CheckTimes(token->startTime, token->endTime, time(0)) < 0) {
713 return KABADPROTOCOL;
715 if ((token->ticketLen < MINKTCTICKETLEN)
716 || (token->ticketLen > MAXKTCTICKETLEN)) {
718 return KABADPROTOCOL;
720 strings = answer_old.name;
721 len = strlen(strings); /* check client name */
722 if ((len < 1) || (len > MAXKTCNAMELEN)) {
724 return KABADPROTOCOL;
726 strings += len + 1; /* check client instance */
727 len = strlen(strings);
728 if ((len < 0) || (len > MAXKTCNAMELEN)) {
730 return KABADPROTOCOL;
733 len = strlen(strings); /* check client cell */
734 if ((len < 0) || (len > MAXKTCNAMELEN)) {
736 return KABADPROTOCOL;
739 len = strlen(strings); /* check server name */
740 if ((len < 1) || (len > MAXKTCNAMELEN) || strcmp(name, strings)) {
742 return KABADPROTOCOL;
745 len = strlen(strings); /* check server instance */
746 if ((len < 0) || (len > MAXKTCNAMELEN) || strcmp(instance, strings)) {
748 return KABADPROTOCOL;
752 if ((strings - oanswer.SeqBody + token->ticketLen) - oanswer.SeqLen >=
753 ENCRYPTIONBLOCKSIZE) {
755 return KABADPROTOCOL;
757 memcpy(token->ticket, strings, token->ticketLen);
762 return KAINTERNALERROR;
770 ka_ChangePassword(char *name, char *instance, struct ubik_client * conn, /* Ubik connection to the AuthServer in
771 * the desired cell */
772 struct ktc_encryptionKey * oldkey,
773 struct ktc_encryptionKey * newkey)
779 ubik_KAM_SetPassword(conn, UBIK_CALL_NEW, name, instance, 0, *(EncryptionKey *)newkey);