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>
56 #include <afs/cellconfig.h>
60 #include <afs/afsutil.h>
63 #endif /* defined(UKERNEL) */
66 static struct afsconf_dir *conf = 0;
67 static struct afsconf_cell explicit_cell_server_list;
68 static struct afsconf_cell debug_cell_server_list;
69 static int explicit = 0;
72 #define ENCRYPTIONBLOCKSIZE (sizeof(des_cblock))
74 /* Copy the specified list of servers into a specially know cell named
75 "explicit". The cell can then be used to debug experimental servers. */
77 void ka_ExplicitCell (
79 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);
100 static int myCellLookup (
101 struct afsconf_dir *conf,
104 struct afsconf_cell *cellinfo)
107 *cellinfo = debug_cell_server_list;
110 else if (explicit && (strcmp(cell, explicit_cell_server_list.name) == 0)) {
111 *cellinfo = explicit_cell_server_list;
114 /* call the real one */
115 else return afsconf_GetCellInfo (conf, cell, service, cellinfo);
118 afs_int32 ka_GetServers (
120 struct afsconf_cell *cellinfo)
123 char cellname[MAXKTCREALMLEN];
126 if (cell && !strlen(cell)) cell = 0;
127 else cell = lcstring (cellname, cell, sizeof(cellname));
133 conf = afsconf_Open (AFSDIR_CLIENT_ETC_DIRPATH);
140 code = myCellLookup (conf, cell, AFSCONF_KAUTHSERVICE, cellinfo);
145 afs_int32 ka_GetSecurity (
147 struct ktc_token *token,
148 struct rx_securityClass **scP,
149 int *siP) /* security class index */
154 case KA_AUTHENTICATION_SERVICE:
155 case KA_TICKET_GRANTING_SERVICE:
157 *scP = (struct rx_securityClass *) rxnull_NewClientSecurityObject();
158 *siP = RX_SCINDEX_NULL;
160 case KA_MAINTENANCE_SERVICE:
161 if (!token) goto no_security;
162 *scP = rxkad_NewClientSecurityObject
163 (rxkad_crypt, &token->sessionKey, token->kvno,
164 token->ticketLen, token->ticket);
165 *siP = RX_SCINDEX_KAD;
169 return KABADARGUMENT;
172 printf ("Failed gettting security object\n");
180 afs_int32 ka_SingleServerConn (
182 char *server, /* name of server to contact */
184 struct ktc_token *token,
185 struct ubik_client **conn)
188 struct rx_connection *serverconns[2];
189 struct rx_securityClass *sc;
190 int si; /* security class index */
191 struct afsconf_cell cellinfo; /* for cell auth server list */
194 char sname[MAXHOSTCHARS];
198 code = ka_GetServers (cell, &cellinfo);
204 lcstring (sname, server, sizeof(sname));
205 snamel = strlen (sname);
207 for (i=0; i<cellinfo.numServers; i++) {
208 if (strncmp (cellinfo.hostName[i], sname, snamel) == 0) {
227 code = ka_GetSecurity (service, token, &sc, &si);
233 #ifdef AFS_PTHREAD_ENV
235 rx_GetCachedConnection (cellinfo.hostAddr[match].sin_addr.s_addr,
236 cellinfo.hostAddr[match].sin_port, service, sc, si);
239 rx_NewConnection (cellinfo.hostAddr[match].sin_addr.s_addr,
240 cellinfo.hostAddr[match].sin_port, service, sc, si);
242 serverconns[1] = 0; /* terminate list */
244 /* next, pass list of server rx_connections (in serverconns), and a place
245 to put the returned client structure that we'll use in all of our rpc
246 calls (via ubik_Call) */
248 code = ubik_ClientInit(serverconns, conn);
251 if (code) return KAUBIKINIT;
255 afs_int32 ka_AuthSpecificServersConn (
257 struct ktc_token *token,
258 struct afsconf_cell *cellinfo,
259 struct ubik_client **conn)
262 struct rx_connection *serverconns[MAXSERVERS];
263 struct rx_securityClass *sc;
264 int si; /* security class index */
274 code = ka_GetSecurity (service, token, &sc, &si);
280 for (i=0; i<cellinfo->numServers; i++)
281 #ifdef AFS_PTHREAD_ENV
283 rx_GetCachedConnection (cellinfo->hostAddr[i].sin_addr.s_addr,
284 cellinfo->hostAddr[i].sin_port, service, sc, si);
287 rx_NewConnection (cellinfo->hostAddr[i].sin_addr.s_addr,
288 cellinfo->hostAddr[i].sin_port, service, sc, si);
290 serverconns[cellinfo->numServers] = 0; /* terminate list */
292 /* next, pass list of server rx_connections (in serverconns), and a place
293 to put the returned client structure that we'll use in all of our rpc
294 calls (via ubik_Call) */
296 code = ubik_ClientInit(serverconns, conn);
299 if (code) return KAUBIKINIT;
303 afs_int32 ka_AuthServerConn (
306 struct ktc_token *token,
307 struct ubik_client **conn)
310 struct rx_connection *serverconns[MAXSERVERS];
311 struct rx_securityClass *sc;
312 int si; /* security class index */
314 struct afsconf_cell cellinfo; /* for cell auth server list */
317 code = ka_GetServers (cell, &cellinfo);
329 code = ka_GetSecurity (service, token, &sc, &si);
335 for (i=0; i<cellinfo.numServers; i++)
336 #ifdef AFS_PTHREAD_ENV
338 rx_GetCachedConnection (cellinfo.hostAddr[i].sin_addr.s_addr,
339 cellinfo.hostAddr[i].sin_port, service, sc, si);
342 rx_NewConnection (cellinfo.hostAddr[i].sin_addr.s_addr,
343 cellinfo.hostAddr[i].sin_port, service, sc, si);
345 serverconns[cellinfo.numServers] = 0; /* terminate list */
347 /* next, pass list of server rx_connections (in serverconns), and a place
348 to put the returned client structure that we'll use in all of our rpc
349 calls (via ubik_Call) */
351 code = ubik_ClientInit(serverconns, conn);
354 if (code) return KAUBIKINIT;
358 static afs_int32 CheckTicketAnswer(
361 struct ktc_token *token,
362 struct ktc_principal *caller,
363 struct ktc_principal *server,
365 afs_int32 *pwexpires)
367 struct ka_ticketAnswer *answer;
371 answer = (struct ka_ticketAnswer *)oanswer->SeqBody;
373 cksum = ntohl(answer->cksum);
374 if (challenge != ntohl(answer->challenge)) return KABADPROTOCOL;
375 memcpy(&token->sessionKey, &answer->sessionKey, sizeof(token->sessionKey));
376 token->startTime = ntohl(answer->startTime);
377 token->endTime = ntohl(answer->endTime);
378 token->kvno = (short) ntohl(answer->kvno);
379 token->ticketLen = ntohl(answer->ticketLen);
381 if (tkt_CheckTimes (token->startTime, token->endTime, time(0)) < 0)
382 return KABADPROTOCOL;
383 if ((token->ticketLen < MINKTCTICKETLEN)||(token->ticketLen > MAXKTCTICKETLEN))
384 return KABADPROTOCOL;
386 { char *strings = answer->name;
389 #define chkstr(field) \
390 len = strlen (strings); \
391 if (len > MAXKTCNAMELEN) return KABADPROTOCOL;\
392 if ((field) && strcmp (field, strings)) return KABADPROTOCOL;\
396 chkstr (caller->name);
397 chkstr (caller->instance);
398 chkstr (caller->cell);
399 } else { chkstr (0); chkstr (0); chkstr (0); }
401 chkstr (server->name);
402 chkstr (server->instance);
403 } else { chkstr (0); chkstr (0); }
405 if ( oanswer->SeqLen -
406 ((strings - oanswer->SeqBody) + token->ticketLen + KA_LABELSIZE)
407 >= (ENCRYPTIONBLOCKSIZE + 12)
409 return KABADPROTOCOL;
411 memcpy(token->ticket, strings, token->ticketLen);
412 strings += token->ticketLen;
413 if (memcmp (strings, label, KA_LABELSIZE) != 0) return KABADPROTOCOL;
417 strings += KA_LABELSIZE;
418 temp = round_up_to_ebs((strings - oanswer->SeqBody));
420 if (oanswer->SeqLen > temp) {
421 strings = oanswer->SeqBody + temp;
422 memcpy(&temp, strings, sizeof(afs_int32));
423 tempc = ntohl(temp) >> 24;
424 /* don't forget this if you add any more fields!
425 strings += sizeof(afs_int32);
438 /* call this instead of stub and we'll guarantee to find a host that's up.
439 * this doesn't handle UNOTSYNC very well, should use ubik_Call if you care
442 kawrap_ubik_Call(aproc, aclient, aflags, p1, p2, p3, p4, p5, p6, p7, p8)
443 struct ubik_client *aclient;
446 void *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
448 afs_int32 code, lcode;
452 /* First pass only checks servers known running. Second checks all.
453 * Once we've cycled through all the servers and still nothing, return
454 * error code from the last server tried.
456 for (pass=0, aflags |= UPUBIKONLY; pass<2; pass++, aflags &= ~UPUBIKONLY) {
459 do { /* Cycle through the servers */
461 code = ubik_CallIter (aproc, aclient, aflags, &count, p1,p2,p3,p4,p5,p6,p7,p8);
462 } while ((code == UNOQUORUM) || (code == UNOTSYNC) ||
463 (code == KALOCKED) || (code == -1));
465 if (code != UNOSERVERS) break;
468 /* If cycled through all the servers, return the last error code */
469 if ((code == UNOSERVERS) && lcode) {
475 /* This is the interface to the AuthServer RPC routine Authenticate. It
476 formats the request packet, calls the encryption routine on the answer,
477 calls Authenticate, and decrypts the response. The response is checked for
478 correctness and its contents are copied into the token. */
481 KABADKEY = the key failed when converted to a key schedule. Probably bad
483 KAUBIKCALL - the call to Ubik returned an error, probably a communication
484 failure such as timeout.
485 KABADPROTOCOL - the returned packet was in error. Since a packet was
486 returned it can be presumed that the AuthServer correctly interpreted
487 the response. This may indicate an inauthentic AuthServer.
488 <other> - errors generated by the server process are returned directly.
491 afs_int32 ka_Authenticate (
495 struct ubik_client *conn, /* Ubik connection to the AuthServer in
497 int service, /* ticket granting or admin service */
498 struct ktc_encryptionKey *key,
500 Date end, /* ticket lifetime */
501 struct ktc_token *token,
502 afs_int32 *pwexpires) /* days until it expires */
505 des_key_schedule schedule;
507 struct ka_gettgtRequest request;
508 struct ka_gettgtAnswer answer_old;
509 struct ka_ticketAnswer answer;
517 if (code = des_key_sched (key, schedule)) {
522 if (service == KA_MAINTENANCE_SERVICE) {
523 req_label = KA_GETADM_REQ_LABEL;
524 ans_label = KA_GETADM_ANS_LABEL;
525 } else if (service == KA_TICKET_GRANTING_SERVICE) {
526 req_label = KA_GETTGT_REQ_LABEL;
527 ans_label = KA_GETTGT_ANS_LABEL;
530 return KABADARGUMENT;
533 request_time = time(0);
534 request.time = htonl(request_time);
535 memcpy(request.label, req_label, sizeof(request.label));
536 arequest.SeqLen = sizeof(request);
537 arequest.SeqBody = (char *)&request;
538 des_pcbc_encrypt (arequest.SeqBody, arequest.SeqBody, arequest.SeqLen,
539 schedule, key, ENCRYPT);
541 oanswer.MaxSeqLen = sizeof(answer);
543 oanswer.SeqBody = (char *)&answer;
546 code = kawrap_ubik_Call (KAA_AuthenticateV2, conn, 0,
547 name, instance, start, end, &arequest, &oanswer);
548 if (code == RXGEN_OPCODE) {
549 extern afs_int32 KAA_Authenticate();
550 oanswer.MaxSeqLen = sizeof(answer);
551 oanswer.SeqBody = (char *)&answer;
553 code = ubik_Call (KAA_Authenticate, conn, 0,
554 name, instance, start, end, &arequest, &oanswer);
555 if (code == RXGEN_OPCODE) {
556 extern int KAA_Authenticate_old();
557 oanswer.MaxSeqLen = sizeof(answer_old);
558 oanswer.SeqBody = (char *)&answer_old;
560 code = ubik_Call (KAA_Authenticate_old, conn, 0,
561 name, instance, start, end, &arequest, &oanswer);
563 if (code == RXGEN_OPCODE) {
564 code = KAOLDINTERFACE;
569 if ((code >= KAMINERROR) && (code <= KAMAXERROR)) return code;
572 des_pcbc_encrypt (oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen,
573 schedule, key, DECRYPT);
578 { struct ktc_principal caller;
579 strcpy (caller.name, name);
580 strcpy (caller.instance, instance);
581 strcpy (caller.cell, "");
582 code = CheckTicketAnswer (&oanswer, request_time+1, token,
583 &caller, 0, ans_label, pwexpires);
591 answer_old.time = ntohl(answer_old.time);
592 answer_old.ticket_len = ntohl(answer_old.ticket_len);
593 if ((answer_old.time != request_time+1) ||
594 (answer_old.ticket_len < MINKTCTICKETLEN) ||
595 (answer_old.ticket_len > MAXKTCTICKETLEN)) {
597 return KABADPROTOCOL;
599 { char *label = ((char *)answer_old.ticket)+answer_old.ticket_len;
601 if (strncmp(label, ans_label, sizeof(answer_old.label))) {
603 return KABADPROTOCOL;
605 token->startTime = start;
606 token->endTime = end;
607 token->kvno = ntohl(answer_old.kvno);
608 token->ticketLen = answer_old.ticket_len;
609 memcpy(token->ticket, answer_old.ticket, sizeof(token->ticket));
610 memcpy(&token->sessionKey, &answer_old.sessionkey, sizeof(struct ktc_encryptionKey));
615 return KAINTERNALERROR;
622 afs_int32 ka_GetToken (
628 struct ubik_client *conn, /* Ubik conn to cell's AuthServer */
630 Date end, /* desired ticket lifetime */
631 struct ktc_token *auth_token,
633 struct ktc_token *token)
635 struct ka_getTicketTimes times;
636 struct ka_getTicketAnswer answer_old;
637 struct ka_ticketAnswer answer;
644 des_key_schedule schedule;
649 aticket.SeqLen = auth_token->ticketLen;
650 aticket.SeqBody = auth_token->ticket;
652 code = des_key_sched (&auth_token->sessionKey, schedule);
658 times.start = htonl(start);
659 times.end = htonl(end);
660 des_ecb_encrypt (×, ×, schedule, ENCRYPT);
662 atimes.SeqLen = sizeof(times);
663 atimes.SeqBody = (char *)×
666 oanswer.MaxSeqLen = sizeof(answer);
667 oanswer.SeqBody = (char *)&answer;
670 code = ubik_Call (KAT_GetTicket, conn, 0,
671 auth_token->kvno, auth_domain, &aticket,
672 name, instance, &atimes, &oanswer);
673 if (code == RXGEN_OPCODE) {
674 extern int KAT_GetTicket_old ();
675 oanswer.SeqLen = 0; /* this may be set by first call */
676 oanswer.MaxSeqLen = sizeof(answer_old);
677 oanswer.SeqBody = (char *)&answer_old;
679 code = ubik_Call (KAT_GetTicket_old, conn, 0,
680 auth_token->kvno, auth_domain, &aticket,
681 name, instance, &atimes, &oanswer);
682 if (code == RXGEN_OPCODE) {
683 code = KAOLDINTERFACE;
688 if ((code >= KAMINERROR) && (code <= KAMAXERROR)) return code;
692 des_pcbc_encrypt (oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen,
693 schedule, &auth_token->sessionKey, DECRYPT);
697 { struct ktc_principal server;
698 strcpy (server.name, name);
699 strcpy (server.instance, instance);
700 code = CheckTicketAnswer (&oanswer, 0, token, 0, &server,
701 KA_GETTICKET_ANS_LABEL, &pwexpires);
709 token->startTime = ntohl(answer_old.startTime);
710 token->endTime = ntohl(answer_old.endTime);
711 token->ticketLen = ntohl(answer_old.ticketLen);
712 token->kvno = ntohl(answer_old.kvno);
713 memcpy(&token->sessionKey, &answer_old.sessionKey, sizeof(token->sessionKey));
715 if (tkt_CheckTimes (token->startTime, token->endTime, time(0)) < 0) {
717 return KABADPROTOCOL;
719 if ((token->ticketLen < MINKTCTICKETLEN) ||
720 (token->ticketLen > MAXKTCTICKETLEN)) {
722 return KABADPROTOCOL;
724 strings = answer_old.name;
725 len = strlen(strings); /* check client name */
726 if ((len < 1) || (len > MAXKTCNAMELEN)) {
728 return KABADPROTOCOL;
730 strings += len+1; /* check client instance */
731 len = strlen(strings);
732 if ((len < 0) || (len > MAXKTCNAMELEN)) {
734 return KABADPROTOCOL;
737 len = strlen(strings); /* check client cell */
738 if ((len < 0) || (len > MAXKTCNAMELEN)) {
740 return KABADPROTOCOL;
743 len = strlen(strings); /* check server name */
744 if ((len < 1) || (len > MAXKTCNAMELEN) ||
745 strcmp (name, strings)) {
747 return KABADPROTOCOL;
750 len = strlen(strings); /* check server instance */
751 if ((len < 0) || (len > MAXKTCNAMELEN) ||
752 strcmp (instance, strings)) {
754 return KABADPROTOCOL;
758 if ((strings - oanswer.SeqBody + token->ticketLen) - oanswer.SeqLen >=
759 ENCRYPTIONBLOCKSIZE) {
761 return KABADPROTOCOL;
763 memcpy(token->ticket, strings, token->ticketLen);
768 return KAINTERNALERROR;
775 afs_int32 ka_ChangePassword (
778 struct ubik_client *conn, /* Ubik connection to the AuthServer in
780 struct ktc_encryptionKey *oldkey,
781 struct ktc_encryptionKey *newkey)
786 #ifdef AFS_S390_LINUX20_ENV
787 code = ubik_Call_New (KAM_SetPassword, conn, 0, name,
788 instance, 0, 0, *newkey);
790 code = ubik_Call_New (KAM_SetPassword, conn, 0, name,
791 instance, 0, *newkey);