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>
22 #include "../afs/sysincludes.h"
23 #include "../afs/afsincludes.h"
24 #include "../afs/afs_usrops.h"
25 #include "../afs/stds.h"
26 #include "../afs/pthread_glock.h"
27 #include "../rx/rxkad.h"
28 #include "../afs/cellconfig.h"
29 #include "../afs/ubik.h"
30 #include "../afs/auth.h"
31 #include "../des/des.h"
32 #include "../afs/afsutil.h"
34 #include "../afsint/kauth.h"
35 #include "../afs/kautils.h"
36 #include "../afs/pthread_glock.h"
38 #else /* defined(UKERNEL) */
40 #include <afs/pthread_glock.h>
41 #include <sys/types.h>
45 #include <sys/socket.h>
46 #include <netinet/in.h>
49 #include <afs/cellconfig.h>
53 #include <afs/afsutil.h>
56 #endif /* defined(UKERNEL) */
59 static struct afsconf_dir *conf = 0;
60 static struct afsconf_cell explicit_cell_server_list;
61 static struct afsconf_cell debug_cell_server_list;
62 static int explicit = 0;
65 #define ENCRYPTIONBLOCKSIZE (sizeof(des_cblock))
67 /* Copy the specified list of servers into a specially know cell named
68 "explicit". The cell can then be used to debug experimental servers. */
70 void ka_ExplicitCell (
72 afs_int32 serverList[])
77 ka_ExpandCell (cell, explicit_cell_server_list.name, 0);
78 for (i=0; i<MAXHOSTSPERCELL; i++)
80 explicit_cell_server_list.numServers = i+1;
81 explicit_cell_server_list.hostAddr[i].sin_family = AF_INET;
82 explicit_cell_server_list.hostAddr[i].sin_addr.s_addr =
84 explicit_cell_server_list.hostName[i][0] = 0;
85 explicit_cell_server_list.hostAddr[i].sin_port =
86 htons(AFSCONF_KAUTHPORT);
93 static int myCellLookup (
94 struct afsconf_dir *conf,
97 struct afsconf_cell *cellinfo)
100 *cellinfo = debug_cell_server_list;
103 else if (explicit && (strcmp(cell, explicit_cell_server_list.name) == 0)) {
104 *cellinfo = explicit_cell_server_list;
107 /* call the real one */
108 else return afsconf_GetCellInfo (conf, cell, service, cellinfo);
111 afs_int32 ka_GetServers (
113 struct afsconf_cell *cellinfo)
116 char cellname[MAXKTCREALMLEN];
119 if (cell && !strlen(cell)) cell = 0;
120 else cell = lcstring (cellname, cell, sizeof(cellname));
126 conf = afsconf_Open (AFSDIR_CLIENT_ETC_DIRPATH);
133 code = myCellLookup (conf, cell, AFSCONF_KAUTHSERVICE, cellinfo);
138 afs_int32 ka_GetSecurity (
140 struct ktc_token *token,
141 struct rx_securityClass **scP,
142 int *siP) /* security class index */
147 case KA_AUTHENTICATION_SERVICE:
148 case KA_TICKET_GRANTING_SERVICE:
150 *scP = (struct rx_securityClass *) rxnull_NewClientSecurityObject();
151 *siP = RX_SCINDEX_NULL;
153 case KA_MAINTENANCE_SERVICE:
154 if (!token) goto no_security;
155 *scP = rxkad_NewClientSecurityObject
156 (rxkad_crypt, &token->sessionKey, token->kvno,
157 token->ticketLen, token->ticket);
158 *siP = RX_SCINDEX_KAD;
162 return KABADARGUMENT;
165 printf ("Failed gettting security object\n");
173 afs_int32 ka_SingleServerConn (
175 char *server, /* name of server to contact */
177 struct ktc_token *token,
178 struct ubik_client **conn)
181 struct rx_connection *serverconns[2];
182 struct rx_securityClass *sc;
183 int si; /* security class index */
184 struct afsconf_cell cellinfo; /* for cell auth server list */
187 char sname[MAXHOSTCHARS];
191 code = ka_GetServers (cell, &cellinfo);
197 lcstring (sname, server, sizeof(sname));
198 snamel = strlen (sname);
200 for (i=0; i<cellinfo.numServers; i++) {
201 if (strncmp (cellinfo.hostName[i], sname, snamel) == 0) {
220 code = ka_GetSecurity (service, token, &sc, &si);
226 #ifdef AFS_PTHREAD_ENV
228 rx_GetCachedConnection (cellinfo.hostAddr[match].sin_addr.s_addr,
229 cellinfo.hostAddr[match].sin_port, service, sc, si);
232 rx_NewConnection (cellinfo.hostAddr[match].sin_addr.s_addr,
233 cellinfo.hostAddr[match].sin_port, service, sc, si);
235 serverconns[1] = 0; /* terminate list */
237 /* next, pass list of server rx_connections (in serverconns), and a place
238 to put the returned client structure that we'll use in all of our rpc
239 calls (via ubik_Call) */
241 code = ubik_ClientInit(serverconns, conn);
244 if (code) return KAUBIKINIT;
248 afs_int32 ka_AuthSpecificServersConn (
250 struct ktc_token *token,
251 struct afsconf_cell *cellinfo,
252 struct ubik_client **conn)
255 struct rx_connection *serverconns[MAXSERVERS];
256 struct rx_securityClass *sc;
257 int si; /* security class index */
267 code = ka_GetSecurity (service, token, &sc, &si);
273 for (i=0; i<cellinfo->numServers; i++)
274 #ifdef AFS_PTHREAD_ENV
276 rx_GetCachedConnection (cellinfo->hostAddr[i].sin_addr.s_addr,
277 cellinfo->hostAddr[i].sin_port, service, sc, si);
280 rx_NewConnection (cellinfo->hostAddr[i].sin_addr.s_addr,
281 cellinfo->hostAddr[i].sin_port, service, sc, si);
283 serverconns[cellinfo->numServers] = 0; /* terminate list */
285 /* next, pass list of server rx_connections (in serverconns), and a place
286 to put the returned client structure that we'll use in all of our rpc
287 calls (via ubik_Call) */
289 code = ubik_ClientInit(serverconns, conn);
292 if (code) return KAUBIKINIT;
296 afs_int32 ka_AuthServerConn (
299 struct ktc_token *token,
300 struct ubik_client **conn)
303 struct rx_connection *serverconns[MAXSERVERS];
304 struct rx_securityClass *sc;
305 int si; /* security class index */
307 struct afsconf_cell cellinfo; /* for cell auth server list */
310 code = ka_GetServers (cell, &cellinfo);
322 code = ka_GetSecurity (service, token, &sc, &si);
328 for (i=0; i<cellinfo.numServers; i++)
329 #ifdef AFS_PTHREAD_ENV
331 rx_GetCachedConnection (cellinfo.hostAddr[i].sin_addr.s_addr,
332 cellinfo.hostAddr[i].sin_port, service, sc, si);
335 rx_NewConnection (cellinfo.hostAddr[i].sin_addr.s_addr,
336 cellinfo.hostAddr[i].sin_port, service, sc, si);
338 serverconns[cellinfo.numServers] = 0; /* terminate list */
340 /* next, pass list of server rx_connections (in serverconns), and a place
341 to put the returned client structure that we'll use in all of our rpc
342 calls (via ubik_Call) */
344 code = ubik_ClientInit(serverconns, conn);
347 if (code) return KAUBIKINIT;
351 static afs_int32 CheckTicketAnswer(
354 struct ktc_token *token,
355 struct ktc_principal *caller,
356 struct ktc_principal *server,
358 afs_int32 *pwexpires)
360 struct ka_ticketAnswer *answer;
364 answer = (struct ka_ticketAnswer *)oanswer->SeqBody;
366 cksum = ntohl(answer->cksum);
367 if (challenge != ntohl(answer->challenge)) return KABADPROTOCOL;
368 memcpy(&token->sessionKey, &answer->sessionKey, sizeof(token->sessionKey));
369 token->startTime = ntohl(answer->startTime);
370 token->endTime = ntohl(answer->endTime);
371 token->kvno = (short) ntohl(answer->kvno);
372 token->ticketLen = ntohl(answer->ticketLen);
374 if (tkt_CheckTimes (token->startTime, token->endTime, time(0)) < 0)
375 return KABADPROTOCOL;
376 if ((token->ticketLen < MINKTCTICKETLEN)||(token->ticketLen > MAXKTCTICKETLEN))
377 return KABADPROTOCOL;
379 { char *strings = answer->name;
382 #define chkstr(field) \
383 len = strlen (strings); \
384 if (len > MAXKTCNAMELEN) return KABADPROTOCOL;\
385 if ((field) && strcmp (field, strings)) return KABADPROTOCOL;\
389 chkstr (caller->name);
390 chkstr (caller->instance);
391 chkstr (caller->cell);
392 } else { chkstr (0); chkstr (0); chkstr (0); }
394 chkstr (server->name);
395 chkstr (server->instance);
396 } else { chkstr (0); chkstr (0); }
398 if ( oanswer->SeqLen -
399 ((strings - oanswer->SeqBody) + token->ticketLen + KA_LABELSIZE)
400 >= (ENCRYPTIONBLOCKSIZE + 12)
402 return KABADPROTOCOL;
404 memcpy(token->ticket, strings, token->ticketLen);
405 strings += token->ticketLen;
406 if (memcmp (strings, label, KA_LABELSIZE) != 0) return KABADPROTOCOL;
410 strings += KA_LABELSIZE;
411 temp = round_up_to_ebs((strings - oanswer->SeqBody));
413 if (oanswer->SeqLen > temp) {
414 strings = oanswer->SeqBody + temp;
415 memcpy(&temp, strings, sizeof(afs_int32));
416 tempc = ntohl(temp) >> 24;
417 /* don't forget this if you add any more fields!
418 strings += sizeof(afs_int32);
431 /* call this instead of stub and we'll guarantee to find a host that's up.
432 * this doesn't handle UNOTSYNC very well, should use ubik_Call if you care
435 kawrap_ubik_Call(aproc, aclient, aflags, p1, p2, p3, p4, p5, p6, p7, p8)
436 struct ubik_client *aclient;
439 void *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
441 afs_int32 code, lcode;
445 /* First pass only checks servers known running. Second checks all.
446 * Once we've cycled through all the servers and still nothing, return
447 * error code from the last server tried.
449 for (pass=0, aflags |= UPUBIKONLY; pass<2; pass++, aflags &= ~UPUBIKONLY) {
452 do { /* Cycle through the servers */
454 code = ubik_CallIter (aproc, aclient, aflags, &count, p1,p2,p3,p4,p5,p6,p7,p8);
455 } while ((code == UNOQUORUM) || (code == UNOTSYNC) ||
456 (code == KALOCKED) || (code == -1));
458 if (code != UNOSERVERS) break;
461 /* If cycled through all the servers, return the last error code */
462 if ((code == UNOSERVERS) && lcode) {
468 /* This is the interface to the AuthServer RPC routine Authenticate. It
469 formats the request packet, calls the encryption routine on the answer,
470 calls Authenticate, and decrypts the response. The response is checked for
471 correctness and its contents are copied into the token. */
474 KABADKEY = the key failed when converted to a key schedule. Probably bad
476 KAUBIKCALL - the call to Ubik returned an error, probably a communication
477 failure such as timeout.
478 KABADPROTOCOL - the returned packet was in error. Since a packet was
479 returned it can be presumed that the AuthServer correctly interpreted
480 the response. This may indicate an inauthentic AuthServer.
481 <other> - errors generated by the server process are returned directly.
484 afs_int32 ka_Authenticate (
488 struct ubik_client *conn, /* Ubik connection to the AuthServer in
490 int service, /* ticket granting or admin service */
491 struct ktc_encryptionKey *key,
493 Date end, /* ticket lifetime */
494 struct ktc_token *token,
495 afs_int32 *pwexpires) /* days until it expires */
498 des_key_schedule schedule;
500 struct ka_gettgtRequest request;
501 struct ka_gettgtAnswer answer_old;
502 struct ka_ticketAnswer answer;
510 if (code = des_key_sched (key, schedule)) {
515 if (service == KA_MAINTENANCE_SERVICE) {
516 req_label = KA_GETADM_REQ_LABEL;
517 ans_label = KA_GETADM_ANS_LABEL;
518 } else if (service == KA_TICKET_GRANTING_SERVICE) {
519 req_label = KA_GETTGT_REQ_LABEL;
520 ans_label = KA_GETTGT_ANS_LABEL;
523 return KABADARGUMENT;
526 request_time = time(0);
527 request.time = htonl(request_time);
528 memcpy(request.label, req_label, sizeof(request.label));
529 arequest.SeqLen = sizeof(request);
530 arequest.SeqBody = (char *)&request;
531 des_pcbc_encrypt (arequest.SeqBody, arequest.SeqBody, arequest.SeqLen,
532 schedule, key, ENCRYPT);
534 oanswer.MaxSeqLen = sizeof(answer);
536 oanswer.SeqBody = (char *)&answer;
539 code = kawrap_ubik_Call (KAA_AuthenticateV2, conn, 0,
540 name, instance, start, end, &arequest, &oanswer);
541 if (code == RXGEN_OPCODE) {
542 extern afs_int32 KAA_Authenticate();
543 oanswer.MaxSeqLen = sizeof(answer);
544 oanswer.SeqBody = (char *)&answer;
546 code = ubik_Call (KAA_Authenticate, conn, 0,
547 name, instance, start, end, &arequest, &oanswer);
548 if (code == RXGEN_OPCODE) {
549 extern int KAA_Authenticate_old();
550 oanswer.MaxSeqLen = sizeof(answer_old);
551 oanswer.SeqBody = (char *)&answer_old;
553 code = ubik_Call (KAA_Authenticate_old, conn, 0,
554 name, instance, start, end, &arequest, &oanswer);
556 if (code == RXGEN_OPCODE) {
557 code = KAOLDINTERFACE;
562 if ((code >= KAMINERROR) && (code <= KAMAXERROR)) return code;
565 des_pcbc_encrypt (oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen,
566 schedule, key, DECRYPT);
571 { struct ktc_principal caller;
572 strcpy (caller.name, name);
573 strcpy (caller.instance, instance);
574 strcpy (caller.cell, "");
575 code = CheckTicketAnswer (&oanswer, request_time+1, token,
576 &caller, 0, ans_label, pwexpires);
584 answer_old.time = ntohl(answer_old.time);
585 answer_old.ticket_len = ntohl(answer_old.ticket_len);
586 if ((answer_old.time != request_time+1) ||
587 (answer_old.ticket_len < MINKTCTICKETLEN) ||
588 (answer_old.ticket_len > MAXKTCTICKETLEN)) {
590 return KABADPROTOCOL;
592 { char *label = ((char *)answer_old.ticket)+answer_old.ticket_len;
594 if (strncmp(label, ans_label, sizeof(answer_old.label))) {
596 return KABADPROTOCOL;
598 token->startTime = start;
599 token->endTime = end;
600 token->kvno = ntohl(answer_old.kvno);
601 token->ticketLen = answer_old.ticket_len;
602 memcpy(token->ticket, answer_old.ticket, sizeof(token->ticket));
603 memcpy(&token->sessionKey, &answer_old.sessionkey, sizeof(struct ktc_encryptionKey));
608 return KAINTERNALERROR;
615 afs_int32 ka_GetToken (
621 struct ubik_client *conn, /* Ubik conn to cell's AuthServer */
623 Date end, /* desired ticket lifetime */
624 struct ktc_token *auth_token,
626 struct ktc_token *token)
628 struct ka_getTicketTimes times;
629 struct ka_getTicketAnswer answer_old;
630 struct ka_ticketAnswer answer;
637 des_key_schedule schedule;
640 char bob[KA_TIMESTR_LEN];
643 aticket.SeqLen = auth_token->ticketLen;
644 aticket.SeqBody = auth_token->ticket;
646 code = des_key_sched (&auth_token->sessionKey, schedule);
652 times.start = htonl(start);
653 times.end = htonl(end);
654 des_ecb_encrypt (×, ×, schedule, ENCRYPT);
656 atimes.SeqLen = sizeof(times);
657 atimes.SeqBody = (char *)×
660 oanswer.MaxSeqLen = sizeof(answer);
661 oanswer.SeqBody = (char *)&answer;
664 code = ubik_Call (KAT_GetTicket, conn, 0,
665 auth_token->kvno, auth_domain, &aticket,
666 name, instance, &atimes, &oanswer);
667 if (code == RXGEN_OPCODE) {
668 extern int KAT_GetTicket_old ();
669 oanswer.SeqLen = 0; /* this may be set by first call */
670 oanswer.MaxSeqLen = sizeof(answer_old);
671 oanswer.SeqBody = (char *)&answer_old;
673 code = ubik_Call (KAT_GetTicket_old, conn, 0,
674 auth_token->kvno, auth_domain, &aticket,
675 name, instance, &atimes, &oanswer);
676 if (code == RXGEN_OPCODE) {
677 code = KAOLDINTERFACE;
682 if ((code >= KAMINERROR) && (code <= KAMAXERROR)) return code;
686 des_pcbc_encrypt (oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen,
687 schedule, &auth_token->sessionKey, DECRYPT);
691 { struct ktc_principal server;
692 strcpy (server.name, name);
693 strcpy (server.instance, instance);
694 code = CheckTicketAnswer (&oanswer, 0, token, 0, &server,
695 KA_GETTICKET_ANS_LABEL, &pwexpires);
703 token->startTime = ntohl(answer_old.startTime);
704 token->endTime = ntohl(answer_old.endTime);
705 token->ticketLen = ntohl(answer_old.ticketLen);
706 token->kvno = ntohl(answer_old.kvno);
707 memcpy(&token->sessionKey, &answer_old.sessionKey, sizeof(token->sessionKey));
709 if (tkt_CheckTimes (token->startTime, token->endTime, time(0)) < 0) {
711 return KABADPROTOCOL;
713 if ((token->ticketLen < MINKTCTICKETLEN) ||
714 (token->ticketLen > MAXKTCTICKETLEN)) {
716 return KABADPROTOCOL;
718 strings = answer_old.name;
719 len = strlen(strings); /* check client name */
720 if ((len < 1) || (len > MAXKTCNAMELEN)) {
722 return KABADPROTOCOL;
724 strings += len+1; /* check client instance */
725 len = strlen(strings);
726 if ((len < 0) || (len > MAXKTCNAMELEN)) {
728 return KABADPROTOCOL;
731 len = strlen(strings); /* check client cell */
732 if ((len < 0) || (len > MAXKTCNAMELEN)) {
734 return KABADPROTOCOL;
737 len = strlen(strings); /* check server name */
738 if ((len < 1) || (len > MAXKTCNAMELEN) ||
739 strcmp (name, strings)) {
741 return KABADPROTOCOL;
744 len = strlen(strings); /* check server instance */
745 if ((len < 0) || (len > MAXKTCNAMELEN) ||
746 strcmp (instance, strings)) {
748 return KABADPROTOCOL;
752 if ((strings - oanswer.SeqBody + token->ticketLen) - oanswer.SeqLen >=
753 ENCRYPTIONBLOCKSIZE) {
755 return KABADPROTOCOL;
757 memcpy(token->ticket, strings, token->ticketLen);
762 return KAINTERNALERROR;
769 afs_int32 ka_ChangePassword (
772 struct ubik_client *conn, /* Ubik connection to the AuthServer in
774 struct ktc_encryptionKey *oldkey,
775 struct ktc_encryptionKey *newkey)
780 #ifdef AFS_S390_LINUX20_ENV
781 code = ubik_Call_New (KAM_SetPassword, conn, 0, name,
782 instance, 0, 0, *newkey);
784 code = ubik_Call_New (KAM_SetPassword, conn, 0, name,
785 instance, 0, *newkey);