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 extern afs_int32 KAA_Authenticate();
554 oanswer.MaxSeqLen = sizeof(answer);
555 oanswer.SeqBody = (char *)&answer;
557 code = ubik_Call (KAA_Authenticate, conn, 0,
558 name, instance, start, end, &arequest, &oanswer);
559 if (code == RXGEN_OPCODE) {
560 extern int KAA_Authenticate_old();
561 oanswer.MaxSeqLen = sizeof(answer_old);
562 oanswer.SeqBody = (char *)&answer_old;
564 code = ubik_Call (KAA_Authenticate_old, conn, 0,
565 name, instance, start, end, &arequest, &oanswer);
567 if (code == RXGEN_OPCODE) {
568 code = KAOLDINTERFACE;
573 if ((code >= KAMINERROR) && (code <= KAMAXERROR)) return code;
576 des_pcbc_encrypt (oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen,
577 schedule, key, DECRYPT);
582 { struct ktc_principal caller;
583 strcpy (caller.name, name);
584 strcpy (caller.instance, instance);
585 strcpy (caller.cell, "");
586 code = CheckTicketAnswer (&oanswer, request_time+1, token,
587 &caller, 0, ans_label, pwexpires);
595 answer_old.time = ntohl(answer_old.time);
596 answer_old.ticket_len = ntohl(answer_old.ticket_len);
597 if ((answer_old.time != request_time+1) ||
598 (answer_old.ticket_len < MINKTCTICKETLEN) ||
599 (answer_old.ticket_len > MAXKTCTICKETLEN)) {
601 return KABADPROTOCOL;
603 { char *label = ((char *)answer_old.ticket)+answer_old.ticket_len;
605 if (strncmp(label, ans_label, sizeof(answer_old.label))) {
607 return KABADPROTOCOL;
609 token->startTime = start;
610 token->endTime = end;
611 token->kvno = ntohl(answer_old.kvno);
612 token->ticketLen = answer_old.ticket_len;
613 memcpy(token->ticket, answer_old.ticket, sizeof(token->ticket));
614 memcpy(&token->sessionKey, &answer_old.sessionkey, sizeof(struct ktc_encryptionKey));
619 return KAINTERNALERROR;
626 afs_int32 ka_GetToken (
632 struct ubik_client *conn, /* Ubik conn to cell's AuthServer */
634 Date end, /* desired ticket lifetime */
635 struct ktc_token *auth_token,
637 struct ktc_token *token)
639 struct ka_getTicketTimes times;
640 struct ka_getTicketAnswer answer_old;
641 struct ka_ticketAnswer answer;
648 des_key_schedule schedule;
653 aticket.SeqLen = auth_token->ticketLen;
654 aticket.SeqBody = auth_token->ticket;
656 code = des_key_sched (&auth_token->sessionKey, schedule);
662 times.start = htonl(start);
663 times.end = htonl(end);
664 des_ecb_encrypt (×, ×, schedule, ENCRYPT);
666 atimes.SeqLen = sizeof(times);
667 atimes.SeqBody = (char *)×
670 oanswer.MaxSeqLen = sizeof(answer);
671 oanswer.SeqBody = (char *)&answer;
674 code = ubik_Call (KAT_GetTicket, conn, 0,
675 auth_token->kvno, auth_domain, &aticket,
676 name, instance, &atimes, &oanswer);
677 if (code == RXGEN_OPCODE) {
678 extern int KAT_GetTicket_old ();
679 oanswer.SeqLen = 0; /* this may be set by first call */
680 oanswer.MaxSeqLen = sizeof(answer_old);
681 oanswer.SeqBody = (char *)&answer_old;
683 code = ubik_Call (KAT_GetTicket_old, conn, 0,
684 auth_token->kvno, auth_domain, &aticket,
685 name, instance, &atimes, &oanswer);
686 if (code == RXGEN_OPCODE) {
687 code = KAOLDINTERFACE;
692 if ((code >= KAMINERROR) && (code <= KAMAXERROR)) return code;
696 des_pcbc_encrypt (oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen,
697 schedule, &auth_token->sessionKey, DECRYPT);
701 { struct ktc_principal server;
702 strcpy (server.name, name);
703 strcpy (server.instance, instance);
704 code = CheckTicketAnswer (&oanswer, 0, token, 0, &server,
705 KA_GETTICKET_ANS_LABEL, &pwexpires);
713 token->startTime = ntohl(answer_old.startTime);
714 token->endTime = ntohl(answer_old.endTime);
715 token->ticketLen = ntohl(answer_old.ticketLen);
716 token->kvno = ntohl(answer_old.kvno);
717 memcpy(&token->sessionKey, &answer_old.sessionKey, sizeof(token->sessionKey));
719 if (tkt_CheckTimes (token->startTime, token->endTime, time(0)) < 0) {
721 return KABADPROTOCOL;
723 if ((token->ticketLen < MINKTCTICKETLEN) ||
724 (token->ticketLen > MAXKTCTICKETLEN)) {
726 return KABADPROTOCOL;
728 strings = answer_old.name;
729 len = strlen(strings); /* check client name */
730 if ((len < 1) || (len > MAXKTCNAMELEN)) {
732 return KABADPROTOCOL;
734 strings += len+1; /* check client instance */
735 len = strlen(strings);
736 if ((len < 0) || (len > MAXKTCNAMELEN)) {
738 return KABADPROTOCOL;
741 len = strlen(strings); /* check client cell */
742 if ((len < 0) || (len > MAXKTCNAMELEN)) {
744 return KABADPROTOCOL;
747 len = strlen(strings); /* check server name */
748 if ((len < 1) || (len > MAXKTCNAMELEN) ||
749 strcmp (name, strings)) {
751 return KABADPROTOCOL;
754 len = strlen(strings); /* check server instance */
755 if ((len < 0) || (len > MAXKTCNAMELEN) ||
756 strcmp (instance, strings)) {
758 return KABADPROTOCOL;
762 if ((strings - oanswer.SeqBody + token->ticketLen) - oanswer.SeqLen >=
763 ENCRYPTIONBLOCKSIZE) {
765 return KABADPROTOCOL;
767 memcpy(token->ticket, strings, token->ticketLen);
772 return KAINTERNALERROR;
779 afs_int32 ka_ChangePassword (
782 struct ubik_client *conn, /* Ubik connection to the AuthServer in
784 struct ktc_encryptionKey *oldkey,
785 struct ktc_encryptionKey *newkey)
790 #ifdef AFS_S390_LINUX20_ENV
791 code = ubik_Call_New (KAM_SetPassword, conn, 0, name,
792 instance, 0, 0, *newkey);
794 code = ubik_Call_New (KAM_SetPassword, conn, 0, name,
795 instance, 0, *newkey);