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>
57 #include <afs/cellconfig.h>
61 #include <afs/afsutil.h>
64 #endif /* defined(UKERNEL) */
67 static struct afsconf_dir *conf = 0;
68 static struct afsconf_cell explicit_cell_server_list;
69 static struct afsconf_cell debug_cell_server_list;
70 static int explicit = 0;
73 #ifdef ENCRYPTIONBLOCKSIZE
74 #undef ENCRYPTIONBLOCKSIZE
76 #define ENCRYPTIONBLOCKSIZE (sizeof(des_cblock))
78 /* Copy the specified list of servers into a specially know cell named
79 "explicit". The cell can then be used to debug experimental servers. */
82 ka_ExplicitCell(char *cell, afs_int32 serverList[])
87 ka_ExpandCell(cell, explicit_cell_server_list.name, 0);
88 for (i = 0; i < MAXHOSTSPERCELL; i++)
90 explicit_cell_server_list.numServers = i + 1;
91 explicit_cell_server_list.hostAddr[i].sin_family = AF_INET;
92 explicit_cell_server_list.hostAddr[i].sin_addr.s_addr =
94 explicit_cell_server_list.hostName[i][0] = 0;
95 explicit_cell_server_list.hostAddr[i].sin_port =
96 htons(AFSCONF_KAUTHPORT);
97 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
98 explicit_cell_server_list.hostAddr[i].sin_len =
99 sizeof(struct sockaddr_in);
108 myCellLookup(struct afsconf_dir *conf, char *cell, char *service,
109 struct afsconf_cell *cellinfo)
112 *cellinfo = debug_cell_server_list;
115 && (strcmp(cell, explicit_cell_server_list.name) == 0)) {
116 *cellinfo = explicit_cell_server_list;
119 /* call the real one */
121 return afsconf_GetCellInfo(conf, cell, service, cellinfo);
125 ka_GetServers(char *cell, struct afsconf_cell * cellinfo)
128 char cellname[MAXKTCREALMLEN];
131 if (cell && !strlen(cell))
134 cell = lcstring(cellname, cell, sizeof(cellname));
140 conf = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
147 code = myCellLookup(conf, cell, AFSCONF_KAUTHSERVICE, cellinfo);
154 ka_GetSecurity(int service, struct ktc_token * token,
155 struct rx_securityClass ** scP, int *siP)
156 { /* security class index */
160 case KA_AUTHENTICATION_SERVICE:
161 case KA_TICKET_GRANTING_SERVICE:
163 *scP = rxnull_NewClientSecurityObject();
164 *siP = RX_SCINDEX_NULL;
166 case KA_MAINTENANCE_SERVICE:
170 rxkad_NewClientSecurityObject(rxkad_crypt, &token->sessionKey,
171 token->kvno, token->ticketLen,
173 *siP = RX_SCINDEX_KAD;
177 return KABADARGUMENT;
180 printf("Failed gettting security object\n");
189 ka_SingleServerConn(char *cell, char *server, /* name of server to contact */
190 int service, struct ktc_token * token,
191 struct ubik_client ** conn)
194 struct rx_connection *serverconns[2];
195 struct rx_securityClass *sc;
196 int si; /* security class index */
197 struct afsconf_cell cellinfo; /* for cell auth server list */
200 char sname[MAXHOSTCHARS];
204 code = ka_GetServers(cell, &cellinfo);
210 lcstring(sname, server, sizeof(sname));
211 snamel = strlen(sname);
213 for (i = 0; i < cellinfo.numServers; i++) {
214 if (strncmp(cellinfo.hostName[i], sname, snamel) == 0) {
233 code = ka_GetSecurity(service, token, &sc, &si);
238 #ifdef AFS_PTHREAD_ENV
240 rx_GetCachedConnection(cellinfo.hostAddr[match].sin_addr.s_addr,
241 cellinfo.hostAddr[match].sin_port, service, sc,
245 rx_NewConnection(cellinfo.hostAddr[match].sin_addr.s_addr,
246 cellinfo.hostAddr[match].sin_port, service, sc, si);
248 serverconns[1] = 0; /* terminate list */
250 /* next, pass list of server rx_connections (in serverconns), and a place
251 * to put the returned client structure that we'll use in all of our rpc
252 * calls (via ubik_Call) */
254 code = ubik_ClientInit(serverconns, conn);
263 ka_AuthSpecificServersConn(int service, struct ktc_token * token,
264 struct afsconf_cell * cellinfo,
265 struct ubik_client ** conn)
268 struct rx_connection *serverconns[MAXSERVERS];
269 struct rx_securityClass *sc;
270 int si; /* security class index */
280 code = ka_GetSecurity(service, token, &sc, &si);
286 for (i = 0; i < cellinfo->numServers; i++)
287 #ifdef AFS_PTHREAD_ENV
289 rx_GetCachedConnection(cellinfo->hostAddr[i].sin_addr.s_addr,
290 cellinfo->hostAddr[i].sin_port, service,
294 rx_NewConnection(cellinfo->hostAddr[i].sin_addr.s_addr,
295 cellinfo->hostAddr[i].sin_port, service, sc, si);
297 serverconns[cellinfo->numServers] = 0; /* terminate list */
299 /* next, pass list of server rx_connections (in serverconns), and a place
300 * to put the returned client structure that we'll use in all of our rpc
301 * calls (via ubik_Call) */
303 code = ubik_ClientInit(serverconns, conn);
312 ka_AuthServerConn(char *cell, int service, struct ktc_token * token,
313 struct ubik_client ** conn)
316 struct rx_connection *serverconns[MAXSERVERS];
317 struct rx_securityClass *sc;
318 int si; /* security class index */
320 struct afsconf_cell cellinfo; /* for cell auth server list */
323 code = ka_GetServers(cell, &cellinfo);
335 code = ka_GetSecurity(service, token, &sc, &si);
341 for (i = 0; i < cellinfo.numServers; i++)
342 #ifdef AFS_PTHREAD_ENV
344 rx_GetCachedConnection(cellinfo.hostAddr[i].sin_addr.s_addr,
345 cellinfo.hostAddr[i].sin_port, service, sc,
349 rx_NewConnection(cellinfo.hostAddr[i].sin_addr.s_addr,
350 cellinfo.hostAddr[i].sin_port, service, sc, si);
352 serverconns[cellinfo.numServers] = 0; /* terminate list */
354 /* next, pass list of server rx_connections (in serverconns), and a place
355 * to put the returned client structure that we'll use in all of our rpc
356 * calls (via ubik_Call) */
358 code = ubik_ClientInit(serverconns, conn);
367 CheckTicketAnswer(ka_BBS * oanswer, afs_int32 challenge,
368 struct ktc_token *token, struct ktc_principal *caller,
369 struct ktc_principal *server, char *label,
370 afs_int32 * pwexpires)
372 struct ka_ticketAnswer *answer;
376 answer = (struct ka_ticketAnswer *)oanswer->SeqBody;
378 cksum = ntohl(answer->cksum);
379 if (challenge != ntohl(answer->challenge))
380 return KABADPROTOCOL;
381 memcpy(&token->sessionKey, &answer->sessionKey,
382 sizeof(token->sessionKey));
383 token->startTime = ntohl(answer->startTime);
384 token->endTime = ntohl(answer->endTime);
385 token->kvno = (short)ntohl(answer->kvno);
386 token->ticketLen = ntohl(answer->ticketLen);
388 if (tkt_CheckTimes(token->startTime, token->endTime, time(0)) < 0)
389 return KABADPROTOCOL;
390 if ((token->ticketLen < MINKTCTICKETLEN)
391 || (token->ticketLen > MAXKTCTICKETLEN))
392 return KABADPROTOCOL;
395 char *strings = answer->name;
398 #define chkstr(field) \
399 len = strlen (strings); \
400 if (len > MAXKTCNAMELEN) return KABADPROTOCOL;\
401 if ((field) && strcmp (field, strings)) return KABADPROTOCOL;\
405 chkstr(caller->name);
406 chkstr(caller->instance);
407 chkstr(caller->cell);
414 chkstr(server->name);
415 chkstr(server->instance);
421 if (oanswer->SeqLen -
422 ((strings - oanswer->SeqBody) + token->ticketLen + KA_LABELSIZE)
423 >= (ENCRYPTIONBLOCKSIZE + 12)
425 return KABADPROTOCOL;
427 memcpy(token->ticket, strings, token->ticketLen);
428 strings += token->ticketLen;
429 if (memcmp(strings, label, KA_LABELSIZE) != 0)
430 return KABADPROTOCOL;
434 strings += KA_LABELSIZE;
435 temp = round_up_to_ebs((strings - oanswer->SeqBody));
437 if (oanswer->SeqLen > temp) {
438 strings = oanswer->SeqBody + temp;
439 memcpy(&temp, strings, sizeof(afs_int32));
440 tempc = ntohl(temp) >> 24;
441 /* don't forget this if you add any more fields!
442 * strings += sizeof(afs_int32);
454 /* call this instead of stub and we'll guarantee to find a host that's up.
455 * this doesn't handle UNOTSYNC very well, should use ubik_Call if you care
458 kawrap_ubik_Call(aproc, aclient, aflags, p1, p2, p3, p4, p5, p6, p7, p8)
459 struct ubik_client *aclient;
462 void *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
464 afs_int32 code, lcode;
468 /* First pass only checks servers known running. Second checks all.
469 * Once we've cycled through all the servers and still nothing, return
470 * error code from the last server tried.
472 for (pass = 0, aflags |= UPUBIKONLY; pass < 2;
473 pass++, aflags &= ~UPUBIKONLY) {
476 do { /* Cycle through the servers */
479 ubik_CallIter(aproc, aclient, aflags, &count, (long) p1,
480 (long) p2, (long) p3, (long) p4,
481 (long) p5, (long) p6, (long) p7,
482 (long) p8, 0, 0, 0, 0, 0, 0, 0, 0);
483 } while ((code == UNOQUORUM) || (code == UNOTSYNC)
484 || (code == KALOCKED) || (code == -1));
486 if (code != UNOSERVERS)
490 /* If cycled through all the servers, return the last error code */
491 if ((code == UNOSERVERS) && lcode) {
497 /* This is the interface to the AuthServer RPC routine Authenticate. It
498 formats the request packet, calls the encryption routine on the answer,
499 calls Authenticate, and decrypts the response. The response is checked for
500 correctness and its contents are copied into the token. */
503 KABADKEY = the key failed when converted to a key schedule. Probably bad
505 KAUBIKCALL - the call to Ubik returned an error, probably a communication
506 failure such as timeout.
507 KABADPROTOCOL - the returned packet was in error. Since a packet was
508 returned it can be presumed that the AuthServer correctly interpreted
509 the response. This may indicate an inauthentic AuthServer.
510 <other> - errors generated by the server process are returned directly.
514 ka_Authenticate(char *name, char *instance, char *cell, struct ubik_client * conn, /* Ubik connection to the AuthServer in
515 * the desired cell */
516 int service, /* ticket granting or admin service */
517 struct ktc_encryptionKey * key, Date start, Date end, /* ticket lifetime */
518 struct ktc_token * token, afs_int32 * pwexpires)
519 { /* days until it expires */
521 des_key_schedule schedule;
523 struct ka_gettgtRequest request;
524 struct ka_gettgtAnswer answer_old;
525 struct ka_ticketAnswer answer;
533 if ((code = des_key_sched(key, schedule))) {
538 if (service == KA_MAINTENANCE_SERVICE) {
539 req_label = KA_GETADM_REQ_LABEL;
540 ans_label = KA_GETADM_ANS_LABEL;
541 } else if (service == KA_TICKET_GRANTING_SERVICE) {
542 req_label = KA_GETTGT_REQ_LABEL;
543 ans_label = KA_GETTGT_ANS_LABEL;
546 return KABADARGUMENT;
549 request_time = time(0);
550 request.time = htonl(request_time);
551 memcpy(request.label, req_label, sizeof(request.label));
552 arequest.SeqLen = sizeof(request);
553 arequest.SeqBody = (char *)&request;
554 des_pcbc_encrypt(arequest.SeqBody, arequest.SeqBody, arequest.SeqLen,
555 schedule, key, ENCRYPT);
557 oanswer.MaxSeqLen = sizeof(answer);
559 oanswer.SeqBody = (char *)&answer;
563 kawrap_ubik_Call(KAA_AuthenticateV2, conn, 0, name, instance, start,
564 end, &arequest, &oanswer);
565 if (code == RXGEN_OPCODE) {
566 oanswer.MaxSeqLen = sizeof(answer);
567 oanswer.SeqBody = (char *)&answer;
570 ubik_Call(KAA_Authenticate, conn, 0, name, instance, start, end,
571 &arequest, &oanswer);
572 if (code == RXGEN_OPCODE) {
573 extern int KAA_Authenticate_old();
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, 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(&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 extern int KAT_GetTicket_old();
691 oanswer.SeqLen = 0; /* this may be set by first call */
692 oanswer.MaxSeqLen = sizeof(answer_old);
693 oanswer.SeqBody = (char *)&answer_old;
696 ubik_Call(KAT_GetTicket_old, conn, 0, auth_token->kvno,
697 auth_domain, &aticket, name, instance, &atimes,
699 if (code == RXGEN_OPCODE) {
700 code = KAOLDINTERFACE;
705 if ((code >= KAMINERROR) && (code <= KAMAXERROR))
710 des_pcbc_encrypt(oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen,
711 schedule, &auth_token->sessionKey, DECRYPT);
716 struct ktc_principal server;
717 strcpy(server.name, name);
718 strcpy(server.instance, instance);
720 CheckTicketAnswer(&oanswer, 0, token, 0, &server,
721 KA_GETTICKET_ANS_LABEL, &pwexpires);
729 token->startTime = ntohl(answer_old.startTime);
730 token->endTime = ntohl(answer_old.endTime);
731 token->ticketLen = ntohl(answer_old.ticketLen);
732 token->kvno = ntohl(answer_old.kvno);
733 memcpy(&token->sessionKey, &answer_old.sessionKey,
734 sizeof(token->sessionKey));
736 if (tkt_CheckTimes(token->startTime, token->endTime, time(0)) < 0) {
738 return KABADPROTOCOL;
740 if ((token->ticketLen < MINKTCTICKETLEN)
741 || (token->ticketLen > MAXKTCTICKETLEN)) {
743 return KABADPROTOCOL;
745 strings = answer_old.name;
746 len = strlen(strings); /* check client name */
747 if ((len < 1) || (len > MAXKTCNAMELEN)) {
749 return KABADPROTOCOL;
751 strings += len + 1; /* check client instance */
752 len = strlen(strings);
753 if ((len < 0) || (len > MAXKTCNAMELEN)) {
755 return KABADPROTOCOL;
758 len = strlen(strings); /* check client cell */
759 if ((len < 0) || (len > MAXKTCNAMELEN)) {
761 return KABADPROTOCOL;
764 len = strlen(strings); /* check server name */
765 if ((len < 1) || (len > MAXKTCNAMELEN) || strcmp(name, strings)) {
767 return KABADPROTOCOL;
770 len = strlen(strings); /* check server instance */
771 if ((len < 0) || (len > MAXKTCNAMELEN) || strcmp(instance, strings)) {
773 return KABADPROTOCOL;
777 if ((strings - oanswer.SeqBody + token->ticketLen) - oanswer.SeqLen >=
778 ENCRYPTIONBLOCKSIZE) {
780 return KABADPROTOCOL;
782 memcpy(token->ticket, strings, token->ticketLen);
787 return KAINTERNALERROR;
795 ka_ChangePassword(char *name, char *instance, struct ubik_client * conn, /* Ubik connection to the AuthServer in
796 * the desired cell */
797 struct ktc_encryptionKey * oldkey,
798 struct ktc_encryptionKey * newkey)
803 #if defined(AFS_S390_LINUX20_ENV) && !defined(AFS_S390X_LINUX20_ENV)
805 ubik_Call_New(KAM_SetPassword, conn, 0, name, instance, 0, 0,
809 ubik_Call_New(KAM_SetPassword, conn, 0, name, instance, 0, *newkey);