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);
153 ka_GetSecurity(int service, struct ktc_token * token,
154 struct rx_securityClass ** scP, int *siP)
155 { /* security class index */
159 case KA_AUTHENTICATION_SERVICE:
160 case KA_TICKET_GRANTING_SERVICE:
162 *scP = rxnull_NewClientSecurityObject();
163 *siP = RX_SCINDEX_NULL;
165 case KA_MAINTENANCE_SERVICE:
169 rxkad_NewClientSecurityObject(rxkad_crypt, &token->sessionKey,
170 token->kvno, token->ticketLen,
172 *siP = RX_SCINDEX_KAD;
176 return KABADARGUMENT;
179 printf("Failed gettting security object\n");
188 ka_SingleServerConn(char *cell, char *server, /* name of server to contact */
189 int service, struct ktc_token * token,
190 struct ubik_client ** conn)
193 struct rx_connection *serverconns[2];
194 struct rx_securityClass *sc;
195 int si; /* security class index */
196 struct afsconf_cell cellinfo; /* for cell auth server list */
199 char sname[MAXHOSTCHARS];
203 code = ka_GetServers(cell, &cellinfo);
209 lcstring(sname, server, sizeof(sname));
210 snamel = strlen(sname);
212 for (i = 0; i < cellinfo.numServers; i++) {
213 if (strncmp(cellinfo.hostName[i], sname, snamel) == 0) {
232 code = ka_GetSecurity(service, token, &sc, &si);
237 #ifdef AFS_PTHREAD_ENV
239 rx_GetCachedConnection(cellinfo.hostAddr[match].sin_addr.s_addr,
240 cellinfo.hostAddr[match].sin_port, service, sc,
244 rx_NewConnection(cellinfo.hostAddr[match].sin_addr.s_addr,
245 cellinfo.hostAddr[match].sin_port, service, sc, si);
247 serverconns[1] = 0; /* terminate list */
249 /* next, pass list of server rx_connections (in serverconns), and a place
250 * to put the returned client structure that we'll use in all of our rpc
251 * calls (via ubik_Call) */
253 code = ubik_ClientInit(serverconns, conn);
262 ka_AuthSpecificServersConn(int service, struct ktc_token * token,
263 struct afsconf_cell * cellinfo,
264 struct ubik_client ** conn)
267 struct rx_connection *serverconns[MAXSERVERS];
268 struct rx_securityClass *sc;
269 int si; /* security class index */
279 code = ka_GetSecurity(service, token, &sc, &si);
285 for (i = 0; i < cellinfo->numServers; i++)
286 #ifdef AFS_PTHREAD_ENV
288 rx_GetCachedConnection(cellinfo->hostAddr[i].sin_addr.s_addr,
289 cellinfo->hostAddr[i].sin_port, service,
293 rx_NewConnection(cellinfo->hostAddr[i].sin_addr.s_addr,
294 cellinfo->hostAddr[i].sin_port, service, sc, si);
296 serverconns[cellinfo->numServers] = 0; /* terminate list */
298 /* next, pass list of server rx_connections (in serverconns), and a place
299 * to put the returned client structure that we'll use in all of our rpc
300 * calls (via ubik_Call) */
302 code = ubik_ClientInit(serverconns, conn);
311 ka_AuthServerConn(char *cell, int service, struct ktc_token * token,
312 struct ubik_client ** conn)
315 struct rx_connection *serverconns[MAXSERVERS];
316 struct rx_securityClass *sc;
317 int si; /* security class index */
319 struct afsconf_cell cellinfo; /* for cell auth server list */
322 code = ka_GetServers(cell, &cellinfo);
334 code = ka_GetSecurity(service, token, &sc, &si);
340 for (i = 0; i < cellinfo.numServers; i++)
341 #ifdef AFS_PTHREAD_ENV
343 rx_GetCachedConnection(cellinfo.hostAddr[i].sin_addr.s_addr,
344 cellinfo.hostAddr[i].sin_port, service, sc,
348 rx_NewConnection(cellinfo.hostAddr[i].sin_addr.s_addr,
349 cellinfo.hostAddr[i].sin_port, service, sc, si);
351 serverconns[cellinfo.numServers] = 0; /* terminate list */
353 /* next, pass list of server rx_connections (in serverconns), and a place
354 * to put the returned client structure that we'll use in all of our rpc
355 * calls (via ubik_Call) */
357 code = ubik_ClientInit(serverconns, conn);
366 CheckTicketAnswer(ka_BBS * oanswer, afs_int32 challenge,
367 struct ktc_token *token, struct ktc_principal *caller,
368 struct ktc_principal *server, char *label,
369 afs_int32 * pwexpires)
371 struct ka_ticketAnswer *answer;
375 answer = (struct ka_ticketAnswer *)oanswer->SeqBody;
377 cksum = ntohl(answer->cksum);
378 if (challenge != ntohl(answer->challenge))
379 return KABADPROTOCOL;
380 memcpy(&token->sessionKey, &answer->sessionKey,
381 sizeof(token->sessionKey));
382 token->startTime = ntohl(answer->startTime);
383 token->endTime = ntohl(answer->endTime);
384 token->kvno = (short)ntohl(answer->kvno);
385 token->ticketLen = ntohl(answer->ticketLen);
387 if (tkt_CheckTimes(token->startTime, token->endTime, time(0)) < 0)
388 return KABADPROTOCOL;
389 if ((token->ticketLen < MINKTCTICKETLEN)
390 || (token->ticketLen > MAXKTCTICKETLEN))
391 return KABADPROTOCOL;
394 char *strings = answer->name;
397 #define chkstr(field) \
398 len = strlen (strings); \
399 if (len > MAXKTCNAMELEN) return KABADPROTOCOL;\
400 if ((field) && strcmp (field, strings)) return KABADPROTOCOL;\
404 chkstr(caller->name);
405 chkstr(caller->instance);
406 chkstr(caller->cell);
413 chkstr(server->name);
414 chkstr(server->instance);
420 if (oanswer->SeqLen -
421 ((strings - oanswer->SeqBody) + token->ticketLen + KA_LABELSIZE)
422 >= (ENCRYPTIONBLOCKSIZE + 12)
424 return KABADPROTOCOL;
426 memcpy(token->ticket, strings, token->ticketLen);
427 strings += token->ticketLen;
428 if (memcmp(strings, label, KA_LABELSIZE) != 0)
429 return KABADPROTOCOL;
433 strings += KA_LABELSIZE;
434 temp = round_up_to_ebs((strings - oanswer->SeqBody));
436 if (oanswer->SeqLen > temp) {
437 strings = oanswer->SeqBody + temp;
438 memcpy(&temp, strings, sizeof(afs_int32));
439 tempc = ntohl(temp) >> 24;
440 /* don't forget this if you add any more fields!
441 * strings += sizeof(afs_int32);
453 /* call this instead of stub and we'll guarantee to find a host that's up.
454 * this doesn't handle UNOTSYNC very well, should use ubik_Call if you care
457 kawrap_ubik_Call(aproc, aclient, aflags, p1, p2, p3, p4, p5, p6, p7, p8)
458 struct ubik_client *aclient;
461 void *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
463 afs_int32 code, lcode;
467 /* First pass only checks servers known running. Second checks all.
468 * Once we've cycled through all the servers and still nothing, return
469 * error code from the last server tried.
471 for (pass = 0, aflags |= UPUBIKONLY; pass < 2;
472 pass++, aflags &= ~UPUBIKONLY) {
475 do { /* Cycle through the servers */
478 ubik_CallIter(aproc, aclient, aflags, &count, (long) p1,
479 (long) p2, (long) p3, (long) p4,
480 (long) p5, (long) p6, (long) p7,
481 (long) p8, 0, 0, 0, 0, 0, 0, 0, 0);
482 } while ((code == UNOQUORUM) || (code == UNOTSYNC)
483 || (code == KALOCKED) || (code == -1));
485 if (code != UNOSERVERS)
489 /* If cycled through all the servers, return the last error code */
490 if ((code == UNOSERVERS) && lcode) {
496 /* This is the interface to the AuthServer RPC routine Authenticate. It
497 formats the request packet, calls the encryption routine on the answer,
498 calls Authenticate, and decrypts the response. The response is checked for
499 correctness and its contents are copied into the token. */
502 KABADKEY = the key failed when converted to a key schedule. Probably bad
504 KAUBIKCALL - the call to Ubik returned an error, probably a communication
505 failure such as timeout.
506 KABADPROTOCOL - the returned packet was in error. Since a packet was
507 returned it can be presumed that the AuthServer correctly interpreted
508 the response. This may indicate an inauthentic AuthServer.
509 <other> - errors generated by the server process are returned directly.
513 ka_Authenticate(char *name, char *instance, char *cell, struct ubik_client * conn, /* Ubik connection to the AuthServer in
514 * the desired cell */
515 int service, /* ticket granting or admin service */
516 struct ktc_encryptionKey * key, Date start, Date end, /* ticket lifetime */
517 struct ktc_token * token, afs_int32 * pwexpires)
518 { /* days until it expires */
520 des_key_schedule schedule;
522 struct ka_gettgtRequest request;
523 struct ka_gettgtAnswer answer_old;
524 struct ka_ticketAnswer answer;
532 if ((code = des_key_sched(key, schedule))) {
537 if (service == KA_MAINTENANCE_SERVICE) {
538 req_label = KA_GETADM_REQ_LABEL;
539 ans_label = KA_GETADM_ANS_LABEL;
540 } else if (service == KA_TICKET_GRANTING_SERVICE) {
541 req_label = KA_GETTGT_REQ_LABEL;
542 ans_label = KA_GETTGT_ANS_LABEL;
545 return KABADARGUMENT;
548 request_time = time(0);
549 request.time = htonl(request_time);
550 memcpy(request.label, req_label, sizeof(request.label));
551 arequest.SeqLen = sizeof(request);
552 arequest.SeqBody = (char *)&request;
553 des_pcbc_encrypt(arequest.SeqBody, arequest.SeqBody, arequest.SeqLen,
554 schedule, key, ENCRYPT);
556 oanswer.MaxSeqLen = sizeof(answer);
558 oanswer.SeqBody = (char *)&answer;
562 kawrap_ubik_Call(KAA_AuthenticateV2, conn, 0, name, instance, start,
563 end, &arequest, &oanswer);
564 if (code == RXGEN_OPCODE) {
565 oanswer.MaxSeqLen = sizeof(answer);
566 oanswer.SeqBody = (char *)&answer;
569 ubik_Call(KAA_Authenticate, conn, 0, name, instance, start, end,
570 &arequest, &oanswer);
571 if (code == RXGEN_OPCODE) {
572 extern int KAA_Authenticate_old();
573 oanswer.MaxSeqLen = sizeof(answer_old);
574 oanswer.SeqBody = (char *)&answer_old;
577 ubik_Call(KAA_Authenticate_old, conn, 0, name, instance,
578 start, end, &arequest, &oanswer);
580 if (code == RXGEN_OPCODE) {
581 code = KAOLDINTERFACE;
586 if ((code >= KAMINERROR) && (code <= KAMAXERROR))
590 des_pcbc_encrypt(oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen,
591 schedule, key, DECRYPT);
597 struct ktc_principal caller;
598 strcpy(caller.name, name);
599 strcpy(caller.instance, instance);
600 strcpy(caller.cell, "");
602 CheckTicketAnswer(&oanswer, request_time + 1, token, &caller,
603 0, ans_label, pwexpires);
611 answer_old.time = ntohl(answer_old.time);
612 answer_old.ticket_len = ntohl(answer_old.ticket_len);
613 if ((answer_old.time != request_time + 1)
614 || (answer_old.ticket_len < MINKTCTICKETLEN)
615 || (answer_old.ticket_len > MAXKTCTICKETLEN)) {
617 return KABADPROTOCOL;
620 char *label = ((char *)answer_old.ticket) + answer_old.ticket_len;
622 if (strncmp(label, ans_label, sizeof(answer_old.label))) {
624 return KABADPROTOCOL;
626 token->startTime = start;
627 token->endTime = end;
628 token->kvno = ntohl(answer_old.kvno);
629 token->ticketLen = answer_old.ticket_len;
630 memcpy(token->ticket, answer_old.ticket, sizeof(token->ticket));
631 memcpy(&token->sessionKey, &answer_old.sessionkey,
632 sizeof(struct ktc_encryptionKey));
637 return KAINTERNALERROR;
645 ka_GetToken(char *name, char *instance, char *cell, char *cname, char *cinst, struct ubik_client * conn, /* Ubik conn to cell's AuthServer */
646 Date start, Date end, /* desired ticket lifetime */
647 struct ktc_token * auth_token, char *auth_domain,
648 struct ktc_token * token)
650 struct ka_getTicketTimes times;
651 struct ka_getTicketAnswer answer_old;
652 struct ka_ticketAnswer answer;
659 des_key_schedule schedule;
664 aticket.SeqLen = auth_token->ticketLen;
665 aticket.SeqBody = auth_token->ticket;
667 code = des_key_sched(&auth_token->sessionKey, schedule);
673 times.start = htonl(start);
674 times.end = htonl(end);
675 des_ecb_encrypt(×, ×, schedule, ENCRYPT);
677 atimes.SeqLen = sizeof(times);
678 atimes.SeqBody = (char *)×
681 oanswer.MaxSeqLen = sizeof(answer);
682 oanswer.SeqBody = (char *)&answer;
686 ubik_Call(KAT_GetTicket, conn, 0, auth_token->kvno, auth_domain,
687 &aticket, name, instance, &atimes, &oanswer);
688 if (code == RXGEN_OPCODE) {
689 extern int KAT_GetTicket_old();
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, &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);