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>
14 #include "afs/param.h"
16 #include <afs/param.h>
23 #include "afs/sysincludes.h"
24 #include "afsincludes.h"
25 #include "afs_usrops.h"
27 #include "afs/pthread_glock.h"
29 #include "afs/cellconfig.h"
33 #include "afs/afsutil.h"
35 #include "afs/kauth.h"
36 #include "afs/kautils.h"
37 #include "afs/pthread_glock.h"
39 #else /* defined(UKERNEL) */
41 #include <afs/pthread_glock.h>
42 #include <sys/types.h>
46 #include <sys/socket.h>
47 #include <netinet/in.h>
51 #include <afs/cellconfig.h>
55 #include <afs/afsutil.h>
58 #endif /* defined(UKERNEL) */
61 static struct afsconf_dir *conf = 0;
62 static struct afsconf_cell explicit_cell_server_list;
63 static struct afsconf_cell debug_cell_server_list;
64 static int explicit = 0;
67 #ifdef ENCRYPTIONBLOCKSIZE
68 #undef ENCRYPTIONBLOCKSIZE
70 #define ENCRYPTIONBLOCKSIZE (sizeof(des_cblock))
72 /* Copy the specified list of servers into a specially know cell named
73 "explicit". The cell can then be used to debug experimental servers. */
76 ka_ExplicitCell(char *cell, afs_int32 serverList[])
81 ka_ExpandCell(cell, explicit_cell_server_list.name, 0);
82 for (i = 0; i < MAXHOSTSPERCELL; i++)
84 explicit_cell_server_list.numServers = i + 1;
85 explicit_cell_server_list.hostAddr[i].sin_family = AF_INET;
86 explicit_cell_server_list.hostAddr[i].sin_addr.s_addr =
88 explicit_cell_server_list.hostName[i][0] = 0;
89 explicit_cell_server_list.hostAddr[i].sin_port =
90 htons(AFSCONF_KAUTHPORT);
91 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
92 explicit_cell_server_list.hostAddr[i].sin_len =
93 sizeof(struct sockaddr_in);
102 myCellLookup(struct afsconf_dir *conf, char *cell, char *service,
103 struct afsconf_cell *cellinfo)
106 *cellinfo = debug_cell_server_list;
109 && (strcmp(cell, explicit_cell_server_list.name) == 0)) {
110 *cellinfo = explicit_cell_server_list;
113 /* call the real one */
115 return afsconf_GetCellInfo(conf, cell, service, cellinfo);
119 ka_GetServers(char *cell, struct afsconf_cell * cellinfo)
122 char cellname[MAXKTCREALMLEN];
125 if (cell && !strlen(cell))
128 cell = lcstring(cellname, cell, sizeof(cellname));
134 conf = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
141 code = myCellLookup(conf, cell, AFSCONF_KAUTHSERVICE, cellinfo);
147 ka_GetSecurity(int service, struct ktc_token * token,
148 struct rx_securityClass ** scP, int *siP)
149 { /* security class index */
153 case KA_AUTHENTICATION_SERVICE:
154 case KA_TICKET_GRANTING_SERVICE:
156 *scP = rxnull_NewClientSecurityObject();
157 *siP = RX_SCINDEX_NULL;
159 case KA_MAINTENANCE_SERVICE:
163 rxkad_NewClientSecurityObject(rxkad_crypt, &token->sessionKey,
164 token->kvno, token->ticketLen,
166 *siP = RX_SCINDEX_KAD;
170 return KABADARGUMENT;
173 printf("Failed gettting security object\n");
182 ka_SingleServerConn(char *cell, char *server, /* name of server to contact */
183 int service, struct ktc_token * token,
184 struct ubik_client ** conn)
187 struct rx_connection *serverconns[2];
188 struct rx_securityClass *sc;
189 int si; /* security class index */
190 struct afsconf_cell cellinfo; /* for cell auth server list */
193 char sname[MAXHOSTCHARS];
197 code = ka_GetServers(cell, &cellinfo);
203 lcstring(sname, server, sizeof(sname));
204 snamel = strlen(sname);
206 for (i = 0; i < cellinfo.numServers; i++) {
207 if (strncmp(cellinfo.hostName[i], sname, snamel) == 0) {
226 code = ka_GetSecurity(service, token, &sc, &si);
231 #ifdef AFS_PTHREAD_ENV
233 rx_GetCachedConnection(cellinfo.hostAddr[match].sin_addr.s_addr,
234 cellinfo.hostAddr[match].sin_port, service, sc,
238 rx_NewConnection(cellinfo.hostAddr[match].sin_addr.s_addr,
239 cellinfo.hostAddr[match].sin_port, service, sc, si);
241 serverconns[1] = 0; /* terminate list */
243 /* next, pass list of server rx_connections (in serverconns), and a place
244 * to put the returned client structure that we'll use in all of our rpc
245 * calls (via ubik_Call) */
247 code = ubik_ClientInit(serverconns, conn);
256 ka_AuthSpecificServersConn(int service, struct ktc_token * token,
257 struct afsconf_cell * cellinfo,
258 struct ubik_client ** conn)
261 struct rx_connection *serverconns[MAXSERVERS];
262 struct rx_securityClass *sc;
263 int si; /* security class index */
273 code = ka_GetSecurity(service, token, &sc, &si);
279 for (i = 0; i < cellinfo->numServers; i++)
280 #ifdef AFS_PTHREAD_ENV
282 rx_GetCachedConnection(cellinfo->hostAddr[i].sin_addr.s_addr,
283 cellinfo->hostAddr[i].sin_port, service,
287 rx_NewConnection(cellinfo->hostAddr[i].sin_addr.s_addr,
288 cellinfo->hostAddr[i].sin_port, service, sc, si);
290 serverconns[cellinfo->numServers] = 0; /* terminate list */
292 /* next, pass list of server rx_connections (in serverconns), and a place
293 * to put the returned client structure that we'll use in all of our rpc
294 * calls (via ubik_Call) */
296 code = ubik_ClientInit(serverconns, conn);
305 ka_AuthServerConn(char *cell, int service, struct ktc_token * token,
306 struct ubik_client ** conn)
309 struct rx_connection *serverconns[MAXSERVERS];
310 struct rx_securityClass *sc;
311 int si; /* security class index */
313 struct afsconf_cell cellinfo; /* for cell auth server list */
316 code = ka_GetServers(cell, &cellinfo);
328 code = ka_GetSecurity(service, token, &sc, &si);
334 for (i = 0; i < cellinfo.numServers; i++)
335 #ifdef AFS_PTHREAD_ENV
337 rx_GetCachedConnection(cellinfo.hostAddr[i].sin_addr.s_addr,
338 cellinfo.hostAddr[i].sin_port, service, sc,
342 rx_NewConnection(cellinfo.hostAddr[i].sin_addr.s_addr,
343 cellinfo.hostAddr[i].sin_port, service, sc, si);
345 serverconns[cellinfo.numServers] = 0; /* terminate list */
347 /* next, pass list of server rx_connections (in serverconns), and a place
348 * to put the returned client structure that we'll use in all of our rpc
349 * calls (via ubik_Call) */
351 code = ubik_ClientInit(serverconns, conn);
360 CheckTicketAnswer(ka_BBS * oanswer, afs_int32 challenge,
361 struct ktc_token *token, struct ktc_principal *caller,
362 struct ktc_principal *server, char *label,
363 afs_int32 * pwexpires)
365 struct ka_ticketAnswer *answer;
369 answer = (struct ka_ticketAnswer *)oanswer->SeqBody;
371 cksum = ntohl(answer->cksum);
372 if (challenge != ntohl(answer->challenge))
373 return KABADPROTOCOL;
374 memcpy(&token->sessionKey, &answer->sessionKey,
375 sizeof(token->sessionKey));
376 token->startTime = ntohl(answer->startTime);
377 token->endTime = ntohl(answer->endTime);
378 token->kvno = (short)ntohl(answer->kvno);
379 token->ticketLen = ntohl(answer->ticketLen);
381 if (tkt_CheckTimes(token->startTime, token->endTime, time(0)) < 0)
382 return KABADPROTOCOL;
383 if ((token->ticketLen < MINKTCTICKETLEN)
384 || (token->ticketLen > MAXKTCTICKETLEN))
385 return KABADPROTOCOL;
388 char *strings = answer->name;
391 #define chkstr(field) \
392 len = strlen (strings); \
393 if (len > MAXKTCNAMELEN) return KABADPROTOCOL;\
394 if ((field) && strcmp (field, strings)) return KABADPROTOCOL;\
398 chkstr(caller->name);
399 chkstr(caller->instance);
400 chkstr(caller->cell);
407 chkstr(server->name);
408 chkstr(server->instance);
414 if (oanswer->SeqLen -
415 ((strings - oanswer->SeqBody) + token->ticketLen + KA_LABELSIZE)
416 >= (ENCRYPTIONBLOCKSIZE + 12)
418 return KABADPROTOCOL;
420 memcpy(token->ticket, strings, token->ticketLen);
421 strings += token->ticketLen;
422 if (memcmp(strings, label, KA_LABELSIZE) != 0)
423 return KABADPROTOCOL;
427 strings += KA_LABELSIZE;
428 temp = round_up_to_ebs((strings - oanswer->SeqBody));
430 if (oanswer->SeqLen > temp) {
431 strings = oanswer->SeqBody + temp;
432 memcpy(&temp, strings, sizeof(afs_int32));
433 tempc = ntohl(temp) >> 24;
434 /* don't forget this if you add any more fields!
435 * strings += sizeof(afs_int32);
447 /* call this instead of stub and we'll guarantee to find a host that's up.
448 * this doesn't handle UNOTSYNC very well, should use ubik_Call if you care
451 kawrap_ubik_Call(aproc, aclient, aflags, p1, p2, p3, p4, p5, p6, p7, p8)
452 struct ubik_client *aclient;
455 void *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
457 afs_int32 code, lcode;
461 /* First pass only checks servers known running. Second checks all.
462 * Once we've cycled through all the servers and still nothing, return
463 * error code from the last server tried.
465 for (pass = 0, aflags |= UPUBIKONLY; pass < 2;
466 pass++, aflags &= ~UPUBIKONLY) {
469 do { /* Cycle through the servers */
472 ubik_CallIter(aproc, aclient, aflags, &count, (long) p1,
473 (long) p2, (long) p3, (long) p4,
474 (long) p5, (long) p6, (long) p7,
475 (long) p8, 0, 0, 0, 0, 0, 0, 0, 0);
476 } while ((code == UNOQUORUM) || (code == UNOTSYNC)
477 || (code == KALOCKED) || (code == -1));
479 if (code != UNOSERVERS)
483 /* If cycled through all the servers, return the last error code */
484 if ((code == UNOSERVERS) && lcode) {
490 /* This is the interface to the AuthServer RPC routine Authenticate. It
491 formats the request packet, calls the encryption routine on the answer,
492 calls Authenticate, and decrypts the response. The response is checked for
493 correctness and its contents are copied into the token. */
496 KABADKEY = the key failed when converted to a key schedule. Probably bad
498 KAUBIKCALL - the call to Ubik returned an error, probably a communication
499 failure such as timeout.
500 KABADPROTOCOL - the returned packet was in error. Since a packet was
501 returned it can be presumed that the AuthServer correctly interpreted
502 the response. This may indicate an inauthentic AuthServer.
503 <other> - errors generated by the server process are returned directly.
507 ka_Authenticate(char *name, char *instance, char *cell, struct ubik_client * conn, /* Ubik connection to the AuthServer in
508 * the desired cell */
509 int service, /* ticket granting or admin service */
510 struct ktc_encryptionKey * key, Date start, Date end, /* ticket lifetime */
511 struct ktc_token * token, afs_int32 * pwexpires)
512 { /* days until it expires */
514 des_key_schedule schedule;
516 struct ka_gettgtRequest request;
517 struct ka_gettgtAnswer answer_old;
518 struct ka_ticketAnswer answer;
526 if ((code = des_key_sched(key, schedule))) {
531 if (service == KA_MAINTENANCE_SERVICE) {
532 req_label = KA_GETADM_REQ_LABEL;
533 ans_label = KA_GETADM_ANS_LABEL;
534 } else if (service == KA_TICKET_GRANTING_SERVICE) {
535 req_label = KA_GETTGT_REQ_LABEL;
536 ans_label = KA_GETTGT_ANS_LABEL;
539 return KABADARGUMENT;
542 request_time = time(0);
543 request.time = htonl(request_time);
544 memcpy(request.label, req_label, sizeof(request.label));
545 arequest.SeqLen = sizeof(request);
546 arequest.SeqBody = (char *)&request;
547 des_pcbc_encrypt(arequest.SeqBody, arequest.SeqBody, arequest.SeqLen,
548 schedule, key, ENCRYPT);
550 oanswer.MaxSeqLen = sizeof(answer);
552 oanswer.SeqBody = (char *)&answer;
556 kawrap_ubik_Call(KAA_AuthenticateV2, conn, 0, name, instance, start,
557 end, &arequest, &oanswer);
558 if (code == RXGEN_OPCODE) {
559 oanswer.MaxSeqLen = sizeof(answer);
560 oanswer.SeqBody = (char *)&answer;
563 ubik_Call(KAA_Authenticate, conn, 0, name, instance, start, end,
564 &arequest, &oanswer);
565 if (code == RXGEN_OPCODE) {
566 extern int KAA_Authenticate_old();
567 oanswer.MaxSeqLen = sizeof(answer_old);
568 oanswer.SeqBody = (char *)&answer_old;
571 ubik_Call(KAA_Authenticate_old, conn, 0, name, instance,
572 start, end, &arequest, &oanswer);
574 if (code == RXGEN_OPCODE) {
575 code = KAOLDINTERFACE;
580 if ((code >= KAMINERROR) && (code <= KAMAXERROR))
584 des_pcbc_encrypt(oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen,
585 schedule, key, DECRYPT);
591 struct ktc_principal caller;
592 strcpy(caller.name, name);
593 strcpy(caller.instance, instance);
594 strcpy(caller.cell, "");
596 CheckTicketAnswer(&oanswer, request_time + 1, token, &caller,
597 0, ans_label, pwexpires);
605 answer_old.time = ntohl(answer_old.time);
606 answer_old.ticket_len = ntohl(answer_old.ticket_len);
607 if ((answer_old.time != request_time + 1)
608 || (answer_old.ticket_len < MINKTCTICKETLEN)
609 || (answer_old.ticket_len > MAXKTCTICKETLEN)) {
611 return KABADPROTOCOL;
614 char *label = ((char *)answer_old.ticket) + answer_old.ticket_len;
616 if (strncmp(label, ans_label, sizeof(answer_old.label))) {
618 return KABADPROTOCOL;
620 token->startTime = start;
621 token->endTime = end;
622 token->kvno = ntohl(answer_old.kvno);
623 token->ticketLen = answer_old.ticket_len;
624 memcpy(token->ticket, answer_old.ticket, sizeof(token->ticket));
625 memcpy(&token->sessionKey, &answer_old.sessionkey,
626 sizeof(struct ktc_encryptionKey));
631 return KAINTERNALERROR;
639 ka_GetToken(char *name, char *instance, char *cell, char *cname, char *cinst, struct ubik_client * conn, /* Ubik conn to cell's AuthServer */
640 Date start, Date end, /* desired ticket lifetime */
641 struct ktc_token * auth_token, char *auth_domain,
642 struct ktc_token * token)
644 struct ka_getTicketTimes times;
645 struct ka_getTicketAnswer answer_old;
646 struct ka_ticketAnswer answer;
653 des_key_schedule schedule;
658 aticket.SeqLen = auth_token->ticketLen;
659 aticket.SeqBody = auth_token->ticket;
661 code = des_key_sched(&auth_token->sessionKey, schedule);
667 times.start = htonl(start);
668 times.end = htonl(end);
669 des_ecb_encrypt(×, ×, schedule, ENCRYPT);
671 atimes.SeqLen = sizeof(times);
672 atimes.SeqBody = (char *)×
675 oanswer.MaxSeqLen = sizeof(answer);
676 oanswer.SeqBody = (char *)&answer;
680 ubik_Call(KAT_GetTicket, conn, 0, auth_token->kvno, auth_domain,
681 &aticket, name, instance, &atimes, &oanswer);
682 if (code == RXGEN_OPCODE) {
683 extern int KAT_GetTicket_old();
684 oanswer.SeqLen = 0; /* this may be set by first call */
685 oanswer.MaxSeqLen = sizeof(answer_old);
686 oanswer.SeqBody = (char *)&answer_old;
689 ubik_Call(KAT_GetTicket_old, conn, 0, auth_token->kvno,
690 auth_domain, &aticket, name, instance, &atimes,
692 if (code == RXGEN_OPCODE) {
693 code = KAOLDINTERFACE;
698 if ((code >= KAMINERROR) && (code <= KAMAXERROR))
703 des_pcbc_encrypt(oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen,
704 schedule, &auth_token->sessionKey, DECRYPT);
709 struct ktc_principal server;
710 strcpy(server.name, name);
711 strcpy(server.instance, instance);
713 CheckTicketAnswer(&oanswer, 0, token, 0, &server,
714 KA_GETTICKET_ANS_LABEL, &pwexpires);
722 token->startTime = ntohl(answer_old.startTime);
723 token->endTime = ntohl(answer_old.endTime);
724 token->ticketLen = ntohl(answer_old.ticketLen);
725 token->kvno = ntohl(answer_old.kvno);
726 memcpy(&token->sessionKey, &answer_old.sessionKey,
727 sizeof(token->sessionKey));
729 if (tkt_CheckTimes(token->startTime, token->endTime, time(0)) < 0) {
731 return KABADPROTOCOL;
733 if ((token->ticketLen < MINKTCTICKETLEN)
734 || (token->ticketLen > MAXKTCTICKETLEN)) {
736 return KABADPROTOCOL;
738 strings = answer_old.name;
739 len = strlen(strings); /* check client name */
740 if ((len < 1) || (len > MAXKTCNAMELEN)) {
742 return KABADPROTOCOL;
744 strings += len + 1; /* check client instance */
745 len = strlen(strings);
746 if ((len < 0) || (len > MAXKTCNAMELEN)) {
748 return KABADPROTOCOL;
751 len = strlen(strings); /* check client cell */
752 if ((len < 0) || (len > MAXKTCNAMELEN)) {
754 return KABADPROTOCOL;
757 len = strlen(strings); /* check server name */
758 if ((len < 1) || (len > MAXKTCNAMELEN) || strcmp(name, strings)) {
760 return KABADPROTOCOL;
763 len = strlen(strings); /* check server instance */
764 if ((len < 0) || (len > MAXKTCNAMELEN) || strcmp(instance, strings)) {
766 return KABADPROTOCOL;
770 if ((strings - oanswer.SeqBody + token->ticketLen) - oanswer.SeqLen >=
771 ENCRYPTIONBLOCKSIZE) {
773 return KABADPROTOCOL;
775 memcpy(token->ticket, strings, token->ticketLen);
780 return KAINTERNALERROR;
788 ka_ChangePassword(char *name, char *instance, struct ubik_client * conn, /* Ubik connection to the AuthServer in
789 * the desired cell */
790 struct ktc_encryptionKey * oldkey,
791 struct ktc_encryptionKey * newkey)
796 #if defined(AFS_S390_LINUX20_ENV) && !defined(AFS_S390X_LINUX20_ENV)
798 ubik_Call_New(KAM_SetPassword, conn, 0, name, instance, 0, 0,
802 ubik_Call_New(KAM_SetPassword, conn, 0, name, instance, 0, *newkey);