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>
20 #define UBIK_LEGACY_CALLITER 1
23 #include "afs/sysincludes.h"
24 #include "afsincludes.h"
25 #include "afs_usrops.h"
27 #include "afs/pthread_glock.h"
29 #include "afs/cellconfig.h"
33 #include "afs/afsutil.h"
35 #include "afs/kauth.h"
36 #include "afs/kautils.h"
37 #include "afs/pthread_glock.h"
39 #else /* defined(UKERNEL) */
41 #include <afs/pthread_glock.h>
42 #include <sys/types.h>
46 #include <sys/socket.h>
47 #include <netinet/in.h>
51 #include <afs/cellconfig.h>
55 #include <afs/afsutil.h>
58 #endif /* defined(UKERNEL) */
61 static struct afsconf_dir *conf = 0;
62 static struct afsconf_cell explicit_cell_server_list;
63 static struct afsconf_cell debug_cell_server_list;
64 static int explicit = 0;
67 #ifdef ENCRYPTIONBLOCKSIZE
68 #undef ENCRYPTIONBLOCKSIZE
70 #define ENCRYPTIONBLOCKSIZE (sizeof(des_cblock))
72 /* Copy the specified list of servers into a specially know cell named
73 "explicit". The cell can then be used to debug experimental servers. */
76 ka_ExplicitCell(char *cell, afs_int32 serverList[])
81 ka_ExpandCell(cell, explicit_cell_server_list.name, 0);
82 for (i = 0; i < MAXHOSTSPERCELL; i++)
84 explicit_cell_server_list.numServers = i + 1;
85 explicit_cell_server_list.hostAddr[i].sin_family = AF_INET;
86 explicit_cell_server_list.hostAddr[i].sin_addr.s_addr =
88 explicit_cell_server_list.hostName[i][0] = 0;
89 explicit_cell_server_list.hostAddr[i].sin_port =
90 htons(AFSCONF_KAUTHPORT);
91 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
92 explicit_cell_server_list.hostAddr[i].sin_len =
93 sizeof(struct sockaddr_in);
102 myCellLookup(struct afsconf_dir *conf, char *cell, char *service,
103 struct afsconf_cell *cellinfo)
106 *cellinfo = debug_cell_server_list;
109 && (strcmp(cell, explicit_cell_server_list.name) == 0)) {
110 *cellinfo = explicit_cell_server_list;
113 /* call the real one */
115 return afsconf_GetCellInfo(conf, cell, service, cellinfo);
119 ka_GetServers(char *cell, struct afsconf_cell * cellinfo)
122 char cellname[MAXKTCREALMLEN];
125 if (cell && !strlen(cell))
128 cell = lcstring(cellname, cell, sizeof(cellname));
134 conf = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
141 code = myCellLookup(conf, cell, AFSCONF_KAUTHSERVICE, cellinfo);
147 ka_GetSecurity(int service, struct ktc_token * token,
148 struct rx_securityClass ** scP, int *siP)
149 { /* security class index */
153 case KA_AUTHENTICATION_SERVICE:
154 case KA_TICKET_GRANTING_SERVICE:
156 *scP = rxnull_NewClientSecurityObject();
157 *siP = RX_SCINDEX_NULL;
159 case KA_MAINTENANCE_SERVICE:
163 rxkad_NewClientSecurityObject(rxkad_crypt, &token->sessionKey,
164 token->kvno, token->ticketLen,
166 *siP = RX_SCINDEX_KAD;
170 return KABADARGUMENT;
173 printf("Failed gettting security object\n");
182 ka_SingleServerConn(char *cell, char *server, /* name of server to contact */
183 int service, struct ktc_token * token,
184 struct ubik_client ** conn)
187 struct rx_connection *serverconns[2];
188 struct rx_securityClass *sc;
189 int si; /* security class index */
190 struct afsconf_cell cellinfo; /* for cell auth server list */
193 char sname[MAXHOSTCHARS];
197 code = ka_GetServers(cell, &cellinfo);
203 lcstring(sname, server, sizeof(sname));
204 snamel = strlen(sname);
206 for (i = 0; i < cellinfo.numServers; i++) {
207 if (strncmp(cellinfo.hostName[i], sname, snamel) == 0) {
226 code = ka_GetSecurity(service, token, &sc, &si);
231 #ifdef AFS_PTHREAD_ENV
233 rx_GetCachedConnection(cellinfo.hostAddr[match].sin_addr.s_addr,
234 cellinfo.hostAddr[match].sin_port, service, sc,
238 rx_NewConnection(cellinfo.hostAddr[match].sin_addr.s_addr,
239 cellinfo.hostAddr[match].sin_port, service, sc, si);
241 serverconns[1] = 0; /* terminate list */
243 /* next, pass list of server rx_connections (in serverconns), and a place
244 * to put the returned client structure that we'll use in all of our rpc
245 * calls (via ubik_Call) */
247 code = ubik_ClientInit(serverconns, conn);
256 ka_AuthSpecificServersConn(int service, struct ktc_token * token,
257 struct afsconf_cell * cellinfo,
258 struct ubik_client ** conn)
261 struct rx_connection *serverconns[MAXSERVERS];
262 struct rx_securityClass *sc;
263 int si; /* security class index */
273 code = ka_GetSecurity(service, token, &sc, &si);
279 for (i = 0; i < cellinfo->numServers; i++)
280 #ifdef AFS_PTHREAD_ENV
282 rx_GetCachedConnection(cellinfo->hostAddr[i].sin_addr.s_addr,
283 cellinfo->hostAddr[i].sin_port, service,
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);
305 ka_AuthServerConn(char *cell, int service, struct ktc_token * token,
306 struct ubik_client ** conn)
309 struct rx_connection *serverconns[MAXSERVERS];
310 struct rx_securityClass *sc;
311 int si; /* security class index */
313 struct afsconf_cell cellinfo; /* for cell auth server list */
316 code = ka_GetServers(cell, &cellinfo);
328 code = ka_GetSecurity(service, token, &sc, &si);
334 for (i = 0; i < cellinfo.numServers; i++)
335 #ifdef AFS_PTHREAD_ENV
337 rx_GetCachedConnection(cellinfo.hostAddr[i].sin_addr.s_addr,
338 cellinfo.hostAddr[i].sin_port, service, sc,
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);
360 CheckTicketAnswer(ka_BBS * oanswer, afs_int32 challenge,
361 struct ktc_token *token, struct ktc_principal *caller,
362 struct ktc_principal *server, char *label,
363 afs_int32 * pwexpires)
365 struct ka_ticketAnswer *answer;
369 answer = (struct ka_ticketAnswer *)oanswer->SeqBody;
371 cksum = ntohl(answer->cksum);
372 if (challenge != ntohl(answer->challenge))
373 return KABADPROTOCOL;
374 memcpy(&token->sessionKey, &answer->sessionKey,
375 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)
384 || (token->ticketLen > MAXKTCTICKETLEN))
385 return KABADPROTOCOL;
388 char *strings = answer->name;
391 #define chkstr(field) \
392 len = strlen (strings); \
393 if (len > MAXKTCNAMELEN) return KABADPROTOCOL;\
394 if ((field) && strcmp (field, strings)) return KABADPROTOCOL;\
398 len = strlen(strings); \
399 if (len > MAXKTCNAMELEN) return KABADPROTOCOL; \
403 chkstr(caller->name);
404 chkstr(caller->instance);
405 chkstr(caller->cell);
412 chkstr(server->name);
413 chkstr(server->instance);
419 if (oanswer->SeqLen -
420 ((strings - oanswer->SeqBody) + token->ticketLen + KA_LABELSIZE)
421 >= (ENCRYPTIONBLOCKSIZE + 12)
423 return KABADPROTOCOL;
425 memcpy(token->ticket, strings, token->ticketLen);
426 strings += token->ticketLen;
427 if (memcmp(strings, label, KA_LABELSIZE) != 0)
428 return KABADPROTOCOL;
432 strings += KA_LABELSIZE;
433 temp = round_up_to_ebs((strings - oanswer->SeqBody));
435 if (oanswer->SeqLen > temp) {
436 strings = oanswer->SeqBody + temp;
437 memcpy(&temp, strings, sizeof(afs_int32));
438 tempc = ntohl(temp) >> 24;
439 /* don't forget this if you add any more fields!
440 * strings += sizeof(afs_int32);
452 /* call this instead of stub and we'll guarantee to find a host that's up.
453 * this doesn't handle UNOTSYNC very well, should use ubik_Call if you care
456 kawrap_ubik_Call(aproc, aclient, aflags, p1, p2, p3, p4, p5, p6, p7, p8)
457 struct ubik_client *aclient;
460 void *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
462 afs_int32 code, lcode;
466 /* First pass only checks servers known running. Second checks all.
467 * Once we've cycled through all the servers and still nothing, return
468 * error code from the last server tried.
470 for (pass = 0, aflags |= UPUBIKONLY; pass < 2;
471 pass++, aflags &= ~UPUBIKONLY) {
474 do { /* Cycle through the servers */
477 ubik_CallIter(aproc, aclient, aflags, &count, (long) p1,
478 (long) p2, (long) p3, (long) p4,
479 (long) p5, (long) p6, (long) p7,
480 (long) p8, 0, 0, 0, 0, 0, 0, 0, 0);
481 } while ((code == UNOQUORUM) || (code == UNOTSYNC)
482 || (code == KALOCKED) || (code == -1));
484 if (code != UNOSERVERS)
488 /* If cycled through all the servers, return the last error code */
489 if ((code == UNOSERVERS) && lcode) {
495 /* This is the interface to the AuthServer RPC routine Authenticate. It
496 formats the request packet, calls the encryption routine on the answer,
497 calls Authenticate, and decrypts the response. The response is checked for
498 correctness and its contents are copied into the token. */
501 KABADKEY = the key failed when converted to a key schedule. Probably bad
503 KAUBIKCALL - the call to Ubik returned an error, probably a communication
504 failure such as timeout.
505 KABADPROTOCOL - the returned packet was in error. Since a packet was
506 returned it can be presumed that the AuthServer correctly interpreted
507 the response. This may indicate an inauthentic AuthServer.
508 <other> - errors generated by the server process are returned directly.
512 ka_Authenticate(char *name, char *instance, char *cell, struct ubik_client * conn, /* Ubik connection to the AuthServer in
513 * the desired cell */
514 int service, /* ticket granting or admin service */
515 struct ktc_encryptionKey * key, Date start, Date end, /* ticket lifetime */
516 struct ktc_token * token, afs_int32 * pwexpires)
517 { /* days until it expires */
519 des_key_schedule schedule;
521 struct ka_gettgtRequest request;
522 struct ka_gettgtAnswer answer_old;
523 struct ka_ticketAnswer answer;
531 if ((code = des_key_sched(key, schedule))) {
536 if (service == KA_MAINTENANCE_SERVICE) {
537 req_label = KA_GETADM_REQ_LABEL;
538 ans_label = KA_GETADM_ANS_LABEL;
539 } else if (service == KA_TICKET_GRANTING_SERVICE) {
540 req_label = KA_GETTGT_REQ_LABEL;
541 ans_label = KA_GETTGT_ANS_LABEL;
544 return KABADARGUMENT;
547 request_time = time(0);
548 request.time = htonl(request_time);
549 memcpy(request.label, req_label, sizeof(request.label));
550 arequest.SeqLen = sizeof(request);
551 arequest.SeqBody = (char *)&request;
552 des_pcbc_encrypt(arequest.SeqBody, arequest.SeqBody, arequest.SeqLen,
553 schedule, key, ENCRYPT);
555 oanswer.MaxSeqLen = sizeof(answer);
557 oanswer.SeqBody = (char *)&answer;
561 kawrap_ubik_Call(KAA_AuthenticateV2, conn, 0, name, instance,
562 start, end, &arequest, &oanswer, 0, 0);
563 if (code == RXGEN_OPCODE) {
564 oanswer.MaxSeqLen = sizeof(answer);
565 oanswer.SeqBody = (char *)&answer;
568 ubik_Call(KAA_Authenticate, conn, 0, name, instance, start, end,
569 &arequest, &oanswer, 0, 0);
570 if (code == RXGEN_OPCODE) {
571 oanswer.MaxSeqLen = sizeof(answer_old);
572 oanswer.SeqBody = (char *)&answer_old;
575 ubik_Call(KAA_Authenticate_old, conn, 0, name, instance,
576 start, end, &arequest, &oanswer);
578 if (code == RXGEN_OPCODE) {
579 code = KAOLDINTERFACE;
584 if ((code >= KAMINERROR) && (code <= KAMAXERROR))
588 des_pcbc_encrypt(oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen,
589 schedule, key, DECRYPT);
595 struct ktc_principal caller;
596 strcpy(caller.name, name);
597 strcpy(caller.instance, instance);
598 strcpy(caller.cell, "");
600 CheckTicketAnswer(&oanswer, request_time + 1, token, &caller,
601 0, ans_label, pwexpires);
609 answer_old.time = ntohl(answer_old.time);
610 answer_old.ticket_len = ntohl(answer_old.ticket_len);
611 if ((answer_old.time != request_time + 1)
612 || (answer_old.ticket_len < MINKTCTICKETLEN)
613 || (answer_old.ticket_len > MAXKTCTICKETLEN)) {
615 return KABADPROTOCOL;
618 char *label = ((char *)answer_old.ticket) + answer_old.ticket_len;
620 if (strncmp(label, ans_label, sizeof(answer_old.label))) {
622 return KABADPROTOCOL;
624 token->startTime = start;
625 token->endTime = end;
626 token->kvno = ntohl(answer_old.kvno);
627 token->ticketLen = answer_old.ticket_len;
628 memcpy(token->ticket, answer_old.ticket, sizeof(token->ticket));
629 memcpy(&token->sessionKey, &answer_old.sessionkey,
630 sizeof(struct ktc_encryptionKey));
635 return KAINTERNALERROR;
643 ka_GetToken(char *name, char *instance, char *cell, char *cname, char *cinst, struct ubik_client * conn, /* Ubik conn to cell's AuthServer */
644 Date start, Date end, /* desired ticket lifetime */
645 struct ktc_token * auth_token, char *auth_domain,
646 struct ktc_token * token)
648 struct ka_getTicketTimes times;
649 struct ka_getTicketAnswer answer_old;
650 struct ka_ticketAnswer answer;
657 des_key_schedule schedule;
662 aticket.SeqLen = auth_token->ticketLen;
663 aticket.SeqBody = auth_token->ticket;
665 code = des_key_sched(&auth_token->sessionKey, schedule);
671 times.start = htonl(start);
672 times.end = htonl(end);
673 des_ecb_encrypt(×, ×, schedule, ENCRYPT);
675 atimes.SeqLen = sizeof(times);
676 atimes.SeqBody = (char *)×
679 oanswer.MaxSeqLen = sizeof(answer);
680 oanswer.SeqBody = (char *)&answer;
684 ubik_Call(KAT_GetTicket, conn, 0, auth_token->kvno, auth_domain,
685 &aticket, name, instance, &atimes, &oanswer);
686 if (code == RXGEN_OPCODE) {
687 oanswer.SeqLen = 0; /* this may be set by first call */
688 oanswer.MaxSeqLen = sizeof(answer_old);
689 oanswer.SeqBody = (char *)&answer_old;
692 ubik_Call(KAT_GetTicket_old, conn, 0, auth_token->kvno,
693 auth_domain, &aticket, name, instance, &atimes,
695 if (code == RXGEN_OPCODE) {
696 code = KAOLDINTERFACE;
701 if ((code >= KAMINERROR) && (code <= KAMAXERROR))
706 des_pcbc_encrypt(oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen,
707 schedule, &auth_token->sessionKey, DECRYPT);
712 struct ktc_principal server;
713 strcpy(server.name, name);
714 strcpy(server.instance, instance);
716 CheckTicketAnswer(&oanswer, 0, token, 0, &server,
717 KA_GETTICKET_ANS_LABEL, &pwexpires);
725 token->startTime = ntohl(answer_old.startTime);
726 token->endTime = ntohl(answer_old.endTime);
727 token->ticketLen = ntohl(answer_old.ticketLen);
728 token->kvno = ntohl(answer_old.kvno);
729 memcpy(&token->sessionKey, &answer_old.sessionKey,
730 sizeof(token->sessionKey));
732 if (tkt_CheckTimes(token->startTime, token->endTime, time(0)) < 0) {
734 return KABADPROTOCOL;
736 if ((token->ticketLen < MINKTCTICKETLEN)
737 || (token->ticketLen > MAXKTCTICKETLEN)) {
739 return KABADPROTOCOL;
741 strings = answer_old.name;
742 len = strlen(strings); /* check client name */
743 if ((len < 1) || (len > MAXKTCNAMELEN)) {
745 return KABADPROTOCOL;
747 strings += len + 1; /* check client instance */
748 len = strlen(strings);
749 if ((len < 0) || (len > MAXKTCNAMELEN)) {
751 return KABADPROTOCOL;
754 len = strlen(strings); /* check client cell */
755 if ((len < 0) || (len > MAXKTCNAMELEN)) {
757 return KABADPROTOCOL;
760 len = strlen(strings); /* check server name */
761 if ((len < 1) || (len > MAXKTCNAMELEN) || strcmp(name, strings)) {
763 return KABADPROTOCOL;
766 len = strlen(strings); /* check server instance */
767 if ((len < 0) || (len > MAXKTCNAMELEN) || strcmp(instance, strings)) {
769 return KABADPROTOCOL;
773 if ((strings - oanswer.SeqBody + token->ticketLen) - oanswer.SeqLen >=
774 ENCRYPTIONBLOCKSIZE) {
776 return KABADPROTOCOL;
778 memcpy(token->ticket, strings, token->ticketLen);
783 return KAINTERNALERROR;
791 ka_ChangePassword(char *name, char *instance, struct ubik_client * conn, /* Ubik connection to the AuthServer in
792 * the desired cell */
793 struct ktc_encryptionKey * oldkey,
794 struct ktc_encryptionKey * newkey)
799 #if defined(AFS_S390_LINUX20_ENV) && !defined(AFS_S390X_LINUX20_ENV)
801 ubik_Call_New(KAM_SetPassword, conn, 0, name, instance, 0, 0,
805 ubik_Call_New(KAM_SetPassword, conn, 0, name, instance, 0, *newkey);