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>
13 #include <afs/param.h>
19 #ifdef IGNORE_SOME_GCC_WARNINGS
20 # pragma GCC diagnostic warning "-Wstrict-prototypes"
21 # pragma GCC diagnostic warning "-Wimplicit-function-declaration"
24 #include <hcrypto/des.h>
26 #define UBIK_LEGACY_CALLITER 1
28 #include <afs/pthread_glock.h>
30 #include <rx/rxkad_convert.h>
31 #include <afs/cellconfig.h>
34 #include <afs/afsutil.h>
40 #include "afs_usrops.h"
43 static struct afsconf_dir *conf = 0;
44 static struct afsconf_cell explicit_cell_server_list;
45 static struct afsconf_cell debug_cell_server_list;
46 static int explicit = 0;
49 #ifdef ENCRYPTIONBLOCKSIZE
50 #undef ENCRYPTIONBLOCKSIZE
52 #define ENCRYPTIONBLOCKSIZE (sizeof(DES_cblock))
54 /* Copy the specified list of servers into a specially know cell named
55 "explicit". The cell can then be used to debug experimental servers. */
58 ka_ExplicitCell(char *cell, afs_uint32 serverList[])
63 ka_ExpandCell(cell, explicit_cell_server_list.name, 0);
64 for (i = 0; i < MAXHOSTSPERCELL; i++)
66 explicit_cell_server_list.numServers = i + 1;
67 explicit_cell_server_list.hostAddr[i].sin_family = AF_INET;
68 explicit_cell_server_list.hostAddr[i].sin_addr.s_addr =
70 explicit_cell_server_list.hostName[i][0] = 0;
71 explicit_cell_server_list.hostAddr[i].sin_port =
72 htons(AFSCONF_KAUTHPORT);
73 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
74 explicit_cell_server_list.hostAddr[i].sin_len =
75 sizeof(struct sockaddr_in);
84 myCellLookup(struct afsconf_dir *conf, char *cell, char *service,
85 struct afsconf_cell *cellinfo)
88 *cellinfo = debug_cell_server_list;
91 && (strcmp(cell, explicit_cell_server_list.name) == 0)) {
92 *cellinfo = explicit_cell_server_list;
95 /* call the real one */
97 return afsconf_GetCellInfo(conf, cell, service, cellinfo);
101 ka_GetServers(char *cell, struct afsconf_cell * cellinfo)
104 char cellname[MAXKTCREALMLEN];
107 if (cell && !strlen(cell))
110 cell = lcstring(cellname, cell, sizeof(cellname));
116 conf = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
123 code = myCellLookup(conf, cell, AFSCONF_KAUTHSERVICE, cellinfo);
129 ka_GetSecurity(int service, struct ktc_token * token,
130 struct rx_securityClass ** scP, int *siP)
131 { /* security class index */
135 case KA_AUTHENTICATION_SERVICE:
136 case KA_TICKET_GRANTING_SERVICE:
138 *scP = rxnull_NewClientSecurityObject();
139 *siP = RX_SCINDEX_NULL;
141 case KA_MAINTENANCE_SERVICE:
145 rxkad_NewClientSecurityObject(rxkad_crypt, &token->sessionKey,
146 token->kvno, token->ticketLen,
148 *siP = RX_SCINDEX_KAD;
152 return KABADARGUMENT;
155 printf("Failed gettting security object\n");
164 ka_SingleServerConn(char *cell, char *server, /* name of server to contact */
165 int service, struct ktc_token * token,
166 struct ubik_client ** conn)
169 struct rx_connection *serverconns[2];
170 struct rx_securityClass *sc;
171 int si; /* security class index */
172 struct afsconf_cell cellinfo; /* for cell auth server list */
175 char sname[MAXHOSTCHARS];
179 code = ka_GetServers(cell, &cellinfo);
185 lcstring(sname, server, sizeof(sname));
186 snamel = strlen(sname);
188 for (i = 0; i < cellinfo.numServers; i++) {
189 if (strncmp(cellinfo.hostName[i], sname, snamel) == 0) {
208 code = ka_GetSecurity(service, token, &sc, &si);
213 #ifdef AFS_PTHREAD_ENV
215 rx_GetCachedConnection(cellinfo.hostAddr[match].sin_addr.s_addr,
216 cellinfo.hostAddr[match].sin_port, service, sc,
220 rx_NewConnection(cellinfo.hostAddr[match].sin_addr.s_addr,
221 cellinfo.hostAddr[match].sin_port, service, sc, si);
223 serverconns[1] = 0; /* terminate list */
225 /* next, pass list of server rx_connections (in serverconns), and a place
226 * to put the returned client structure that we'll use in all of our rpc
227 * calls (via ubik_Call) */
229 code = ubik_ClientInit(serverconns, conn);
238 ka_AuthSpecificServersConn(int service, struct ktc_token * token,
239 struct afsconf_cell * cellinfo,
240 struct ubik_client ** conn)
243 struct rx_connection *serverconns[MAXSERVERS];
244 struct rx_securityClass *sc;
245 int si; /* security class index */
255 code = ka_GetSecurity(service, token, &sc, &si);
261 for (i = 0; i < cellinfo->numServers; i++)
262 #ifdef AFS_PTHREAD_ENV
264 rx_GetCachedConnection(cellinfo->hostAddr[i].sin_addr.s_addr,
265 cellinfo->hostAddr[i].sin_port, service,
269 rx_NewConnection(cellinfo->hostAddr[i].sin_addr.s_addr,
270 cellinfo->hostAddr[i].sin_port, service, sc, si);
272 serverconns[cellinfo->numServers] = 0; /* terminate list */
274 /* next, pass list of server rx_connections (in serverconns), and a place
275 * to put the returned client structure that we'll use in all of our rpc
276 * calls (via ubik_Call) */
278 code = ubik_ClientInit(serverconns, conn);
287 ka_AuthServerConn(char *cell, int service, struct ktc_token * token,
288 struct ubik_client ** conn)
291 struct rx_connection *serverconns[MAXSERVERS];
292 struct rx_securityClass *sc;
293 int si; /* security class index */
295 struct afsconf_cell cellinfo; /* for cell auth server list */
298 code = ka_GetServers(cell, &cellinfo);
310 code = ka_GetSecurity(service, token, &sc, &si);
316 for (i = 0; i < cellinfo.numServers; i++)
317 #ifdef AFS_PTHREAD_ENV
319 rx_GetCachedConnection(cellinfo.hostAddr[i].sin_addr.s_addr,
320 cellinfo.hostAddr[i].sin_port, service, sc,
324 rx_NewConnection(cellinfo.hostAddr[i].sin_addr.s_addr,
325 cellinfo.hostAddr[i].sin_port, service, sc, si);
327 serverconns[cellinfo.numServers] = 0; /* terminate list */
329 /* next, pass list of server rx_connections (in serverconns), and a place
330 * to put the returned client structure that we'll use in all of our rpc
331 * calls (via ubik_Call) */
333 code = ubik_ClientInit(serverconns, conn);
342 CheckTicketAnswer(ka_BBS * oanswer, afs_int32 challenge,
343 struct ktc_token *token, struct ktc_principal *caller,
344 struct ktc_principal *server, char *label,
345 afs_int32 * pwexpires)
347 struct ka_ticketAnswer *answer;
350 answer = (struct ka_ticketAnswer *)oanswer->SeqBody;
352 if (challenge != ntohl(answer->challenge))
353 return KABADPROTOCOL;
354 memcpy(&token->sessionKey, &answer->sessionKey,
355 sizeof(token->sessionKey));
356 token->startTime = ntohl(answer->startTime);
357 token->endTime = ntohl(answer->endTime);
358 token->kvno = (short)ntohl(answer->kvno);
359 token->ticketLen = ntohl(answer->ticketLen);
361 if (tkt_CheckTimes(token->startTime, token->endTime, time(0)) < 0)
362 return KABADPROTOCOL;
363 if ((token->ticketLen < MINKTCTICKETLEN)
364 || (token->ticketLen > MAXKTCTICKETLEN))
365 return KABADPROTOCOL;
368 char *strings = answer->name;
371 #define chkstr(field) \
372 len = strlen (strings); \
373 if (len > MAXKTCNAMELEN) return KABADPROTOCOL;\
374 if ((field) && strcmp (field, strings)) return KABADPROTOCOL;\
378 len = strlen(strings); \
379 if (len > MAXKTCNAMELEN) return KABADPROTOCOL; \
383 chkstr(caller->name);
384 chkstr(caller->instance);
385 chkstr(caller->cell);
392 chkstr(server->name);
393 chkstr(server->instance);
399 if (oanswer->SeqLen -
400 ((strings - oanswer->SeqBody) + token->ticketLen + KA_LABELSIZE)
401 >= (ENCRYPTIONBLOCKSIZE + 12)
403 return KABADPROTOCOL;
405 memcpy(token->ticket, strings, token->ticketLen);
406 strings += token->ticketLen;
407 if (memcmp(strings, label, KA_LABELSIZE) != 0)
408 return KABADPROTOCOL;
412 strings += KA_LABELSIZE;
413 temp = round_up_to_ebs((strings - oanswer->SeqBody));
415 if (oanswer->SeqLen > temp) {
416 strings = oanswer->SeqBody + temp;
417 memcpy(&temp, strings, sizeof(afs_int32));
418 tempc = ntohl(temp) >> 24;
419 /* don't forget this if you add any more fields!
420 * strings += sizeof(afs_int32);
432 /* call this instead of stub and we'll guarantee to find a host that's up.
433 * this doesn't handle UNOTSYNC very well, should use ubik_Call if you care
436 kawrap_ubik_Call(int (*aproc) (), struct ubik_client *aclient,
437 afs_int32 aflags, void *p1, void *p2, void *p3, void *p4,
438 void *p5, void *p6, void *p7, void *p8)
440 afs_int32 code, lcode;
444 /* First pass only checks servers known running. Second checks all.
445 * Once we've cycled through all the servers and still nothing, return
446 * error code from the last server tried.
448 for (pass = 0, aflags |= UPUBIKONLY; pass < 2;
449 pass++, aflags &= ~UPUBIKONLY) {
452 do { /* Cycle through the servers */
455 ubik_CallIter(aproc, aclient, aflags, &count, (long) p1,
456 (long) p2, (long) p3, (long) p4,
457 (long) p5, (long) p6, (long) p7,
458 (long) p8, 0, 0, 0, 0, 0, 0, 0, 0);
459 } while ((code == UNOQUORUM) || (code == UNOTSYNC)
460 || (code == KALOCKED) || (code == -1));
462 if (code != UNOSERVERS)
466 /* If cycled through all the servers, return the last error code */
467 if ((code == UNOSERVERS) && lcode) {
473 /* This is the interface to the AuthServer RPC routine Authenticate. It
474 formats the request packet, calls the encryption routine on the answer,
475 calls Authenticate, and decrypts the response. The response is checked for
476 correctness and its contents are copied into the token. */
479 KABADKEY = the key failed when converted to a key schedule. Probably bad
481 KAUBIKCALL - the call to Ubik returned an error, probably a communication
482 failure such as timeout.
483 KABADPROTOCOL - the returned packet was in error. Since a packet was
484 returned it can be presumed that the AuthServer correctly interpreted
485 the response. This may indicate an inauthentic AuthServer.
486 <other> - errors generated by the server process are returned directly.
490 ka_Authenticate(char *name, char *instance, char *cell, struct ubik_client * conn, /* Ubik connection to the AuthServer in
491 * the desired cell */
492 int service, /* ticket granting or admin service */
493 struct ktc_encryptionKey * key, Date start, Date end, /* ticket lifetime */
494 struct ktc_token * token, afs_int32 * pwexpires)
495 { /* days until it expires */
497 DES_key_schedule schedule;
499 struct ka_gettgtRequest request;
500 struct ka_gettgtAnswer answer_old;
501 struct ka_ticketAnswer answer;
509 if ((code = DES_key_sched(ktc_to_cblock(key), &schedule))) {
514 if (service == KA_MAINTENANCE_SERVICE) {
515 req_label = KA_GETADM_REQ_LABEL;
516 ans_label = KA_GETADM_ANS_LABEL;
517 } else if (service == KA_TICKET_GRANTING_SERVICE) {
518 req_label = KA_GETTGT_REQ_LABEL;
519 ans_label = KA_GETTGT_ANS_LABEL;
522 return KABADARGUMENT;
525 request_time = time(0);
526 request.time = htonl(request_time);
527 memcpy(request.label, req_label, sizeof(request.label));
528 arequest.SeqLen = sizeof(request);
529 arequest.SeqBody = (char *)&request;
530 DES_pcbc_encrypt(arequest.SeqBody, arequest.SeqBody, arequest.SeqLen,
531 &schedule, ktc_to_cblockptr(key), ENCRYPT);
533 oanswer.MaxSeqLen = sizeof(answer);
535 oanswer.SeqBody = (char *)&answer;
539 kawrap_ubik_Call(KAA_AuthenticateV2, conn, 0, name, instance,
540 (void*)(uintptr_t)start, (void*)(uintptr_t)end, &arequest, &oanswer, 0, 0);
541 if (code == RXGEN_OPCODE) {
542 oanswer.MaxSeqLen = sizeof(answer);
543 oanswer.SeqBody = (char *)&answer;
546 ubik_KAA_Authenticate(conn, 0, name, instance, start, end,
547 &arequest, &oanswer);
548 if (code == RXGEN_OPCODE) {
549 oanswer.MaxSeqLen = sizeof(answer_old);
550 oanswer.SeqBody = (char *)&answer_old;
553 ubik_KAA_Authenticate_old(conn, 0, name, instance,
554 start, end, &arequest, &oanswer);
556 if (code == RXGEN_OPCODE) {
557 code = KAOLDINTERFACE;
562 if ((code >= KAMINERROR) && (code <= KAMAXERROR))
566 DES_pcbc_encrypt(oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen,
567 &schedule, ktc_to_cblockptr(key), DECRYPT);
573 struct ktc_principal caller;
574 strcpy(caller.name, name);
575 strcpy(caller.instance, instance);
576 strcpy(caller.cell, "");
578 CheckTicketAnswer(&oanswer, request_time + 1, token, &caller,
579 0, ans_label, pwexpires);
587 answer_old.time = ntohl(answer_old.time);
588 answer_old.ticket_len = ntohl(answer_old.ticket_len);
589 if ((answer_old.time != request_time + 1)
590 || (answer_old.ticket_len < MINKTCTICKETLEN)
591 || (answer_old.ticket_len > MAXKTCTICKETLEN)) {
593 return KABADPROTOCOL;
596 char *label = ((char *)answer_old.ticket) + answer_old.ticket_len;
598 if (strncmp(label, ans_label, sizeof(answer_old.label))) {
600 return KABADPROTOCOL;
602 token->startTime = start;
603 token->endTime = end;
604 token->kvno = ntohl(answer_old.kvno);
605 token->ticketLen = answer_old.ticket_len;
606 memcpy(token->ticket, answer_old.ticket, sizeof(token->ticket));
607 memcpy(&token->sessionKey, &answer_old.sessionkey,
608 sizeof(struct ktc_encryptionKey));
613 return KAINTERNALERROR;
621 ka_GetToken(char *name, char *instance, char *cell, char *cname, char *cinst, struct ubik_client * conn, /* Ubik conn to cell's AuthServer */
622 Date start, Date end, /* desired ticket lifetime */
623 struct ktc_token * auth_token, char *auth_domain,
624 struct ktc_token * token)
626 struct ka_getTicketTimes times;
627 struct ka_getTicketAnswer answer_old;
628 struct ka_ticketAnswer answer;
635 DES_key_schedule schedule;
640 aticket.SeqLen = auth_token->ticketLen;
641 aticket.SeqBody = auth_token->ticket;
643 code = DES_key_sched(ktc_to_cblock(&auth_token->sessionKey), &schedule);
649 times.start = htonl(start);
650 times.end = htonl(end);
651 DES_ecb_encrypt((DES_cblock *)×, (DES_cblock *)×, &schedule,
654 atimes.SeqLen = sizeof(times);
655 atimes.SeqBody = (char *)×
658 oanswer.MaxSeqLen = sizeof(answer);
659 oanswer.SeqBody = (char *)&answer;
663 ubik_KAT_GetTicket(conn, 0, auth_token->kvno, auth_domain,
664 &aticket, name, instance, &atimes, &oanswer);
665 if (code == RXGEN_OPCODE) {
666 oanswer.SeqLen = 0; /* this may be set by first call */
667 oanswer.MaxSeqLen = sizeof(answer_old);
668 oanswer.SeqBody = (char *)&answer_old;
671 ubik_KAT_GetTicket_old(conn, 0, auth_token->kvno,
672 auth_domain, &aticket, name, instance, &atimes,
674 if (code == RXGEN_OPCODE) {
675 code = KAOLDINTERFACE;
680 if ((code >= KAMINERROR) && (code <= KAMAXERROR))
685 DES_pcbc_encrypt(oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen,
686 &schedule, ktc_to_cblockptr(&auth_token->sessionKey),
692 struct ktc_principal server;
693 strcpy(server.name, name);
694 strcpy(server.instance, instance);
696 CheckTicketAnswer(&oanswer, 0, token, 0, &server,
697 KA_GETTICKET_ANS_LABEL, &pwexpires);
705 token->startTime = ntohl(answer_old.startTime);
706 token->endTime = ntohl(answer_old.endTime);
707 token->ticketLen = ntohl(answer_old.ticketLen);
708 token->kvno = ntohl(answer_old.kvno);
709 memcpy(&token->sessionKey, &answer_old.sessionKey,
710 sizeof(token->sessionKey));
712 if (tkt_CheckTimes(token->startTime, token->endTime, time(0)) < 0) {
714 return KABADPROTOCOL;
716 if ((token->ticketLen < MINKTCTICKETLEN)
717 || (token->ticketLen > MAXKTCTICKETLEN)) {
719 return KABADPROTOCOL;
721 strings = answer_old.name;
722 len = strlen(strings); /* check client name */
723 if ((len < 1) || (len > MAXKTCNAMELEN)) {
725 return KABADPROTOCOL;
727 strings += len + 1; /* check client instance */
728 len = strlen(strings);
729 if ((len < 0) || (len > MAXKTCNAMELEN)) {
731 return KABADPROTOCOL;
734 len = strlen(strings); /* check client cell */
735 if ((len < 0) || (len > MAXKTCNAMELEN)) {
737 return KABADPROTOCOL;
740 len = strlen(strings); /* check server name */
741 if ((len < 1) || (len > MAXKTCNAMELEN) || strcmp(name, strings)) {
743 return KABADPROTOCOL;
746 len = strlen(strings); /* check server instance */
747 if ((len < 0) || (len > MAXKTCNAMELEN) || strcmp(instance, strings)) {
749 return KABADPROTOCOL;
753 if ((strings - oanswer.SeqBody + token->ticketLen) - oanswer.SeqLen >=
754 ENCRYPTIONBLOCKSIZE) {
756 return KABADPROTOCOL;
758 memcpy(token->ticket, strings, token->ticketLen);
763 return KAINTERNALERROR;
771 ka_ChangePassword(char *name, char *instance, struct ubik_client * conn, /* Ubik connection to the AuthServer in
772 * the desired cell */
773 struct ktc_encryptionKey * oldkey,
774 struct ktc_encryptionKey * newkey)
780 ubik_KAM_SetPassword(conn, UBIK_CALL_NEW, name, instance, 0, *(EncryptionKey *)newkey);