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>
15 #ifdef IGNORE_SOME_GCC_WARNINGS
16 # pragma GCC diagnostic warning "-Wstrict-prototypes"
17 # pragma GCC diagnostic warning "-Wimplicit-function-declaration"
20 #define UBIK_LEGACY_CALLITER 1
23 #include <afs/pthread_glock.h>
24 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
37 #include <des_prototypes.h>
39 #include <afs/cellconfig.h>
42 #include <afs/afsutil.h>
47 #include "afs_usrops.h"
50 static struct afsconf_dir *conf = 0;
51 static struct afsconf_cell explicit_cell_server_list;
52 static struct afsconf_cell debug_cell_server_list;
53 static int explicit = 0;
56 #ifdef ENCRYPTIONBLOCKSIZE
57 #undef ENCRYPTIONBLOCKSIZE
59 #define ENCRYPTIONBLOCKSIZE (sizeof(des_cblock))
61 /* Copy the specified list of servers into a specially know cell named
62 "explicit". The cell can then be used to debug experimental servers. */
65 ka_ExplicitCell(char *cell, afs_uint32 serverList[])
70 ka_ExpandCell(cell, explicit_cell_server_list.name, 0);
71 for (i = 0; i < MAXHOSTSPERCELL; i++)
73 explicit_cell_server_list.numServers = i + 1;
74 explicit_cell_server_list.hostAddr[i].sin_family = AF_INET;
75 explicit_cell_server_list.hostAddr[i].sin_addr.s_addr =
77 explicit_cell_server_list.hostName[i][0] = 0;
78 explicit_cell_server_list.hostAddr[i].sin_port =
79 htons(AFSCONF_KAUTHPORT);
80 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
81 explicit_cell_server_list.hostAddr[i].sin_len =
82 sizeof(struct sockaddr_in);
91 myCellLookup(struct afsconf_dir *conf, char *cell, char *service,
92 struct afsconf_cell *cellinfo)
95 *cellinfo = debug_cell_server_list;
98 && (strcmp(cell, explicit_cell_server_list.name) == 0)) {
99 *cellinfo = explicit_cell_server_list;
102 /* call the real one */
104 return afsconf_GetCellInfo(conf, cell, service, cellinfo);
108 ka_GetServers(char *cell, struct afsconf_cell * cellinfo)
111 char cellname[MAXKTCREALMLEN];
114 if (cell && !strlen(cell))
117 cell = lcstring(cellname, cell, sizeof(cellname));
123 conf = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
130 code = myCellLookup(conf, cell, AFSCONF_KAUTHSERVICE, cellinfo);
136 ka_GetSecurity(int service, struct ktc_token * token,
137 struct rx_securityClass ** scP, int *siP)
138 { /* security class index */
142 case KA_AUTHENTICATION_SERVICE:
143 case KA_TICKET_GRANTING_SERVICE:
145 *scP = rxnull_NewClientSecurityObject();
146 *siP = RX_SCINDEX_NULL;
148 case KA_MAINTENANCE_SERVICE:
152 rxkad_NewClientSecurityObject(rxkad_crypt, &token->sessionKey,
153 token->kvno, token->ticketLen,
155 *siP = RX_SCINDEX_KAD;
159 return KABADARGUMENT;
162 printf("Failed gettting security object\n");
171 ka_SingleServerConn(char *cell, char *server, /* name of server to contact */
172 int service, struct ktc_token * token,
173 struct ubik_client ** conn)
176 struct rx_connection *serverconns[2];
177 struct rx_securityClass *sc;
178 int si; /* security class index */
179 struct afsconf_cell cellinfo; /* for cell auth server list */
182 char sname[MAXHOSTCHARS];
186 code = ka_GetServers(cell, &cellinfo);
192 lcstring(sname, server, sizeof(sname));
193 snamel = strlen(sname);
195 for (i = 0; i < cellinfo.numServers; i++) {
196 if (strncmp(cellinfo.hostName[i], sname, snamel) == 0) {
215 code = ka_GetSecurity(service, token, &sc, &si);
220 #ifdef AFS_PTHREAD_ENV
222 rx_GetCachedConnection(cellinfo.hostAddr[match].sin_addr.s_addr,
223 cellinfo.hostAddr[match].sin_port, service, sc,
227 rx_NewConnection(cellinfo.hostAddr[match].sin_addr.s_addr,
228 cellinfo.hostAddr[match].sin_port, service, sc, si);
230 serverconns[1] = 0; /* terminate list */
232 /* next, pass list of server rx_connections (in serverconns), and a place
233 * to put the returned client structure that we'll use in all of our rpc
234 * calls (via ubik_Call) */
236 code = ubik_ClientInit(serverconns, conn);
245 ka_AuthSpecificServersConn(int service, struct ktc_token * token,
246 struct afsconf_cell * cellinfo,
247 struct ubik_client ** conn)
250 struct rx_connection *serverconns[MAXSERVERS];
251 struct rx_securityClass *sc;
252 int si; /* security class index */
262 code = ka_GetSecurity(service, token, &sc, &si);
268 for (i = 0; i < cellinfo->numServers; i++)
269 #ifdef AFS_PTHREAD_ENV
271 rx_GetCachedConnection(cellinfo->hostAddr[i].sin_addr.s_addr,
272 cellinfo->hostAddr[i].sin_port, service,
276 rx_NewConnection(cellinfo->hostAddr[i].sin_addr.s_addr,
277 cellinfo->hostAddr[i].sin_port, service, sc, si);
279 serverconns[cellinfo->numServers] = 0; /* terminate list */
281 /* next, pass list of server rx_connections (in serverconns), and a place
282 * to put the returned client structure that we'll use in all of our rpc
283 * calls (via ubik_Call) */
285 code = ubik_ClientInit(serverconns, conn);
294 ka_AuthServerConn(char *cell, int service, struct ktc_token * token,
295 struct ubik_client ** conn)
298 struct rx_connection *serverconns[MAXSERVERS];
299 struct rx_securityClass *sc;
300 int si; /* security class index */
302 struct afsconf_cell cellinfo; /* for cell auth server list */
305 code = ka_GetServers(cell, &cellinfo);
317 code = ka_GetSecurity(service, token, &sc, &si);
323 for (i = 0; i < cellinfo.numServers; i++)
324 #ifdef AFS_PTHREAD_ENV
326 rx_GetCachedConnection(cellinfo.hostAddr[i].sin_addr.s_addr,
327 cellinfo.hostAddr[i].sin_port, service, sc,
331 rx_NewConnection(cellinfo.hostAddr[i].sin_addr.s_addr,
332 cellinfo.hostAddr[i].sin_port, service, sc, si);
334 serverconns[cellinfo.numServers] = 0; /* terminate list */
336 /* next, pass list of server rx_connections (in serverconns), and a place
337 * to put the returned client structure that we'll use in all of our rpc
338 * calls (via ubik_Call) */
340 code = ubik_ClientInit(serverconns, conn);
349 CheckTicketAnswer(ka_BBS * oanswer, afs_int32 challenge,
350 struct ktc_token *token, struct ktc_principal *caller,
351 struct ktc_principal *server, char *label,
352 afs_int32 * pwexpires)
354 struct ka_ticketAnswer *answer;
358 answer = (struct ka_ticketAnswer *)oanswer->SeqBody;
360 cksum = ntohl(answer->cksum);
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(×, ×, schedule, ENCRYPT);
662 atimes.SeqLen = sizeof(times);
663 atimes.SeqBody = (char *)×
666 oanswer.MaxSeqLen = sizeof(answer);
667 oanswer.SeqBody = (char *)&answer;
671 ubik_KAT_GetTicket(conn, 0, auth_token->kvno, auth_domain,
672 &aticket, name, instance, &atimes, &oanswer);
673 if (code == RXGEN_OPCODE) {
674 oanswer.SeqLen = 0; /* this may be set by first call */
675 oanswer.MaxSeqLen = sizeof(answer_old);
676 oanswer.SeqBody = (char *)&answer_old;
679 ubik_KAT_GetTicket_old(conn, 0, auth_token->kvno,
680 auth_domain, &aticket, name, instance, &atimes,
682 if (code == RXGEN_OPCODE) {
683 code = KAOLDINTERFACE;
688 if ((code >= KAMINERROR) && (code <= KAMAXERROR))
693 des_pcbc_encrypt(oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen,
694 schedule, ktc_to_cblockptr(&auth_token->sessionKey), DECRYPT);
699 struct ktc_principal server;
700 strcpy(server.name, name);
701 strcpy(server.instance, instance);
703 CheckTicketAnswer(&oanswer, 0, token, 0, &server,
704 KA_GETTICKET_ANS_LABEL, &pwexpires);
712 token->startTime = ntohl(answer_old.startTime);
713 token->endTime = ntohl(answer_old.endTime);
714 token->ticketLen = ntohl(answer_old.ticketLen);
715 token->kvno = ntohl(answer_old.kvno);
716 memcpy(&token->sessionKey, &answer_old.sessionKey,
717 sizeof(token->sessionKey));
719 if (tkt_CheckTimes(token->startTime, token->endTime, time(0)) < 0) {
721 return KABADPROTOCOL;
723 if ((token->ticketLen < MINKTCTICKETLEN)
724 || (token->ticketLen > MAXKTCTICKETLEN)) {
726 return KABADPROTOCOL;
728 strings = answer_old.name;
729 len = strlen(strings); /* check client name */
730 if ((len < 1) || (len > MAXKTCNAMELEN)) {
732 return KABADPROTOCOL;
734 strings += len + 1; /* check client instance */
735 len = strlen(strings);
736 if ((len < 0) || (len > MAXKTCNAMELEN)) {
738 return KABADPROTOCOL;
741 len = strlen(strings); /* check client cell */
742 if ((len < 0) || (len > MAXKTCNAMELEN)) {
744 return KABADPROTOCOL;
747 len = strlen(strings); /* check server name */
748 if ((len < 1) || (len > MAXKTCNAMELEN) || strcmp(name, strings)) {
750 return KABADPROTOCOL;
753 len = strlen(strings); /* check server instance */
754 if ((len < 0) || (len > MAXKTCNAMELEN) || strcmp(instance, strings)) {
756 return KABADPROTOCOL;
760 if ((strings - oanswer.SeqBody + token->ticketLen) - oanswer.SeqLen >=
761 ENCRYPTIONBLOCKSIZE) {
763 return KABADPROTOCOL;
765 memcpy(token->ticket, strings, token->ticketLen);
770 return KAINTERNALERROR;
778 ka_ChangePassword(char *name, char *instance, struct ubik_client * conn, /* Ubik connection to the AuthServer in
779 * the desired cell */
780 struct ktc_encryptionKey * oldkey,
781 struct ktc_encryptionKey * newkey)
787 ubik_KAM_SetPassword(conn, UBIK_CALL_NEW, name, instance, 0, *(EncryptionKey *)newkey);