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);
94 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
95 explicit_cell_server_list.hostAddr[i].sin_len =
96 sizeof(struct sockaddr_in);
104 static int myCellLookup (
105 struct afsconf_dir *conf,
108 struct afsconf_cell *cellinfo)
111 *cellinfo = debug_cell_server_list;
114 else if (explicit && (strcmp(cell, explicit_cell_server_list.name) == 0)) {
115 *cellinfo = explicit_cell_server_list;
118 /* call the real one */
119 else return afsconf_GetCellInfo (conf, cell, service, cellinfo);
122 afs_int32 ka_GetServers (
124 struct afsconf_cell *cellinfo)
127 char cellname[MAXKTCREALMLEN];
130 if (cell && !strlen(cell)) cell = 0;
131 else cell = lcstring (cellname, cell, sizeof(cellname));
137 conf = afsconf_Open (AFSDIR_CLIENT_ETC_DIRPATH);
144 code = myCellLookup (conf, cell, AFSCONF_KAUTHSERVICE, cellinfo);
149 afs_int32 ka_GetSecurity (
151 struct ktc_token *token,
152 struct rx_securityClass **scP,
153 int *siP) /* security class index */
158 case KA_AUTHENTICATION_SERVICE:
159 case KA_TICKET_GRANTING_SERVICE:
161 *scP = (struct rx_securityClass *) rxnull_NewClientSecurityObject();
162 *siP = RX_SCINDEX_NULL;
164 case KA_MAINTENANCE_SERVICE:
165 if (!token) goto no_security;
166 *scP = rxkad_NewClientSecurityObject
167 (rxkad_crypt, &token->sessionKey, token->kvno,
168 token->ticketLen, token->ticket);
169 *siP = RX_SCINDEX_KAD;
173 return KABADARGUMENT;
176 printf ("Failed gettting security object\n");
184 afs_int32 ka_SingleServerConn (
186 char *server, /* name of server to contact */
188 struct ktc_token *token,
189 struct ubik_client **conn)
192 struct rx_connection *serverconns[2];
193 struct rx_securityClass *sc;
194 int si; /* security class index */
195 struct afsconf_cell cellinfo; /* for cell auth server list */
198 char sname[MAXHOSTCHARS];
202 code = ka_GetServers (cell, &cellinfo);
208 lcstring (sname, server, sizeof(sname));
209 snamel = strlen (sname);
211 for (i=0; i<cellinfo.numServers; i++) {
212 if (strncmp (cellinfo.hostName[i], sname, snamel) == 0) {
231 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, si);
243 rx_NewConnection (cellinfo.hostAddr[match].sin_addr.s_addr,
244 cellinfo.hostAddr[match].sin_port, service, sc, si);
246 serverconns[1] = 0; /* terminate list */
248 /* next, pass list of server rx_connections (in serverconns), and a place
249 to put the returned client structure that we'll use in all of our rpc
250 calls (via ubik_Call) */
252 code = ubik_ClientInit(serverconns, conn);
255 if (code) return KAUBIKINIT;
259 afs_int32 ka_AuthSpecificServersConn (
261 struct ktc_token *token,
262 struct afsconf_cell *cellinfo,
263 struct ubik_client **conn)
266 struct rx_connection *serverconns[MAXSERVERS];
267 struct rx_securityClass *sc;
268 int si; /* security class index */
278 code = ka_GetSecurity (service, token, &sc, &si);
284 for (i=0; i<cellinfo->numServers; i++)
285 #ifdef AFS_PTHREAD_ENV
287 rx_GetCachedConnection (cellinfo->hostAddr[i].sin_addr.s_addr,
288 cellinfo->hostAddr[i].sin_port, service, sc, si);
291 rx_NewConnection (cellinfo->hostAddr[i].sin_addr.s_addr,
292 cellinfo->hostAddr[i].sin_port, service, sc, si);
294 serverconns[cellinfo->numServers] = 0; /* terminate list */
296 /* next, pass list of server rx_connections (in serverconns), and a place
297 to put the returned client structure that we'll use in all of our rpc
298 calls (via ubik_Call) */
300 code = ubik_ClientInit(serverconns, conn);
303 if (code) return KAUBIKINIT;
307 afs_int32 ka_AuthServerConn (
310 struct ktc_token *token,
311 struct ubik_client **conn)
314 struct rx_connection *serverconns[MAXSERVERS];
315 struct rx_securityClass *sc;
316 int si; /* security class index */
318 struct afsconf_cell cellinfo; /* for cell auth server list */
321 code = ka_GetServers (cell, &cellinfo);
333 code = ka_GetSecurity (service, token, &sc, &si);
339 for (i=0; i<cellinfo.numServers; i++)
340 #ifdef AFS_PTHREAD_ENV
342 rx_GetCachedConnection (cellinfo.hostAddr[i].sin_addr.s_addr,
343 cellinfo.hostAddr[i].sin_port, service, sc, si);
346 rx_NewConnection (cellinfo.hostAddr[i].sin_addr.s_addr,
347 cellinfo.hostAddr[i].sin_port, service, sc, si);
349 serverconns[cellinfo.numServers] = 0; /* terminate list */
351 /* next, pass list of server rx_connections (in serverconns), and a place
352 to put the returned client structure that we'll use in all of our rpc
353 calls (via ubik_Call) */
355 code = ubik_ClientInit(serverconns, conn);
358 if (code) return KAUBIKINIT;
362 static afs_int32 CheckTicketAnswer(
365 struct ktc_token *token,
366 struct ktc_principal *caller,
367 struct ktc_principal *server,
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)) return KABADPROTOCOL;
379 memcpy(&token->sessionKey, &answer->sessionKey, sizeof(token->sessionKey));
380 token->startTime = ntohl(answer->startTime);
381 token->endTime = ntohl(answer->endTime);
382 token->kvno = (short) ntohl(answer->kvno);
383 token->ticketLen = ntohl(answer->ticketLen);
385 if (tkt_CheckTimes (token->startTime, token->endTime, time(0)) < 0)
386 return KABADPROTOCOL;
387 if ((token->ticketLen < MINKTCTICKETLEN)||(token->ticketLen > MAXKTCTICKETLEN))
388 return KABADPROTOCOL;
390 { char *strings = answer->name;
393 #define chkstr(field) \
394 len = strlen (strings); \
395 if (len > MAXKTCNAMELEN) return KABADPROTOCOL;\
396 if ((field) && strcmp (field, strings)) return KABADPROTOCOL;\
400 chkstr (caller->name);
401 chkstr (caller->instance);
402 chkstr (caller->cell);
403 } else { chkstr (0); chkstr (0); chkstr (0); }
405 chkstr (server->name);
406 chkstr (server->instance);
407 } else { chkstr (0); chkstr (0); }
409 if ( oanswer->SeqLen -
410 ((strings - oanswer->SeqBody) + token->ticketLen + KA_LABELSIZE)
411 >= (ENCRYPTIONBLOCKSIZE + 12)
413 return KABADPROTOCOL;
415 memcpy(token->ticket, strings, token->ticketLen);
416 strings += token->ticketLen;
417 if (memcmp (strings, label, KA_LABELSIZE) != 0) return KABADPROTOCOL;
421 strings += KA_LABELSIZE;
422 temp = round_up_to_ebs((strings - oanswer->SeqBody));
424 if (oanswer->SeqLen > temp) {
425 strings = oanswer->SeqBody + temp;
426 memcpy(&temp, strings, sizeof(afs_int32));
427 tempc = ntohl(temp) >> 24;
428 /* don't forget this if you add any more fields!
429 strings += sizeof(afs_int32);
442 /* call this instead of stub and we'll guarantee to find a host that's up.
443 * this doesn't handle UNOTSYNC very well, should use ubik_Call if you care
446 kawrap_ubik_Call(aproc, aclient, aflags, p1, p2, p3, p4, p5, p6, p7, p8)
447 struct ubik_client *aclient;
450 void *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
452 afs_int32 code, lcode;
456 /* First pass only checks servers known running. Second checks all.
457 * Once we've cycled through all the servers and still nothing, return
458 * error code from the last server tried.
460 for (pass=0, aflags |= UPUBIKONLY; pass<2; pass++, aflags &= ~UPUBIKONLY) {
463 do { /* Cycle through the servers */
465 code = ubik_CallIter (aproc, aclient, aflags, &count, p1,p2,p3,p4,p5,p6,p7,p8);
466 } while ((code == UNOQUORUM) || (code == UNOTSYNC) ||
467 (code == KALOCKED) || (code == -1));
469 if (code != UNOSERVERS) break;
472 /* If cycled through all the servers, return the last error code */
473 if ((code == UNOSERVERS) && lcode) {
479 /* This is the interface to the AuthServer RPC routine Authenticate. It
480 formats the request packet, calls the encryption routine on the answer,
481 calls Authenticate, and decrypts the response. The response is checked for
482 correctness and its contents are copied into the token. */
485 KABADKEY = the key failed when converted to a key schedule. Probably bad
487 KAUBIKCALL - the call to Ubik returned an error, probably a communication
488 failure such as timeout.
489 KABADPROTOCOL - the returned packet was in error. Since a packet was
490 returned it can be presumed that the AuthServer correctly interpreted
491 the response. This may indicate an inauthentic AuthServer.
492 <other> - errors generated by the server process are returned directly.
495 afs_int32 ka_Authenticate (
499 struct ubik_client *conn, /* Ubik connection to the AuthServer in
501 int service, /* ticket granting or admin service */
502 struct ktc_encryptionKey *key,
504 Date end, /* ticket lifetime */
505 struct ktc_token *token,
506 afs_int32 *pwexpires) /* days until it expires */
509 des_key_schedule schedule;
511 struct ka_gettgtRequest request;
512 struct ka_gettgtAnswer answer_old;
513 struct ka_ticketAnswer answer;
521 if (code = des_key_sched (key, schedule)) {
526 if (service == KA_MAINTENANCE_SERVICE) {
527 req_label = KA_GETADM_REQ_LABEL;
528 ans_label = KA_GETADM_ANS_LABEL;
529 } else if (service == KA_TICKET_GRANTING_SERVICE) {
530 req_label = KA_GETTGT_REQ_LABEL;
531 ans_label = KA_GETTGT_ANS_LABEL;
534 return KABADARGUMENT;
537 request_time = time(0);
538 request.time = htonl(request_time);
539 memcpy(request.label, req_label, sizeof(request.label));
540 arequest.SeqLen = sizeof(request);
541 arequest.SeqBody = (char *)&request;
542 des_pcbc_encrypt (arequest.SeqBody, arequest.SeqBody, arequest.SeqLen,
543 schedule, key, ENCRYPT);
545 oanswer.MaxSeqLen = sizeof(answer);
547 oanswer.SeqBody = (char *)&answer;
550 code = kawrap_ubik_Call (KAA_AuthenticateV2, conn, 0,
551 name, instance, start, end, &arequest, &oanswer);
552 if (code == RXGEN_OPCODE) {
553 oanswer.MaxSeqLen = sizeof(answer);
554 oanswer.SeqBody = (char *)&answer;
556 code = ubik_Call (KAA_Authenticate, conn, 0,
557 name, instance, start, end, &arequest, &oanswer);
558 if (code == RXGEN_OPCODE) {
559 extern int KAA_Authenticate_old();
560 oanswer.MaxSeqLen = sizeof(answer_old);
561 oanswer.SeqBody = (char *)&answer_old;
563 code = ubik_Call (KAA_Authenticate_old, conn, 0,
564 name, instance, start, end, &arequest, &oanswer);
566 if (code == RXGEN_OPCODE) {
567 code = KAOLDINTERFACE;
572 if ((code >= KAMINERROR) && (code <= KAMAXERROR)) return code;
575 des_pcbc_encrypt (oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen,
576 schedule, key, DECRYPT);
581 { struct ktc_principal caller;
582 strcpy (caller.name, name);
583 strcpy (caller.instance, instance);
584 strcpy (caller.cell, "");
585 code = CheckTicketAnswer (&oanswer, request_time+1, token,
586 &caller, 0, ans_label, pwexpires);
594 answer_old.time = ntohl(answer_old.time);
595 answer_old.ticket_len = ntohl(answer_old.ticket_len);
596 if ((answer_old.time != request_time+1) ||
597 (answer_old.ticket_len < MINKTCTICKETLEN) ||
598 (answer_old.ticket_len > MAXKTCTICKETLEN)) {
600 return KABADPROTOCOL;
602 { char *label = ((char *)answer_old.ticket)+answer_old.ticket_len;
604 if (strncmp(label, ans_label, sizeof(answer_old.label))) {
606 return KABADPROTOCOL;
608 token->startTime = start;
609 token->endTime = end;
610 token->kvno = ntohl(answer_old.kvno);
611 token->ticketLen = answer_old.ticket_len;
612 memcpy(token->ticket, answer_old.ticket, sizeof(token->ticket));
613 memcpy(&token->sessionKey, &answer_old.sessionkey, sizeof(struct ktc_encryptionKey));
618 return KAINTERNALERROR;
625 afs_int32 ka_GetToken (
631 struct ubik_client *conn, /* Ubik conn to cell's AuthServer */
633 Date end, /* desired ticket lifetime */
634 struct ktc_token *auth_token,
636 struct ktc_token *token)
638 struct ka_getTicketTimes times;
639 struct ka_getTicketAnswer answer_old;
640 struct ka_ticketAnswer answer;
647 des_key_schedule schedule;
652 aticket.SeqLen = auth_token->ticketLen;
653 aticket.SeqBody = auth_token->ticket;
655 code = des_key_sched (&auth_token->sessionKey, schedule);
661 times.start = htonl(start);
662 times.end = htonl(end);
663 des_ecb_encrypt (×, ×, schedule, ENCRYPT);
665 atimes.SeqLen = sizeof(times);
666 atimes.SeqBody = (char *)×
669 oanswer.MaxSeqLen = sizeof(answer);
670 oanswer.SeqBody = (char *)&answer;
673 code = ubik_Call (KAT_GetTicket, conn, 0,
674 auth_token->kvno, auth_domain, &aticket,
675 name, instance, &atimes, &oanswer);
676 if (code == RXGEN_OPCODE) {
677 extern int KAT_GetTicket_old ();
678 oanswer.SeqLen = 0; /* this may be set by first call */
679 oanswer.MaxSeqLen = sizeof(answer_old);
680 oanswer.SeqBody = (char *)&answer_old;
682 code = ubik_Call (KAT_GetTicket_old, conn, 0,
683 auth_token->kvno, auth_domain, &aticket,
684 name, instance, &atimes, &oanswer);
685 if (code == RXGEN_OPCODE) {
686 code = KAOLDINTERFACE;
691 if ((code >= KAMINERROR) && (code <= KAMAXERROR)) return code;
695 des_pcbc_encrypt (oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen,
696 schedule, &auth_token->sessionKey, DECRYPT);
700 { struct ktc_principal server;
701 strcpy (server.name, name);
702 strcpy (server.instance, instance);
703 code = CheckTicketAnswer (&oanswer, 0, token, 0, &server,
704 KA_GETTICKET_ANS_LABEL, &pwexpires);
712 token->startTime = ntohl(answer_old.startTime);
713 token->endTime = ntohl(answer_old.endTime);
714 token->ticketLen = ntohl(answer_old.ticketLen);
715 token->kvno = ntohl(answer_old.kvno);
716 memcpy(&token->sessionKey, &answer_old.sessionKey, sizeof(token->sessionKey));
718 if (tkt_CheckTimes (token->startTime, token->endTime, time(0)) < 0) {
720 return KABADPROTOCOL;
722 if ((token->ticketLen < MINKTCTICKETLEN) ||
723 (token->ticketLen > MAXKTCTICKETLEN)) {
725 return KABADPROTOCOL;
727 strings = answer_old.name;
728 len = strlen(strings); /* check client name */
729 if ((len < 1) || (len > MAXKTCNAMELEN)) {
731 return KABADPROTOCOL;
733 strings += len+1; /* check client instance */
734 len = strlen(strings);
735 if ((len < 0) || (len > MAXKTCNAMELEN)) {
737 return KABADPROTOCOL;
740 len = strlen(strings); /* check client cell */
741 if ((len < 0) || (len > MAXKTCNAMELEN)) {
743 return KABADPROTOCOL;
746 len = strlen(strings); /* check server name */
747 if ((len < 1) || (len > MAXKTCNAMELEN) ||
748 strcmp (name, strings)) {
750 return KABADPROTOCOL;
753 len = strlen(strings); /* check server instance */
754 if ((len < 0) || (len > MAXKTCNAMELEN) ||
755 strcmp (instance, strings)) {
757 return KABADPROTOCOL;
761 if ((strings - oanswer.SeqBody + token->ticketLen) - oanswer.SeqLen >=
762 ENCRYPTIONBLOCKSIZE) {
764 return KABADPROTOCOL;
766 memcpy(token->ticket, strings, token->ticketLen);
771 return KAINTERNALERROR;
778 afs_int32 ka_ChangePassword (
781 struct ubik_client *conn, /* Ubik connection to the AuthServer in
783 struct ktc_encryptionKey *oldkey,
784 struct ktc_encryptionKey *newkey)
789 #ifdef AFS_S390_LINUX20_ENV
790 code = ubik_Call_New (KAM_SetPassword, conn, 0, name,
791 instance, 0, 0, *newkey);
793 code = ubik_Call_New (KAM_SetPassword, conn, 0, name,
794 instance, 0, *newkey);