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>
19 #ifdef IGNORE_SOME_GCC_WARNINGS
20 # pragma GCC diagnostic warning "-Wstrict-prototypes"
21 # pragma GCC diagnostic warning "-Wimplicit-function-declaration"
24 #define UBIK_LEGACY_CALLITER 1
27 #include "afs/sysincludes.h"
28 #include "afsincludes.h"
29 #include "afs_usrops.h"
31 #include "afs/pthread_glock.h"
33 #include "des_prototypes.h"
35 #include "afs/cellconfig.h"
38 #include "afs/afsutil.h"
40 #include "afs/kauth.h"
41 #include "afs/kautils.h"
42 #include "afs/pthread_glock.h"
44 #else /* defined(UKERNEL) */
46 #include <afs/pthread_glock.h>
47 #include <sys/types.h>
51 #include <sys/socket.h>
52 #include <netinet/in.h>
60 #include <des_prototypes.h>
62 #include <afs/cellconfig.h>
65 #include <afs/afsutil.h>
68 #endif /* defined(UKERNEL) */
71 static struct afsconf_dir *conf = 0;
72 static struct afsconf_cell explicit_cell_server_list;
73 static struct afsconf_cell debug_cell_server_list;
74 static int explicit = 0;
77 #ifdef ENCRYPTIONBLOCKSIZE
78 #undef ENCRYPTIONBLOCKSIZE
80 #define ENCRYPTIONBLOCKSIZE (sizeof(des_cblock))
82 /* Copy the specified list of servers into a specially know cell named
83 "explicit". The cell can then be used to debug experimental servers. */
86 ka_ExplicitCell(char *cell, afs_int32 serverList[])
91 ka_ExpandCell(cell, explicit_cell_server_list.name, 0);
92 for (i = 0; i < MAXHOSTSPERCELL; i++)
94 explicit_cell_server_list.numServers = i + 1;
95 explicit_cell_server_list.hostAddr[i].sin_family = AF_INET;
96 explicit_cell_server_list.hostAddr[i].sin_addr.s_addr =
98 explicit_cell_server_list.hostName[i][0] = 0;
99 explicit_cell_server_list.hostAddr[i].sin_port =
100 htons(AFSCONF_KAUTHPORT);
101 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
102 explicit_cell_server_list.hostAddr[i].sin_len =
103 sizeof(struct sockaddr_in);
112 myCellLookup(struct afsconf_dir *conf, char *cell, char *service,
113 struct afsconf_cell *cellinfo)
116 *cellinfo = debug_cell_server_list;
119 && (strcmp(cell, explicit_cell_server_list.name) == 0)) {
120 *cellinfo = explicit_cell_server_list;
123 /* call the real one */
125 return afsconf_GetCellInfo(conf, cell, service, cellinfo);
129 ka_GetServers(char *cell, struct afsconf_cell * cellinfo)
132 char cellname[MAXKTCREALMLEN];
135 if (cell && !strlen(cell))
138 cell = lcstring(cellname, cell, sizeof(cellname));
144 conf = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
151 code = myCellLookup(conf, cell, AFSCONF_KAUTHSERVICE, cellinfo);
157 ka_GetSecurity(int service, struct ktc_token * token,
158 struct rx_securityClass ** scP, int *siP)
159 { /* security class index */
163 case KA_AUTHENTICATION_SERVICE:
164 case KA_TICKET_GRANTING_SERVICE:
166 *scP = rxnull_NewClientSecurityObject();
167 *siP = RX_SCINDEX_NULL;
169 case KA_MAINTENANCE_SERVICE:
173 rxkad_NewClientSecurityObject(rxkad_crypt, &token->sessionKey,
174 token->kvno, token->ticketLen,
176 *siP = RX_SCINDEX_KAD;
180 return KABADARGUMENT;
183 printf("Failed gettting security object\n");
192 ka_SingleServerConn(char *cell, char *server, /* name of server to contact */
193 int service, struct ktc_token * token,
194 struct ubik_client ** conn)
197 struct rx_connection *serverconns[2];
198 struct rx_securityClass *sc;
199 int si; /* security class index */
200 struct afsconf_cell cellinfo; /* for cell auth server list */
203 char sname[MAXHOSTCHARS];
207 code = ka_GetServers(cell, &cellinfo);
213 lcstring(sname, server, sizeof(sname));
214 snamel = strlen(sname);
216 for (i = 0; i < cellinfo.numServers; i++) {
217 if (strncmp(cellinfo.hostName[i], sname, snamel) == 0) {
236 code = ka_GetSecurity(service, token, &sc, &si);
241 #ifdef AFS_PTHREAD_ENV
243 rx_GetCachedConnection(cellinfo.hostAddr[match].sin_addr.s_addr,
244 cellinfo.hostAddr[match].sin_port, service, sc,
248 rx_NewConnection(cellinfo.hostAddr[match].sin_addr.s_addr,
249 cellinfo.hostAddr[match].sin_port, service, sc, si);
251 serverconns[1] = 0; /* terminate list */
253 /* next, pass list of server rx_connections (in serverconns), and a place
254 * to put the returned client structure that we'll use in all of our rpc
255 * calls (via ubik_Call) */
257 code = ubik_ClientInit(serverconns, conn);
266 ka_AuthSpecificServersConn(int service, struct ktc_token * token,
267 struct afsconf_cell * cellinfo,
268 struct ubik_client ** conn)
271 struct rx_connection *serverconns[MAXSERVERS];
272 struct rx_securityClass *sc;
273 int si; /* security class index */
283 code = ka_GetSecurity(service, token, &sc, &si);
289 for (i = 0; i < cellinfo->numServers; i++)
290 #ifdef AFS_PTHREAD_ENV
292 rx_GetCachedConnection(cellinfo->hostAddr[i].sin_addr.s_addr,
293 cellinfo->hostAddr[i].sin_port, service,
297 rx_NewConnection(cellinfo->hostAddr[i].sin_addr.s_addr,
298 cellinfo->hostAddr[i].sin_port, service, sc, si);
300 serverconns[cellinfo->numServers] = 0; /* terminate list */
302 /* next, pass list of server rx_connections (in serverconns), and a place
303 * to put the returned client structure that we'll use in all of our rpc
304 * calls (via ubik_Call) */
306 code = ubik_ClientInit(serverconns, conn);
315 ka_AuthServerConn(char *cell, int service, struct ktc_token * token,
316 struct ubik_client ** conn)
319 struct rx_connection *serverconns[MAXSERVERS];
320 struct rx_securityClass *sc;
321 int si; /* security class index */
323 struct afsconf_cell cellinfo; /* for cell auth server list */
326 code = ka_GetServers(cell, &cellinfo);
338 code = ka_GetSecurity(service, token, &sc, &si);
344 for (i = 0; i < cellinfo.numServers; i++)
345 #ifdef AFS_PTHREAD_ENV
347 rx_GetCachedConnection(cellinfo.hostAddr[i].sin_addr.s_addr,
348 cellinfo.hostAddr[i].sin_port, service, sc,
352 rx_NewConnection(cellinfo.hostAddr[i].sin_addr.s_addr,
353 cellinfo.hostAddr[i].sin_port, service, sc, si);
355 serverconns[cellinfo.numServers] = 0; /* terminate list */
357 /* next, pass list of server rx_connections (in serverconns), and a place
358 * to put the returned client structure that we'll use in all of our rpc
359 * calls (via ubik_Call) */
361 code = ubik_ClientInit(serverconns, conn);
370 CheckTicketAnswer(ka_BBS * oanswer, afs_int32 challenge,
371 struct ktc_token *token, struct ktc_principal *caller,
372 struct ktc_principal *server, char *label,
373 afs_int32 * pwexpires)
375 struct ka_ticketAnswer *answer;
379 answer = (struct ka_ticketAnswer *)oanswer->SeqBody;
381 cksum = ntohl(answer->cksum);
382 if (challenge != ntohl(answer->challenge))
383 return KABADPROTOCOL;
384 memcpy(&token->sessionKey, &answer->sessionKey,
385 sizeof(token->sessionKey));
386 token->startTime = ntohl(answer->startTime);
387 token->endTime = ntohl(answer->endTime);
388 token->kvno = (short)ntohl(answer->kvno);
389 token->ticketLen = ntohl(answer->ticketLen);
391 if (tkt_CheckTimes(token->startTime, token->endTime, time(0)) < 0)
392 return KABADPROTOCOL;
393 if ((token->ticketLen < MINKTCTICKETLEN)
394 || (token->ticketLen > MAXKTCTICKETLEN))
395 return KABADPROTOCOL;
398 char *strings = answer->name;
401 #define chkstr(field) \
402 len = strlen (strings); \
403 if (len > MAXKTCNAMELEN) return KABADPROTOCOL;\
404 if ((field) && strcmp (field, strings)) return KABADPROTOCOL;\
408 len = strlen(strings); \
409 if (len > MAXKTCNAMELEN) return KABADPROTOCOL; \
413 chkstr(caller->name);
414 chkstr(caller->instance);
415 chkstr(caller->cell);
422 chkstr(server->name);
423 chkstr(server->instance);
429 if (oanswer->SeqLen -
430 ((strings - oanswer->SeqBody) + token->ticketLen + KA_LABELSIZE)
431 >= (ENCRYPTIONBLOCKSIZE + 12)
433 return KABADPROTOCOL;
435 memcpy(token->ticket, strings, token->ticketLen);
436 strings += token->ticketLen;
437 if (memcmp(strings, label, KA_LABELSIZE) != 0)
438 return KABADPROTOCOL;
442 strings += KA_LABELSIZE;
443 temp = round_up_to_ebs((strings - oanswer->SeqBody));
445 if (oanswer->SeqLen > temp) {
446 strings = oanswer->SeqBody + temp;
447 memcpy(&temp, strings, sizeof(afs_int32));
448 tempc = ntohl(temp) >> 24;
449 /* don't forget this if you add any more fields!
450 * strings += sizeof(afs_int32);
462 /* call this instead of stub and we'll guarantee to find a host that's up.
463 * this doesn't handle UNOTSYNC very well, should use ubik_Call if you care
466 kawrap_ubik_Call(int (*aproc) (), struct ubik_client *aclient,
467 afs_int32 aflags, void *p1, void *p2, void *p3, void *p4,
468 void *p5, void *p6, void *p7, void *p8)
470 afs_int32 code, lcode;
474 /* First pass only checks servers known running. Second checks all.
475 * Once we've cycled through all the servers and still nothing, return
476 * error code from the last server tried.
478 for (pass = 0, aflags |= UPUBIKONLY; pass < 2;
479 pass++, aflags &= ~UPUBIKONLY) {
482 do { /* Cycle through the servers */
485 ubik_CallIter(aproc, aclient, aflags, &count, (long) p1,
486 (long) p2, (long) p3, (long) p4,
487 (long) p5, (long) p6, (long) p7,
488 (long) p8, 0, 0, 0, 0, 0, 0, 0, 0);
489 } while ((code == UNOQUORUM) || (code == UNOTSYNC)
490 || (code == KALOCKED) || (code == -1));
492 if (code != UNOSERVERS)
496 /* If cycled through all the servers, return the last error code */
497 if ((code == UNOSERVERS) && lcode) {
503 /* This is the interface to the AuthServer RPC routine Authenticate. It
504 formats the request packet, calls the encryption routine on the answer,
505 calls Authenticate, and decrypts the response. The response is checked for
506 correctness and its contents are copied into the token. */
509 KABADKEY = the key failed when converted to a key schedule. Probably bad
511 KAUBIKCALL - the call to Ubik returned an error, probably a communication
512 failure such as timeout.
513 KABADPROTOCOL - the returned packet was in error. Since a packet was
514 returned it can be presumed that the AuthServer correctly interpreted
515 the response. This may indicate an inauthentic AuthServer.
516 <other> - errors generated by the server process are returned directly.
520 ka_Authenticate(char *name, char *instance, char *cell, struct ubik_client * conn, /* Ubik connection to the AuthServer in
521 * the desired cell */
522 int service, /* ticket granting or admin service */
523 struct ktc_encryptionKey * key, Date start, Date end, /* ticket lifetime */
524 struct ktc_token * token, afs_int32 * pwexpires)
525 { /* days until it expires */
527 des_key_schedule schedule;
529 struct ka_gettgtRequest request;
530 struct ka_gettgtAnswer answer_old;
531 struct ka_ticketAnswer answer;
539 if ((code = des_key_sched(ktc_to_cblock(key), schedule))) {
544 if (service == KA_MAINTENANCE_SERVICE) {
545 req_label = KA_GETADM_REQ_LABEL;
546 ans_label = KA_GETADM_ANS_LABEL;
547 } else if (service == KA_TICKET_GRANTING_SERVICE) {
548 req_label = KA_GETTGT_REQ_LABEL;
549 ans_label = KA_GETTGT_ANS_LABEL;
552 return KABADARGUMENT;
555 request_time = time(0);
556 request.time = htonl(request_time);
557 memcpy(request.label, req_label, sizeof(request.label));
558 arequest.SeqLen = sizeof(request);
559 arequest.SeqBody = (char *)&request;
560 des_pcbc_encrypt(arequest.SeqBody, arequest.SeqBody, arequest.SeqLen,
561 schedule, ktc_to_cblockptr(key), ENCRYPT);
563 oanswer.MaxSeqLen = sizeof(answer);
565 oanswer.SeqBody = (char *)&answer;
569 kawrap_ubik_Call(KAA_AuthenticateV2, conn, 0, name, instance,
570 (void*)(uintptr_t)start, (void*)(uintptr_t)end, &arequest, &oanswer, 0, 0);
571 if (code == RXGEN_OPCODE) {
572 oanswer.MaxSeqLen = sizeof(answer);
573 oanswer.SeqBody = (char *)&answer;
576 ubik_KAA_Authenticate(conn, 0, name, instance, start, end,
577 &arequest, &oanswer);
578 if (code == RXGEN_OPCODE) {
579 oanswer.MaxSeqLen = sizeof(answer_old);
580 oanswer.SeqBody = (char *)&answer_old;
583 ubik_KAA_Authenticate_old(conn, 0, name, instance,
584 start, end, &arequest, &oanswer);
586 if (code == RXGEN_OPCODE) {
587 code = KAOLDINTERFACE;
592 if ((code >= KAMINERROR) && (code <= KAMAXERROR))
596 des_pcbc_encrypt(oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen,
597 schedule, ktc_to_cblockptr(key), DECRYPT);
603 struct ktc_principal caller;
604 strcpy(caller.name, name);
605 strcpy(caller.instance, instance);
606 strcpy(caller.cell, "");
608 CheckTicketAnswer(&oanswer, request_time + 1, token, &caller,
609 0, ans_label, pwexpires);
617 answer_old.time = ntohl(answer_old.time);
618 answer_old.ticket_len = ntohl(answer_old.ticket_len);
619 if ((answer_old.time != request_time + 1)
620 || (answer_old.ticket_len < MINKTCTICKETLEN)
621 || (answer_old.ticket_len > MAXKTCTICKETLEN)) {
623 return KABADPROTOCOL;
626 char *label = ((char *)answer_old.ticket) + answer_old.ticket_len;
628 if (strncmp(label, ans_label, sizeof(answer_old.label))) {
630 return KABADPROTOCOL;
632 token->startTime = start;
633 token->endTime = end;
634 token->kvno = ntohl(answer_old.kvno);
635 token->ticketLen = answer_old.ticket_len;
636 memcpy(token->ticket, answer_old.ticket, sizeof(token->ticket));
637 memcpy(&token->sessionKey, &answer_old.sessionkey,
638 sizeof(struct ktc_encryptionKey));
643 return KAINTERNALERROR;
651 ka_GetToken(char *name, char *instance, char *cell, char *cname, char *cinst, struct ubik_client * conn, /* Ubik conn to cell's AuthServer */
652 Date start, Date end, /* desired ticket lifetime */
653 struct ktc_token * auth_token, char *auth_domain,
654 struct ktc_token * token)
656 struct ka_getTicketTimes times;
657 struct ka_getTicketAnswer answer_old;
658 struct ka_ticketAnswer answer;
665 des_key_schedule schedule;
670 aticket.SeqLen = auth_token->ticketLen;
671 aticket.SeqBody = auth_token->ticket;
673 code = des_key_sched(ktc_to_cblock(&auth_token->sessionKey), schedule);
679 times.start = htonl(start);
680 times.end = htonl(end);
681 des_ecb_encrypt(×, ×, schedule, ENCRYPT);
683 atimes.SeqLen = sizeof(times);
684 atimes.SeqBody = (char *)×
687 oanswer.MaxSeqLen = sizeof(answer);
688 oanswer.SeqBody = (char *)&answer;
692 ubik_KAT_GetTicket(conn, 0, auth_token->kvno, auth_domain,
693 &aticket, name, instance, &atimes, &oanswer);
694 if (code == RXGEN_OPCODE) {
695 oanswer.SeqLen = 0; /* this may be set by first call */
696 oanswer.MaxSeqLen = sizeof(answer_old);
697 oanswer.SeqBody = (char *)&answer_old;
700 ubik_KAT_GetTicket_old(conn, 0, auth_token->kvno,
701 auth_domain, &aticket, name, instance, &atimes,
703 if (code == RXGEN_OPCODE) {
704 code = KAOLDINTERFACE;
709 if ((code >= KAMINERROR) && (code <= KAMAXERROR))
714 des_pcbc_encrypt(oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen,
715 schedule, ktc_to_cblockptr(&auth_token->sessionKey), DECRYPT);
720 struct ktc_principal server;
721 strcpy(server.name, name);
722 strcpy(server.instance, instance);
724 CheckTicketAnswer(&oanswer, 0, token, 0, &server,
725 KA_GETTICKET_ANS_LABEL, &pwexpires);
733 token->startTime = ntohl(answer_old.startTime);
734 token->endTime = ntohl(answer_old.endTime);
735 token->ticketLen = ntohl(answer_old.ticketLen);
736 token->kvno = ntohl(answer_old.kvno);
737 memcpy(&token->sessionKey, &answer_old.sessionKey,
738 sizeof(token->sessionKey));
740 if (tkt_CheckTimes(token->startTime, token->endTime, time(0)) < 0) {
742 return KABADPROTOCOL;
744 if ((token->ticketLen < MINKTCTICKETLEN)
745 || (token->ticketLen > MAXKTCTICKETLEN)) {
747 return KABADPROTOCOL;
749 strings = answer_old.name;
750 len = strlen(strings); /* check client name */
751 if ((len < 1) || (len > MAXKTCNAMELEN)) {
753 return KABADPROTOCOL;
755 strings += len + 1; /* check client instance */
756 len = strlen(strings);
757 if ((len < 0) || (len > MAXKTCNAMELEN)) {
759 return KABADPROTOCOL;
762 len = strlen(strings); /* check client cell */
763 if ((len < 0) || (len > MAXKTCNAMELEN)) {
765 return KABADPROTOCOL;
768 len = strlen(strings); /* check server name */
769 if ((len < 1) || (len > MAXKTCNAMELEN) || strcmp(name, strings)) {
771 return KABADPROTOCOL;
774 len = strlen(strings); /* check server instance */
775 if ((len < 0) || (len > MAXKTCNAMELEN) || strcmp(instance, strings)) {
777 return KABADPROTOCOL;
781 if ((strings - oanswer.SeqBody + token->ticketLen) - oanswer.SeqLen >=
782 ENCRYPTIONBLOCKSIZE) {
784 return KABADPROTOCOL;
786 memcpy(token->ticket, strings, token->ticketLen);
791 return KAINTERNALERROR;
799 ka_ChangePassword(char *name, char *instance, struct ubik_client * conn, /* Ubik connection to the AuthServer in
800 * the desired cell */
801 struct ktc_encryptionKey * oldkey,
802 struct ktc_encryptionKey * newkey)
807 #if defined(AFS_S390_LINUX20_ENV) && !defined(AFS_S390X_LINUX20_ENV)
809 ubik_KAM_SetPassword(conn, UBIK_CALL_NEW, name, instance, 0, 0, *(EncryptionKey *)newkey);
812 ubik_KAM_SetPassword(conn, UBIK_CALL_NEW, name, instance, 0, *(EncryptionKey *)newkey);