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>
17 #ifdef IGNORE_SOME_GCC_WARNINGS
18 # pragma GCC diagnostic warning "-Wstrict-prototypes"
19 # pragma GCC diagnostic warning "-Wimplicit-function-declaration"
22 #define UBIK_LEGACY_CALLITER 1
25 #include <afs/pthread_glock.h>
26 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
39 #include <afs/cellconfig.h>
42 #include <afs/afsutil.h>
43 #include <hcrypto/des.h>
49 #include "afs_usrops.h"
52 static struct afsconf_dir *conf = 0;
53 static struct afsconf_cell explicit_cell_server_list;
54 static struct afsconf_cell debug_cell_server_list;
55 static int explicit = 0;
58 #ifdef ENCRYPTIONBLOCKSIZE
59 #undef ENCRYPTIONBLOCKSIZE
61 #define ENCRYPTIONBLOCKSIZE (sizeof(DES_cblock))
63 /* Copy the specified list of servers into a specially know cell named
64 "explicit". The cell can then be used to debug experimental servers. */
67 ka_ExplicitCell(char *cell, afs_uint32 serverList[])
72 ka_ExpandCell(cell, explicit_cell_server_list.name, 0);
73 for (i = 0; i < MAXHOSTSPERCELL; i++)
75 explicit_cell_server_list.numServers = i + 1;
76 explicit_cell_server_list.hostAddr[i].sin_family = AF_INET;
77 explicit_cell_server_list.hostAddr[i].sin_addr.s_addr =
79 explicit_cell_server_list.hostName[i][0] = 0;
80 explicit_cell_server_list.hostAddr[i].sin_port =
81 htons(AFSCONF_KAUTHPORT);
82 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
83 explicit_cell_server_list.hostAddr[i].sin_len =
84 sizeof(struct sockaddr_in);
93 myCellLookup(struct afsconf_dir *conf, char *cell, char *service,
94 struct afsconf_cell *cellinfo)
97 *cellinfo = debug_cell_server_list;
100 && (strcmp(cell, explicit_cell_server_list.name) == 0)) {
101 *cellinfo = explicit_cell_server_list;
104 /* call the real one */
106 return afsconf_GetCellInfo(conf, cell, service, cellinfo);
110 ka_GetServers(char *cell, struct afsconf_cell * cellinfo)
113 char cellname[MAXKTCREALMLEN];
116 if (cell && !strlen(cell))
119 cell = lcstring(cellname, cell, sizeof(cellname));
125 conf = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
132 code = myCellLookup(conf, cell, AFSCONF_KAUTHSERVICE, cellinfo);
138 ka_GetSecurity(int service, struct ktc_token * token,
139 struct rx_securityClass ** scP, int *siP)
140 { /* security class index */
144 case KA_AUTHENTICATION_SERVICE:
145 case KA_TICKET_GRANTING_SERVICE:
147 *scP = rxnull_NewClientSecurityObject();
148 *siP = RX_SCINDEX_NULL;
150 case KA_MAINTENANCE_SERVICE:
154 rxkad_NewClientSecurityObject(rxkad_crypt, &token->sessionKey,
155 token->kvno, token->ticketLen,
157 *siP = RX_SCINDEX_KAD;
161 return KABADARGUMENT;
164 printf("Failed gettting security object\n");
173 ka_SingleServerConn(char *cell, char *server, /* name of server to contact */
174 int service, struct ktc_token * token,
175 struct ubik_client ** conn)
178 struct rx_connection *serverconns[2];
179 struct rx_securityClass *sc;
180 int si; /* security class index */
181 struct afsconf_cell cellinfo; /* for cell auth server list */
184 char sname[MAXHOSTCHARS];
188 code = ka_GetServers(cell, &cellinfo);
194 lcstring(sname, server, sizeof(sname));
195 snamel = strlen(sname);
197 for (i = 0; i < cellinfo.numServers; i++) {
198 if (strncmp(cellinfo.hostName[i], sname, snamel) == 0) {
217 code = ka_GetSecurity(service, token, &sc, &si);
222 #ifdef AFS_PTHREAD_ENV
224 rx_GetCachedConnection(cellinfo.hostAddr[match].sin_addr.s_addr,
225 cellinfo.hostAddr[match].sin_port, service, sc,
229 rx_NewConnection(cellinfo.hostAddr[match].sin_addr.s_addr,
230 cellinfo.hostAddr[match].sin_port, service, sc, si);
232 serverconns[1] = 0; /* terminate list */
234 /* next, pass list of server rx_connections (in serverconns), and a place
235 * to put the returned client structure that we'll use in all of our rpc
236 * calls (via ubik_Call) */
238 code = ubik_ClientInit(serverconns, conn);
247 ka_AuthSpecificServersConn(int service, struct ktc_token * token,
248 struct afsconf_cell * cellinfo,
249 struct ubik_client ** conn)
252 struct rx_connection *serverconns[MAXSERVERS];
253 struct rx_securityClass *sc;
254 int si; /* security class index */
264 code = ka_GetSecurity(service, token, &sc, &si);
270 for (i = 0; i < cellinfo->numServers; i++)
271 #ifdef AFS_PTHREAD_ENV
273 rx_GetCachedConnection(cellinfo->hostAddr[i].sin_addr.s_addr,
274 cellinfo->hostAddr[i].sin_port, service,
278 rx_NewConnection(cellinfo->hostAddr[i].sin_addr.s_addr,
279 cellinfo->hostAddr[i].sin_port, service, sc, si);
281 serverconns[cellinfo->numServers] = 0; /* terminate list */
283 /* next, pass list of server rx_connections (in serverconns), and a place
284 * to put the returned client structure that we'll use in all of our rpc
285 * calls (via ubik_Call) */
287 code = ubik_ClientInit(serverconns, conn);
296 ka_AuthServerConn(char *cell, int service, struct ktc_token * token,
297 struct ubik_client ** conn)
300 struct rx_connection *serverconns[MAXSERVERS];
301 struct rx_securityClass *sc;
302 int si; /* security class index */
304 struct afsconf_cell cellinfo; /* for cell auth server list */
307 code = ka_GetServers(cell, &cellinfo);
319 code = ka_GetSecurity(service, token, &sc, &si);
325 for (i = 0; i < cellinfo.numServers; i++)
326 #ifdef AFS_PTHREAD_ENV
328 rx_GetCachedConnection(cellinfo.hostAddr[i].sin_addr.s_addr,
329 cellinfo.hostAddr[i].sin_port, service, sc,
333 rx_NewConnection(cellinfo.hostAddr[i].sin_addr.s_addr,
334 cellinfo.hostAddr[i].sin_port, service, sc, si);
336 serverconns[cellinfo.numServers] = 0; /* terminate list */
338 /* next, pass list of server rx_connections (in serverconns), and a place
339 * to put the returned client structure that we'll use in all of our rpc
340 * calls (via ubik_Call) */
342 code = ubik_ClientInit(serverconns, conn);
351 CheckTicketAnswer(ka_BBS * oanswer, afs_int32 challenge,
352 struct ktc_token *token, struct ktc_principal *caller,
353 struct ktc_principal *server, char *label,
354 afs_int32 * pwexpires)
356 struct ka_ticketAnswer *answer;
359 answer = (struct ka_ticketAnswer *)oanswer->SeqBody;
361 if (challenge != ntohl(answer->challenge))
362 return KABADPROTOCOL;
363 memcpy(&token->sessionKey, &answer->sessionKey,
364 sizeof(token->sessionKey));
365 token->startTime = ntohl(answer->startTime);
366 token->endTime = ntohl(answer->endTime);
367 token->kvno = (short)ntohl(answer->kvno);
368 token->ticketLen = ntohl(answer->ticketLen);
370 if (tkt_CheckTimes(token->startTime, token->endTime, time(0)) < 0)
371 return KABADPROTOCOL;
372 if ((token->ticketLen < MINKTCTICKETLEN)
373 || (token->ticketLen > MAXKTCTICKETLEN))
374 return KABADPROTOCOL;
377 char *strings = answer->name;
380 #define chkstr(field) \
381 len = strlen (strings); \
382 if (len > MAXKTCNAMELEN) return KABADPROTOCOL;\
383 if ((field) && strcmp (field, strings)) return KABADPROTOCOL;\
387 len = strlen(strings); \
388 if (len > MAXKTCNAMELEN) return KABADPROTOCOL; \
392 chkstr(caller->name);
393 chkstr(caller->instance);
394 chkstr(caller->cell);
401 chkstr(server->name);
402 chkstr(server->instance);
408 if (oanswer->SeqLen -
409 ((strings - oanswer->SeqBody) + token->ticketLen + KA_LABELSIZE)
410 >= (ENCRYPTIONBLOCKSIZE + 12)
412 return KABADPROTOCOL;
414 memcpy(token->ticket, strings, token->ticketLen);
415 strings += token->ticketLen;
416 if (memcmp(strings, label, KA_LABELSIZE) != 0)
417 return KABADPROTOCOL;
421 strings += KA_LABELSIZE;
422 temp = round_up_to_ebs((strings - oanswer->SeqBody));
424 if (oanswer->SeqLen > temp) {
425 strings = oanswer->SeqBody + temp;
426 memcpy(&temp, strings, sizeof(afs_int32));
427 tempc = ntohl(temp) >> 24;
428 /* don't forget this if you add any more fields!
429 * strings += sizeof(afs_int32);
441 /* call this instead of stub and we'll guarantee to find a host that's up.
442 * this doesn't handle UNOTSYNC very well, should use ubik_Call if you care
445 kawrap_ubik_Call(int (*aproc) (), struct ubik_client *aclient,
446 afs_int32 aflags, void *p1, void *p2, void *p3, void *p4,
447 void *p5, void *p6, void *p7, void *p8)
449 afs_int32 code, lcode;
453 /* First pass only checks servers known running. Second checks all.
454 * Once we've cycled through all the servers and still nothing, return
455 * error code from the last server tried.
457 for (pass = 0, aflags |= UPUBIKONLY; pass < 2;
458 pass++, aflags &= ~UPUBIKONLY) {
461 do { /* Cycle through the servers */
464 ubik_CallIter(aproc, aclient, aflags, &count, (long) p1,
465 (long) p2, (long) p3, (long) p4,
466 (long) p5, (long) p6, (long) p7,
467 (long) p8, 0, 0, 0, 0, 0, 0, 0, 0);
468 } while ((code == UNOQUORUM) || (code == UNOTSYNC)
469 || (code == KALOCKED) || (code == -1));
471 if (code != UNOSERVERS)
475 /* If cycled through all the servers, return the last error code */
476 if ((code == UNOSERVERS) && lcode) {
482 /* This is the interface to the AuthServer RPC routine Authenticate. It
483 formats the request packet, calls the encryption routine on the answer,
484 calls Authenticate, and decrypts the response. The response is checked for
485 correctness and its contents are copied into the token. */
488 KABADKEY = the key failed when converted to a key schedule. Probably bad
490 KAUBIKCALL - the call to Ubik returned an error, probably a communication
491 failure such as timeout.
492 KABADPROTOCOL - the returned packet was in error. Since a packet was
493 returned it can be presumed that the AuthServer correctly interpreted
494 the response. This may indicate an inauthentic AuthServer.
495 <other> - errors generated by the server process are returned directly.
499 ka_Authenticate(char *name, char *instance, char *cell, struct ubik_client * conn, /* Ubik connection to the AuthServer in
500 * the desired cell */
501 int service, /* ticket granting or admin service */
502 struct ktc_encryptionKey * key, Date start, Date end, /* ticket lifetime */
503 struct ktc_token * token, afs_int32 * pwexpires)
504 { /* days until it expires */
506 DES_key_schedule schedule;
508 struct ka_gettgtRequest request;
509 struct ka_gettgtAnswer answer_old;
510 struct ka_ticketAnswer answer;
518 if ((code = DES_key_sched(ktc_to_cblock(key), &schedule))) {
523 if (service == KA_MAINTENANCE_SERVICE) {
524 req_label = KA_GETADM_REQ_LABEL;
525 ans_label = KA_GETADM_ANS_LABEL;
526 } else if (service == KA_TICKET_GRANTING_SERVICE) {
527 req_label = KA_GETTGT_REQ_LABEL;
528 ans_label = KA_GETTGT_ANS_LABEL;
531 return KABADARGUMENT;
534 request_time = time(0);
535 request.time = htonl(request_time);
536 memcpy(request.label, req_label, sizeof(request.label));
537 arequest.SeqLen = sizeof(request);
538 arequest.SeqBody = (char *)&request;
539 DES_pcbc_encrypt(arequest.SeqBody, arequest.SeqBody, arequest.SeqLen,
540 &schedule, ktc_to_cblockptr(key), ENCRYPT);
542 oanswer.MaxSeqLen = sizeof(answer);
544 oanswer.SeqBody = (char *)&answer;
548 kawrap_ubik_Call(KAA_AuthenticateV2, conn, 0, name, instance,
549 (void*)(uintptr_t)start, (void*)(uintptr_t)end, &arequest, &oanswer, 0, 0);
550 if (code == RXGEN_OPCODE) {
551 oanswer.MaxSeqLen = sizeof(answer);
552 oanswer.SeqBody = (char *)&answer;
555 ubik_KAA_Authenticate(conn, 0, name, instance, start, end,
556 &arequest, &oanswer);
557 if (code == RXGEN_OPCODE) {
558 oanswer.MaxSeqLen = sizeof(answer_old);
559 oanswer.SeqBody = (char *)&answer_old;
562 ubik_KAA_Authenticate_old(conn, 0, name, instance,
563 start, end, &arequest, &oanswer);
565 if (code == RXGEN_OPCODE) {
566 code = KAOLDINTERFACE;
571 if ((code >= KAMINERROR) && (code <= KAMAXERROR))
575 DES_pcbc_encrypt(oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen,
576 &schedule, ktc_to_cblockptr(key), DECRYPT);
582 struct ktc_principal caller;
583 strcpy(caller.name, name);
584 strcpy(caller.instance, instance);
585 strcpy(caller.cell, "");
587 CheckTicketAnswer(&oanswer, request_time + 1, token, &caller,
588 0, ans_label, pwexpires);
596 answer_old.time = ntohl(answer_old.time);
597 answer_old.ticket_len = ntohl(answer_old.ticket_len);
598 if ((answer_old.time != request_time + 1)
599 || (answer_old.ticket_len < MINKTCTICKETLEN)
600 || (answer_old.ticket_len > MAXKTCTICKETLEN)) {
602 return KABADPROTOCOL;
605 char *label = ((char *)answer_old.ticket) + answer_old.ticket_len;
607 if (strncmp(label, ans_label, sizeof(answer_old.label))) {
609 return KABADPROTOCOL;
611 token->startTime = start;
612 token->endTime = end;
613 token->kvno = ntohl(answer_old.kvno);
614 token->ticketLen = answer_old.ticket_len;
615 memcpy(token->ticket, answer_old.ticket, sizeof(token->ticket));
616 memcpy(&token->sessionKey, &answer_old.sessionkey,
617 sizeof(struct ktc_encryptionKey));
622 return KAINTERNALERROR;
630 ka_GetToken(char *name, char *instance, char *cell, char *cname, char *cinst, struct ubik_client * conn, /* Ubik conn to cell's AuthServer */
631 Date start, Date end, /* desired ticket lifetime */
632 struct ktc_token * auth_token, char *auth_domain,
633 struct ktc_token * token)
635 struct ka_getTicketTimes times;
636 struct ka_getTicketAnswer answer_old;
637 struct ka_ticketAnswer answer;
644 DES_key_schedule schedule;
649 aticket.SeqLen = auth_token->ticketLen;
650 aticket.SeqBody = auth_token->ticket;
652 code = DES_key_sched(ktc_to_cblock(&auth_token->sessionKey), &schedule);
658 times.start = htonl(start);
659 times.end = htonl(end);
660 DES_ecb_encrypt((DES_cblock *)×, (DES_cblock *)×, &schedule,
663 atimes.SeqLen = sizeof(times);
664 atimes.SeqBody = (char *)×
667 oanswer.MaxSeqLen = sizeof(answer);
668 oanswer.SeqBody = (char *)&answer;
672 ubik_KAT_GetTicket(conn, 0, auth_token->kvno, auth_domain,
673 &aticket, name, instance, &atimes, &oanswer);
674 if (code == RXGEN_OPCODE) {
675 oanswer.SeqLen = 0; /* this may be set by first call */
676 oanswer.MaxSeqLen = sizeof(answer_old);
677 oanswer.SeqBody = (char *)&answer_old;
680 ubik_KAT_GetTicket_old(conn, 0, auth_token->kvno,
681 auth_domain, &aticket, name, instance, &atimes,
683 if (code == RXGEN_OPCODE) {
684 code = KAOLDINTERFACE;
689 if ((code >= KAMINERROR) && (code <= KAMAXERROR))
694 DES_pcbc_encrypt(oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen,
695 &schedule, ktc_to_cblockptr(&auth_token->sessionKey),
701 struct ktc_principal server;
702 strcpy(server.name, name);
703 strcpy(server.instance, instance);
705 CheckTicketAnswer(&oanswer, 0, token, 0, &server,
706 KA_GETTICKET_ANS_LABEL, &pwexpires);
714 token->startTime = ntohl(answer_old.startTime);
715 token->endTime = ntohl(answer_old.endTime);
716 token->ticketLen = ntohl(answer_old.ticketLen);
717 token->kvno = ntohl(answer_old.kvno);
718 memcpy(&token->sessionKey, &answer_old.sessionKey,
719 sizeof(token->sessionKey));
721 if (tkt_CheckTimes(token->startTime, token->endTime, time(0)) < 0) {
723 return KABADPROTOCOL;
725 if ((token->ticketLen < MINKTCTICKETLEN)
726 || (token->ticketLen > MAXKTCTICKETLEN)) {
728 return KABADPROTOCOL;
730 strings = answer_old.name;
731 len = strlen(strings); /* check client name */
732 if ((len < 1) || (len > MAXKTCNAMELEN)) {
734 return KABADPROTOCOL;
736 strings += len + 1; /* check client instance */
737 len = strlen(strings);
738 if ((len < 0) || (len > MAXKTCNAMELEN)) {
740 return KABADPROTOCOL;
743 len = strlen(strings); /* check client cell */
744 if ((len < 0) || (len > MAXKTCNAMELEN)) {
746 return KABADPROTOCOL;
749 len = strlen(strings); /* check server name */
750 if ((len < 1) || (len > MAXKTCNAMELEN) || strcmp(name, strings)) {
752 return KABADPROTOCOL;
755 len = strlen(strings); /* check server instance */
756 if ((len < 0) || (len > MAXKTCNAMELEN) || strcmp(instance, strings)) {
758 return KABADPROTOCOL;
762 if ((strings - oanswer.SeqBody + token->ticketLen) - oanswer.SeqLen >=
763 ENCRYPTIONBLOCKSIZE) {
765 return KABADPROTOCOL;
767 memcpy(token->ticket, strings, token->ticketLen);
772 return KAINTERNALERROR;
780 ka_ChangePassword(char *name, char *instance, struct ubik_client * conn, /* Ubik connection to the AuthServer in
781 * the desired cell */
782 struct ktc_encryptionKey * oldkey,
783 struct ktc_encryptionKey * newkey)
789 ubik_KAM_SetPassword(conn, UBIK_CALL_NEW, name, instance, 0, *(EncryptionKey *)newkey);