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>
20 #define UBIK_LEGACY_CALLITER 1
23 #include "afs/sysincludes.h"
24 #include "afsincludes.h"
25 #include "afs_usrops.h"
27 #include "afs/pthread_glock.h"
29 #include "des_prototypes.h"
31 #include "afs/cellconfig.h"
34 #include "afs/afsutil.h"
36 #include "afs/kauth.h"
37 #include "afs/kautils.h"
38 #include "afs/pthread_glock.h"
40 #else /* defined(UKERNEL) */
42 #include <afs/pthread_glock.h>
43 #include <sys/types.h>
47 #include <sys/socket.h>
48 #include <netinet/in.h>
53 #include <des_prototypes.h>
55 #include <afs/cellconfig.h>
58 #include <afs/afsutil.h>
61 #endif /* defined(UKERNEL) */
64 static struct afsconf_dir *conf = 0;
65 static struct afsconf_cell explicit_cell_server_list;
66 static struct afsconf_cell debug_cell_server_list;
67 static int explicit = 0;
70 #ifdef ENCRYPTIONBLOCKSIZE
71 #undef ENCRYPTIONBLOCKSIZE
73 #define ENCRYPTIONBLOCKSIZE (sizeof(des_cblock))
75 /* Copy the specified list of servers into a specially know cell named
76 "explicit". The cell can then be used to debug experimental servers. */
79 ka_ExplicitCell(char *cell, afs_int32 serverList[])
84 ka_ExpandCell(cell, explicit_cell_server_list.name, 0);
85 for (i = 0; i < MAXHOSTSPERCELL; i++)
87 explicit_cell_server_list.numServers = i + 1;
88 explicit_cell_server_list.hostAddr[i].sin_family = AF_INET;
89 explicit_cell_server_list.hostAddr[i].sin_addr.s_addr =
91 explicit_cell_server_list.hostName[i][0] = 0;
92 explicit_cell_server_list.hostAddr[i].sin_port =
93 htons(AFSCONF_KAUTHPORT);
94 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
95 explicit_cell_server_list.hostAddr[i].sin_len =
96 sizeof(struct sockaddr_in);
105 myCellLookup(struct afsconf_dir *conf, char *cell, char *service,
106 struct afsconf_cell *cellinfo)
109 *cellinfo = debug_cell_server_list;
112 && (strcmp(cell, explicit_cell_server_list.name) == 0)) {
113 *cellinfo = explicit_cell_server_list;
116 /* call the real one */
118 return afsconf_GetCellInfo(conf, cell, service, cellinfo);
122 ka_GetServers(char *cell, struct afsconf_cell * cellinfo)
125 char cellname[MAXKTCREALMLEN];
128 if (cell && !strlen(cell))
131 cell = lcstring(cellname, cell, sizeof(cellname));
137 conf = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
144 code = myCellLookup(conf, cell, AFSCONF_KAUTHSERVICE, cellinfo);
150 ka_GetSecurity(int service, struct ktc_token * token,
151 struct rx_securityClass ** scP, int *siP)
152 { /* security class index */
156 case KA_AUTHENTICATION_SERVICE:
157 case KA_TICKET_GRANTING_SERVICE:
159 *scP = rxnull_NewClientSecurityObject();
160 *siP = RX_SCINDEX_NULL;
162 case KA_MAINTENANCE_SERVICE:
166 rxkad_NewClientSecurityObject(rxkad_crypt, &token->sessionKey,
167 token->kvno, token->ticketLen,
169 *siP = RX_SCINDEX_KAD;
173 return KABADARGUMENT;
176 printf("Failed gettting security object\n");
185 ka_SingleServerConn(char *cell, char *server, /* name of server to contact */
186 int service, struct ktc_token * token,
187 struct ubik_client ** conn)
190 struct rx_connection *serverconns[2];
191 struct rx_securityClass *sc;
192 int si; /* security class index */
193 struct afsconf_cell cellinfo; /* for cell auth server list */
196 char sname[MAXHOSTCHARS];
200 code = ka_GetServers(cell, &cellinfo);
206 lcstring(sname, server, sizeof(sname));
207 snamel = strlen(sname);
209 for (i = 0; i < cellinfo.numServers; i++) {
210 if (strncmp(cellinfo.hostName[i], sname, snamel) == 0) {
229 code = ka_GetSecurity(service, token, &sc, &si);
234 #ifdef AFS_PTHREAD_ENV
236 rx_GetCachedConnection(cellinfo.hostAddr[match].sin_addr.s_addr,
237 cellinfo.hostAddr[match].sin_port, service, sc,
241 rx_NewConnection(cellinfo.hostAddr[match].sin_addr.s_addr,
242 cellinfo.hostAddr[match].sin_port, service, sc, si);
244 serverconns[1] = 0; /* terminate list */
246 /* next, pass list of server rx_connections (in serverconns), and a place
247 * to put the returned client structure that we'll use in all of our rpc
248 * calls (via ubik_Call) */
250 code = ubik_ClientInit(serverconns, conn);
259 ka_AuthSpecificServersConn(int service, struct ktc_token * token,
260 struct afsconf_cell * cellinfo,
261 struct ubik_client ** conn)
264 struct rx_connection *serverconns[MAXSERVERS];
265 struct rx_securityClass *sc;
266 int si; /* security class index */
276 code = ka_GetSecurity(service, token, &sc, &si);
282 for (i = 0; i < cellinfo->numServers; i++)
283 #ifdef AFS_PTHREAD_ENV
285 rx_GetCachedConnection(cellinfo->hostAddr[i].sin_addr.s_addr,
286 cellinfo->hostAddr[i].sin_port, service,
290 rx_NewConnection(cellinfo->hostAddr[i].sin_addr.s_addr,
291 cellinfo->hostAddr[i].sin_port, service, sc, si);
293 serverconns[cellinfo->numServers] = 0; /* terminate list */
295 /* next, pass list of server rx_connections (in serverconns), and a place
296 * to put the returned client structure that we'll use in all of our rpc
297 * calls (via ubik_Call) */
299 code = ubik_ClientInit(serverconns, conn);
308 ka_AuthServerConn(char *cell, int service, struct ktc_token * token,
309 struct ubik_client ** conn)
312 struct rx_connection *serverconns[MAXSERVERS];
313 struct rx_securityClass *sc;
314 int si; /* security class index */
316 struct afsconf_cell cellinfo; /* for cell auth server list */
319 code = ka_GetServers(cell, &cellinfo);
331 code = ka_GetSecurity(service, token, &sc, &si);
337 for (i = 0; i < cellinfo.numServers; i++)
338 #ifdef AFS_PTHREAD_ENV
340 rx_GetCachedConnection(cellinfo.hostAddr[i].sin_addr.s_addr,
341 cellinfo.hostAddr[i].sin_port, service, sc,
345 rx_NewConnection(cellinfo.hostAddr[i].sin_addr.s_addr,
346 cellinfo.hostAddr[i].sin_port, service, sc, si);
348 serverconns[cellinfo.numServers] = 0; /* terminate list */
350 /* next, pass list of server rx_connections (in serverconns), and a place
351 * to put the returned client structure that we'll use in all of our rpc
352 * calls (via ubik_Call) */
354 code = ubik_ClientInit(serverconns, conn);
363 CheckTicketAnswer(ka_BBS * oanswer, afs_int32 challenge,
364 struct ktc_token *token, struct ktc_principal *caller,
365 struct ktc_principal *server, char *label,
366 afs_int32 * pwexpires)
368 struct ka_ticketAnswer *answer;
372 answer = (struct ka_ticketAnswer *)oanswer->SeqBody;
374 cksum = ntohl(answer->cksum);
375 if (challenge != ntohl(answer->challenge))
376 return KABADPROTOCOL;
377 memcpy(&token->sessionKey, &answer->sessionKey,
378 sizeof(token->sessionKey));
379 token->startTime = ntohl(answer->startTime);
380 token->endTime = ntohl(answer->endTime);
381 token->kvno = (short)ntohl(answer->kvno);
382 token->ticketLen = ntohl(answer->ticketLen);
384 if (tkt_CheckTimes(token->startTime, token->endTime, time(0)) < 0)
385 return KABADPROTOCOL;
386 if ((token->ticketLen < MINKTCTICKETLEN)
387 || (token->ticketLen > MAXKTCTICKETLEN))
388 return KABADPROTOCOL;
391 char *strings = answer->name;
394 #define chkstr(field) \
395 len = strlen (strings); \
396 if (len > MAXKTCNAMELEN) return KABADPROTOCOL;\
397 if ((field) && strcmp (field, strings)) return KABADPROTOCOL;\
401 len = strlen(strings); \
402 if (len > MAXKTCNAMELEN) return KABADPROTOCOL; \
406 chkstr(caller->name);
407 chkstr(caller->instance);
408 chkstr(caller->cell);
415 chkstr(server->name);
416 chkstr(server->instance);
422 if (oanswer->SeqLen -
423 ((strings - oanswer->SeqBody) + token->ticketLen + KA_LABELSIZE)
424 >= (ENCRYPTIONBLOCKSIZE + 12)
426 return KABADPROTOCOL;
428 memcpy(token->ticket, strings, token->ticketLen);
429 strings += token->ticketLen;
430 if (memcmp(strings, label, KA_LABELSIZE) != 0)
431 return KABADPROTOCOL;
435 strings += KA_LABELSIZE;
436 temp = round_up_to_ebs((strings - oanswer->SeqBody));
438 if (oanswer->SeqLen > temp) {
439 strings = oanswer->SeqBody + temp;
440 memcpy(&temp, strings, sizeof(afs_int32));
441 tempc = ntohl(temp) >> 24;
442 /* don't forget this if you add any more fields!
443 * strings += sizeof(afs_int32);
455 /* call this instead of stub and we'll guarantee to find a host that's up.
456 * this doesn't handle UNOTSYNC very well, should use ubik_Call if you care
459 kawrap_ubik_Call(aproc, aclient, aflags, p1, p2, p3, p4, p5, p6, p7, p8)
460 struct ubik_client *aclient;
463 void *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
465 afs_int32 code, lcode;
469 /* First pass only checks servers known running. Second checks all.
470 * Once we've cycled through all the servers and still nothing, return
471 * error code from the last server tried.
473 for (pass = 0, aflags |= UPUBIKONLY; pass < 2;
474 pass++, aflags &= ~UPUBIKONLY) {
477 do { /* Cycle through the servers */
480 ubik_CallIter(aproc, aclient, aflags, &count, (long) p1,
481 (long) p2, (long) p3, (long) p4,
482 (long) p5, (long) p6, (long) p7,
483 (long) p8, 0, 0, 0, 0, 0, 0, 0, 0);
484 } while ((code == UNOQUORUM) || (code == UNOTSYNC)
485 || (code == KALOCKED) || (code == -1));
487 if (code != UNOSERVERS)
491 /* If cycled through all the servers, return the last error code */
492 if ((code == UNOSERVERS) && lcode) {
498 /* This is the interface to the AuthServer RPC routine Authenticate. It
499 formats the request packet, calls the encryption routine on the answer,
500 calls Authenticate, and decrypts the response. The response is checked for
501 correctness and its contents are copied into the token. */
504 KABADKEY = the key failed when converted to a key schedule. Probably bad
506 KAUBIKCALL - the call to Ubik returned an error, probably a communication
507 failure such as timeout.
508 KABADPROTOCOL - the returned packet was in error. Since a packet was
509 returned it can be presumed that the AuthServer correctly interpreted
510 the response. This may indicate an inauthentic AuthServer.
511 <other> - errors generated by the server process are returned directly.
515 ka_Authenticate(char *name, char *instance, char *cell, struct ubik_client * conn, /* Ubik connection to the AuthServer in
516 * the desired cell */
517 int service, /* ticket granting or admin service */
518 struct ktc_encryptionKey * key, Date start, Date end, /* ticket lifetime */
519 struct ktc_token * token, afs_int32 * pwexpires)
520 { /* days until it expires */
522 des_key_schedule schedule;
524 struct ka_gettgtRequest request;
525 struct ka_gettgtAnswer answer_old;
526 struct ka_ticketAnswer answer;
534 if ((code = des_key_sched(ktc_to_cblock(key), schedule))) {
539 if (service == KA_MAINTENANCE_SERVICE) {
540 req_label = KA_GETADM_REQ_LABEL;
541 ans_label = KA_GETADM_ANS_LABEL;
542 } else if (service == KA_TICKET_GRANTING_SERVICE) {
543 req_label = KA_GETTGT_REQ_LABEL;
544 ans_label = KA_GETTGT_ANS_LABEL;
547 return KABADARGUMENT;
550 request_time = time(0);
551 request.time = htonl(request_time);
552 memcpy(request.label, req_label, sizeof(request.label));
553 arequest.SeqLen = sizeof(request);
554 arequest.SeqBody = (char *)&request;
555 des_pcbc_encrypt(arequest.SeqBody, arequest.SeqBody, arequest.SeqLen,
556 schedule, ktc_to_cblockptr(key), ENCRYPT);
558 oanswer.MaxSeqLen = sizeof(answer);
560 oanswer.SeqBody = (char *)&answer;
564 kawrap_ubik_Call(KAA_AuthenticateV2, conn, 0, name, instance,
565 start, end, &arequest, &oanswer, 0, 0);
566 if (code == RXGEN_OPCODE) {
567 oanswer.MaxSeqLen = sizeof(answer);
568 oanswer.SeqBody = (char *)&answer;
571 ubik_Call(KAA_Authenticate, conn, 0, name, instance, start, end,
572 &arequest, &oanswer, 0, 0);
573 if (code == RXGEN_OPCODE) {
574 oanswer.MaxSeqLen = sizeof(answer_old);
575 oanswer.SeqBody = (char *)&answer_old;
578 ubik_Call(KAA_Authenticate_old, conn, 0, name, instance,
579 start, end, &arequest, &oanswer);
581 if (code == RXGEN_OPCODE) {
582 code = KAOLDINTERFACE;
587 if ((code >= KAMINERROR) && (code <= KAMAXERROR))
591 des_pcbc_encrypt(oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen,
592 schedule, ktc_to_cblockptr(key), DECRYPT);
598 struct ktc_principal caller;
599 strcpy(caller.name, name);
600 strcpy(caller.instance, instance);
601 strcpy(caller.cell, "");
603 CheckTicketAnswer(&oanswer, request_time + 1, token, &caller,
604 0, ans_label, pwexpires);
612 answer_old.time = ntohl(answer_old.time);
613 answer_old.ticket_len = ntohl(answer_old.ticket_len);
614 if ((answer_old.time != request_time + 1)
615 || (answer_old.ticket_len < MINKTCTICKETLEN)
616 || (answer_old.ticket_len > MAXKTCTICKETLEN)) {
618 return KABADPROTOCOL;
621 char *label = ((char *)answer_old.ticket) + answer_old.ticket_len;
623 if (strncmp(label, ans_label, sizeof(answer_old.label))) {
625 return KABADPROTOCOL;
627 token->startTime = start;
628 token->endTime = end;
629 token->kvno = ntohl(answer_old.kvno);
630 token->ticketLen = answer_old.ticket_len;
631 memcpy(token->ticket, answer_old.ticket, sizeof(token->ticket));
632 memcpy(&token->sessionKey, &answer_old.sessionkey,
633 sizeof(struct ktc_encryptionKey));
638 return KAINTERNALERROR;
646 ka_GetToken(char *name, char *instance, char *cell, char *cname, char *cinst, struct ubik_client * conn, /* Ubik conn to cell's AuthServer */
647 Date start, Date end, /* desired ticket lifetime */
648 struct ktc_token * auth_token, char *auth_domain,
649 struct ktc_token * token)
651 struct ka_getTicketTimes times;
652 struct ka_getTicketAnswer answer_old;
653 struct ka_ticketAnswer answer;
660 des_key_schedule schedule;
665 aticket.SeqLen = auth_token->ticketLen;
666 aticket.SeqBody = auth_token->ticket;
668 code = des_key_sched(ktc_to_cblock(&auth_token->sessionKey), schedule);
674 times.start = htonl(start);
675 times.end = htonl(end);
676 des_ecb_encrypt(×, ×, schedule, ENCRYPT);
678 atimes.SeqLen = sizeof(times);
679 atimes.SeqBody = (char *)×
682 oanswer.MaxSeqLen = sizeof(answer);
683 oanswer.SeqBody = (char *)&answer;
687 ubik_Call(KAT_GetTicket, conn, 0, auth_token->kvno, auth_domain,
688 &aticket, name, instance, &atimes, &oanswer);
689 if (code == RXGEN_OPCODE) {
690 oanswer.SeqLen = 0; /* this may be set by first call */
691 oanswer.MaxSeqLen = sizeof(answer_old);
692 oanswer.SeqBody = (char *)&answer_old;
695 ubik_Call(KAT_GetTicket_old, conn, 0, auth_token->kvno,
696 auth_domain, &aticket, name, instance, &atimes,
698 if (code == RXGEN_OPCODE) {
699 code = KAOLDINTERFACE;
704 if ((code >= KAMINERROR) && (code <= KAMAXERROR))
709 des_pcbc_encrypt(oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen,
710 schedule, ktc_to_cblockptr(&auth_token->sessionKey), DECRYPT);
715 struct ktc_principal server;
716 strcpy(server.name, name);
717 strcpy(server.instance, instance);
719 CheckTicketAnswer(&oanswer, 0, token, 0, &server,
720 KA_GETTICKET_ANS_LABEL, &pwexpires);
728 token->startTime = ntohl(answer_old.startTime);
729 token->endTime = ntohl(answer_old.endTime);
730 token->ticketLen = ntohl(answer_old.ticketLen);
731 token->kvno = ntohl(answer_old.kvno);
732 memcpy(&token->sessionKey, &answer_old.sessionKey,
733 sizeof(token->sessionKey));
735 if (tkt_CheckTimes(token->startTime, token->endTime, time(0)) < 0) {
737 return KABADPROTOCOL;
739 if ((token->ticketLen < MINKTCTICKETLEN)
740 || (token->ticketLen > MAXKTCTICKETLEN)) {
742 return KABADPROTOCOL;
744 strings = answer_old.name;
745 len = strlen(strings); /* check client name */
746 if ((len < 1) || (len > MAXKTCNAMELEN)) {
748 return KABADPROTOCOL;
750 strings += len + 1; /* check client instance */
751 len = strlen(strings);
752 if ((len < 0) || (len > MAXKTCNAMELEN)) {
754 return KABADPROTOCOL;
757 len = strlen(strings); /* check client cell */
758 if ((len < 0) || (len > MAXKTCNAMELEN)) {
760 return KABADPROTOCOL;
763 len = strlen(strings); /* check server name */
764 if ((len < 1) || (len > MAXKTCNAMELEN) || strcmp(name, strings)) {
766 return KABADPROTOCOL;
769 len = strlen(strings); /* check server instance */
770 if ((len < 0) || (len > MAXKTCNAMELEN) || strcmp(instance, strings)) {
772 return KABADPROTOCOL;
776 if ((strings - oanswer.SeqBody + token->ticketLen) - oanswer.SeqLen >=
777 ENCRYPTIONBLOCKSIZE) {
779 return KABADPROTOCOL;
781 memcpy(token->ticket, strings, token->ticketLen);
786 return KAINTERNALERROR;
794 ka_ChangePassword(char *name, char *instance, struct ubik_client * conn, /* Ubik connection to the AuthServer in
795 * the desired cell */
796 struct ktc_encryptionKey * oldkey,
797 struct ktc_encryptionKey * newkey)
802 #if defined(AFS_S390_LINUX20_ENV) && !defined(AFS_S390X_LINUX20_ENV)
804 ubik_Call_New(KAM_SetPassword, conn, 0, name, instance, 0, 0,
808 ubik_Call_New(KAM_SetPassword, conn, 0, name, instance, 0, *newkey);