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>
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>
57 #include <afs/cellconfig.h>
61 #include <afs/afsutil.h>
64 #endif /* defined(UKERNEL) */
67 static struct afsconf_dir *conf = 0;
68 static struct afsconf_cell explicit_cell_server_list;
69 static struct afsconf_cell debug_cell_server_list;
70 static int explicit = 0;
73 #ifdef ENCRYPTIONBLOCKSIZE
74 #undef ENCRYPTIONBLOCKSIZE
76 #define ENCRYPTIONBLOCKSIZE (sizeof(des_cblock))
78 /* Copy the specified list of servers into a specially know cell named
79 "explicit". The cell can then be used to debug experimental servers. */
82 ka_ExplicitCell(char *cell, afs_int32 serverList[])
86 LOCK_GLOBAL_MUTEX ka_ExpandCell(cell, explicit_cell_server_list.name, 0);
87 for (i = 0; i < MAXHOSTSPERCELL; i++)
89 explicit_cell_server_list.numServers = i + 1;
90 explicit_cell_server_list.hostAddr[i].sin_family = AF_INET;
91 explicit_cell_server_list.hostAddr[i].sin_addr.s_addr =
93 explicit_cell_server_list.hostName[i][0] = 0;
94 explicit_cell_server_list.hostAddr[i].sin_port =
95 htons(AFSCONF_KAUTHPORT);
96 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
97 explicit_cell_server_list.hostAddr[i].sin_len =
98 sizeof(struct sockaddr_in);
106 myCellLookup(struct afsconf_dir *conf, char *cell, char *service,
107 struct afsconf_cell *cellinfo)
110 *cellinfo = debug_cell_server_list;
113 && (strcmp(cell, explicit_cell_server_list.name) == 0)) {
114 *cellinfo = explicit_cell_server_list;
117 /* call the real one */
119 return afsconf_GetCellInfo(conf, cell, service, cellinfo);
123 ka_GetServers(char *cell, struct afsconf_cell * cellinfo)
126 char cellname[MAXKTCREALMLEN];
128 LOCK_GLOBAL_MUTEX if (cell && !strlen(cell))
131 cell = lcstring(cellname, cell, sizeof(cellname));
137 conf = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH);
140 UNLOCK_GLOBAL_MUTEX return KANOCELLS;
143 code = myCellLookup(conf, cell, AFSCONF_KAUTHSERVICE, cellinfo);
144 UNLOCK_GLOBAL_MUTEX return code;
148 ka_GetSecurity(int service, struct ktc_token * token,
149 struct rx_securityClass ** scP, int *siP)
150 { /* security class index */
151 LOCK_GLOBAL_MUTEX *scP = 0;
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;
169 UNLOCK_GLOBAL_MUTEX return KABADARGUMENT;
172 printf("Failed gettting security object\n");
173 UNLOCK_GLOBAL_MUTEX return KARXFAIL;
175 UNLOCK_GLOBAL_MUTEX return 0;
179 ka_SingleServerConn(char *cell, char *server, /* name of server to contact */
180 int service, struct ktc_token * token,
181 struct ubik_client ** conn)
184 struct rx_connection *serverconns[2];
185 struct rx_securityClass *sc;
186 int si; /* security class index */
187 struct afsconf_cell cellinfo; /* for cell auth server list */
190 char sname[MAXHOSTCHARS];
193 LOCK_GLOBAL_MUTEX code = ka_GetServers(cell, &cellinfo);
195 UNLOCK_GLOBAL_MUTEX return code;
198 lcstring(sname, server, sizeof(sname));
199 snamel = strlen(sname);
201 for (i = 0; i < cellinfo.numServers; i++) {
202 if (strncmp(cellinfo.hostName[i], sname, snamel) == 0) {
204 UNLOCK_GLOBAL_MUTEX return KANOCELLS;
210 UNLOCK_GLOBAL_MUTEX return KANOCELLS;
215 UNLOCK_GLOBAL_MUTEX return code;
218 code = ka_GetSecurity(service, token, &sc, &si);
220 UNLOCK_GLOBAL_MUTEX return code;
222 #ifdef AFS_PTHREAD_ENV
224 rx_GetCachedConnection(cellinfo.hostAddr[match].sin_addr.s_addr,
225 cellinfo.hostAddr[match].sin_port, service, sc,
229 rx_NewConnection(cellinfo.hostAddr[match].sin_addr.s_addr,
230 cellinfo.hostAddr[match].sin_port, service, sc, si);
232 serverconns[1] = 0; /* terminate list */
234 /* next, pass list of server rx_connections (in serverconns), and a place
235 * to put the returned client structure that we'll use in all of our rpc
236 * calls (via ubik_Call) */
238 code = ubik_ClientInit(serverconns, conn);
240 UNLOCK_GLOBAL_MUTEX if (code)
246 ka_AuthSpecificServersConn(int service, struct ktc_token * token,
247 struct afsconf_cell * cellinfo,
248 struct ubik_client ** conn)
251 struct rx_connection *serverconns[MAXSERVERS];
252 struct rx_securityClass *sc;
253 int si; /* security class index */
256 LOCK_GLOBAL_MUTEX code = rx_Init(0);
258 UNLOCK_GLOBAL_MUTEX return code;
261 code = ka_GetSecurity(service, token, &sc, &si);
263 UNLOCK_GLOBAL_MUTEX return code;
266 for (i = 0; i < cellinfo->numServers; i++)
267 #ifdef AFS_PTHREAD_ENV
269 rx_GetCachedConnection(cellinfo->hostAddr[i].sin_addr.s_addr,
270 cellinfo->hostAddr[i].sin_port, service,
274 rx_NewConnection(cellinfo->hostAddr[i].sin_addr.s_addr,
275 cellinfo->hostAddr[i].sin_port, service, sc, si);
277 serverconns[cellinfo->numServers] = 0; /* terminate list */
279 /* next, pass list of server rx_connections (in serverconns), and a place
280 * to put the returned client structure that we'll use in all of our rpc
281 * calls (via ubik_Call) */
283 code = ubik_ClientInit(serverconns, conn);
285 UNLOCK_GLOBAL_MUTEX if (code)
291 ka_AuthServerConn(char *cell, int service, struct ktc_token * token,
292 struct ubik_client ** conn)
295 struct rx_connection *serverconns[MAXSERVERS];
296 struct rx_securityClass *sc;
297 int si; /* security class index */
299 struct afsconf_cell cellinfo; /* for cell auth server list */
301 LOCK_GLOBAL_MUTEX code = ka_GetServers(cell, &cellinfo);
303 UNLOCK_GLOBAL_MUTEX return code;
308 UNLOCK_GLOBAL_MUTEX return code;
311 code = ka_GetSecurity(service, token, &sc, &si);
313 UNLOCK_GLOBAL_MUTEX return code;
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);
335 UNLOCK_GLOBAL_MUTEX if (code)
341 CheckTicketAnswer(ka_BBS * oanswer, afs_int32 challenge,
342 struct ktc_token *token, struct ktc_principal *caller,
343 struct ktc_principal *server, char *label,
344 afs_int32 * pwexpires)
346 struct ka_ticketAnswer *answer;
350 answer = (struct ka_ticketAnswer *)oanswer->SeqBody;
352 cksum = ntohl(answer->cksum);
353 if (challenge != ntohl(answer->challenge))
354 return KABADPROTOCOL;
355 memcpy(&token->sessionKey, &answer->sessionKey,
356 sizeof(token->sessionKey));
357 token->startTime = ntohl(answer->startTime);
358 token->endTime = ntohl(answer->endTime);
359 token->kvno = (short)ntohl(answer->kvno);
360 token->ticketLen = ntohl(answer->ticketLen);
362 if (tkt_CheckTimes(token->startTime, token->endTime, time(0)) < 0)
363 return KABADPROTOCOL;
364 if ((token->ticketLen < MINKTCTICKETLEN)
365 || (token->ticketLen > MAXKTCTICKETLEN))
366 return KABADPROTOCOL;
369 char *strings = answer->name;
372 #define chkstr(field) \
373 len = strlen (strings); \
374 if (len > MAXKTCNAMELEN) return KABADPROTOCOL;\
375 if ((field) && strcmp (field, strings)) return KABADPROTOCOL;\
379 chkstr(caller->name);
380 chkstr(caller->instance);
381 chkstr(caller->cell);
388 chkstr(server->name);
389 chkstr(server->instance);
395 if (oanswer->SeqLen -
396 ((strings - oanswer->SeqBody) + token->ticketLen + KA_LABELSIZE)
397 >= (ENCRYPTIONBLOCKSIZE + 12)
399 return KABADPROTOCOL;
401 memcpy(token->ticket, strings, token->ticketLen);
402 strings += token->ticketLen;
403 if (memcmp(strings, label, KA_LABELSIZE) != 0)
404 return KABADPROTOCOL;
408 strings += KA_LABELSIZE;
409 temp = round_up_to_ebs((strings - oanswer->SeqBody));
411 if (oanswer->SeqLen > temp) {
412 strings = oanswer->SeqBody + temp;
413 memcpy(&temp, strings, sizeof(afs_int32));
414 tempc = ntohl(temp) >> 24;
415 /* don't forget this if you add any more fields!
416 * strings += sizeof(afs_int32);
428 /* call this instead of stub and we'll guarantee to find a host that's up.
429 * this doesn't handle UNOTSYNC very well, should use ubik_Call if you care
432 kawrap_ubik_Call(aproc, aclient, aflags, p1, p2, p3, p4, p5, p6, p7, p8)
433 struct ubik_client *aclient;
436 void *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
438 afs_int32 code, lcode;
442 /* First pass only checks servers known running. Second checks all.
443 * Once we've cycled through all the servers and still nothing, return
444 * error code from the last server tried.
446 for (pass = 0, aflags |= UPUBIKONLY; pass < 2;
447 pass++, aflags &= ~UPUBIKONLY) {
450 do { /* Cycle through the servers */
453 ubik_CallIter(aproc, aclient, aflags, &count, p1, p2, p3, p4,
455 } while ((code == UNOQUORUM) || (code == UNOTSYNC)
456 || (code == KALOCKED) || (code == -1));
458 if (code != UNOSERVERS)
462 /* If cycled through all the servers, return the last error code */
463 if ((code == UNOSERVERS) && lcode) {
469 /* This is the interface to the AuthServer RPC routine Authenticate. It
470 formats the request packet, calls the encryption routine on the answer,
471 calls Authenticate, and decrypts the response. The response is checked for
472 correctness and its contents are copied into the token. */
475 KABADKEY = the key failed when converted to a key schedule. Probably bad
477 KAUBIKCALL - the call to Ubik returned an error, probably a communication
478 failure such as timeout.
479 KABADPROTOCOL - the returned packet was in error. Since a packet was
480 returned it can be presumed that the AuthServer correctly interpreted
481 the response. This may indicate an inauthentic AuthServer.
482 <other> - errors generated by the server process are returned directly.
486 ka_Authenticate(char *name, char *instance, char *cell, struct ubik_client * conn, /* Ubik connection to the AuthServer in
487 * the desired cell */
488 int service, /* ticket granting or admin service */
489 struct ktc_encryptionKey * key, Date start, Date end, /* ticket lifetime */
490 struct ktc_token * token, afs_int32 * pwexpires)
491 { /* days until it expires */
493 des_key_schedule schedule;
495 struct ka_gettgtRequest request;
496 struct ka_gettgtAnswer answer_old;
497 struct ka_ticketAnswer answer;
504 LOCK_GLOBAL_MUTEX if ((code = des_key_sched(key, schedule))) {
505 UNLOCK_GLOBAL_MUTEX return KABADKEY;
508 if (service == KA_MAINTENANCE_SERVICE) {
509 req_label = KA_GETADM_REQ_LABEL;
510 ans_label = KA_GETADM_ANS_LABEL;
511 } else if (service == KA_TICKET_GRANTING_SERVICE) {
512 req_label = KA_GETTGT_REQ_LABEL;
513 ans_label = KA_GETTGT_ANS_LABEL;
515 UNLOCK_GLOBAL_MUTEX return KABADARGUMENT;
518 request_time = time(0);
519 request.time = htonl(request_time);
520 memcpy(request.label, req_label, sizeof(request.label));
521 arequest.SeqLen = sizeof(request);
522 arequest.SeqBody = (char *)&request;
523 des_pcbc_encrypt(arequest.SeqBody, arequest.SeqBody, arequest.SeqLen,
524 schedule, key, ENCRYPT);
526 oanswer.MaxSeqLen = sizeof(answer);
528 oanswer.SeqBody = (char *)&answer;
532 kawrap_ubik_Call(KAA_AuthenticateV2, conn, 0, name, instance, start,
533 end, &arequest, &oanswer);
534 if (code == RXGEN_OPCODE) {
535 oanswer.MaxSeqLen = sizeof(answer);
536 oanswer.SeqBody = (char *)&answer;
539 ubik_Call(KAA_Authenticate, conn, 0, name, instance, start, end,
540 &arequest, &oanswer);
541 if (code == RXGEN_OPCODE) {
542 extern int KAA_Authenticate_old();
543 oanswer.MaxSeqLen = sizeof(answer_old);
544 oanswer.SeqBody = (char *)&answer_old;
547 ubik_Call(KAA_Authenticate_old, conn, 0, name, instance,
548 start, end, &arequest, &oanswer);
550 if (code == RXGEN_OPCODE) {
551 code = KAOLDINTERFACE;
555 UNLOCK_GLOBAL_MUTEX if ((code >= KAMINERROR) && (code <= KAMAXERROR))
559 des_pcbc_encrypt(oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen,
560 schedule, key, DECRYPT);
566 struct ktc_principal caller;
567 strcpy(caller.name, name);
568 strcpy(caller.instance, instance);
569 strcpy(caller.cell, "");
571 CheckTicketAnswer(&oanswer, request_time + 1, token, &caller,
572 0, ans_label, pwexpires);
574 UNLOCK_GLOBAL_MUTEX return code;
579 answer_old.time = ntohl(answer_old.time);
580 answer_old.ticket_len = ntohl(answer_old.ticket_len);
581 if ((answer_old.time != request_time + 1)
582 || (answer_old.ticket_len < MINKTCTICKETLEN)
583 || (answer_old.ticket_len > MAXKTCTICKETLEN)) {
584 UNLOCK_GLOBAL_MUTEX return KABADPROTOCOL;
587 char *label = ((char *)answer_old.ticket) + answer_old.ticket_len;
589 if (strncmp(label, ans_label, sizeof(answer_old.label))) {
590 UNLOCK_GLOBAL_MUTEX return KABADPROTOCOL;
592 token->startTime = start;
593 token->endTime = end;
594 token->kvno = ntohl(answer_old.kvno);
595 token->ticketLen = answer_old.ticket_len;
596 memcpy(token->ticket, answer_old.ticket, sizeof(token->ticket));
597 memcpy(&token->sessionKey, &answer_old.sessionkey,
598 sizeof(struct ktc_encryptionKey));
602 UNLOCK_GLOBAL_MUTEX return KAINTERNALERROR;
605 UNLOCK_GLOBAL_MUTEX return 0;
609 ka_GetToken(char *name, char *instance, char *cell, char *cname, char *cinst, struct ubik_client * conn, /* Ubik conn to cell's AuthServer */
610 Date start, Date end, /* desired ticket lifetime */
611 struct ktc_token * auth_token, char *auth_domain,
612 struct ktc_token * token)
614 struct ka_getTicketTimes times;
615 struct ka_getTicketAnswer answer_old;
616 struct ka_ticketAnswer answer;
623 des_key_schedule schedule;
627 LOCK_GLOBAL_MUTEX aticket.SeqLen = auth_token->ticketLen;
628 aticket.SeqBody = auth_token->ticket;
630 code = des_key_sched(&auth_token->sessionKey, schedule);
632 UNLOCK_GLOBAL_MUTEX return KABADKEY;
635 times.start = htonl(start);
636 times.end = htonl(end);
637 des_ecb_encrypt(×, ×, schedule, ENCRYPT);
639 atimes.SeqLen = sizeof(times);
640 atimes.SeqBody = (char *)×
643 oanswer.MaxSeqLen = sizeof(answer);
644 oanswer.SeqBody = (char *)&answer;
648 ubik_Call(KAT_GetTicket, conn, 0, auth_token->kvno, auth_domain,
649 &aticket, name, instance, &atimes, &oanswer);
650 if (code == RXGEN_OPCODE) {
651 extern int KAT_GetTicket_old();
652 oanswer.SeqLen = 0; /* this may be set by first call */
653 oanswer.MaxSeqLen = sizeof(answer_old);
654 oanswer.SeqBody = (char *)&answer_old;
657 ubik_Call(KAT_GetTicket_old, conn, 0, auth_token->kvno,
658 auth_domain, &aticket, name, instance, &atimes,
660 if (code == RXGEN_OPCODE) {
661 code = KAOLDINTERFACE;
665 UNLOCK_GLOBAL_MUTEX if ((code >= KAMINERROR) && (code <= KAMAXERROR))
670 des_pcbc_encrypt(oanswer.SeqBody, oanswer.SeqBody, oanswer.SeqLen,
671 schedule, &auth_token->sessionKey, DECRYPT);
676 struct ktc_principal server;
677 strcpy(server.name, name);
678 strcpy(server.instance, instance);
680 CheckTicketAnswer(&oanswer, 0, token, 0, &server,
681 KA_GETTICKET_ANS_LABEL, &pwexpires);
683 UNLOCK_GLOBAL_MUTEX return code;
688 token->startTime = ntohl(answer_old.startTime);
689 token->endTime = ntohl(answer_old.endTime);
690 token->ticketLen = ntohl(answer_old.ticketLen);
691 token->kvno = ntohl(answer_old.kvno);
692 memcpy(&token->sessionKey, &answer_old.sessionKey,
693 sizeof(token->sessionKey));
695 if (tkt_CheckTimes(token->startTime, token->endTime, time(0)) < 0) {
696 UNLOCK_GLOBAL_MUTEX return KABADPROTOCOL;
698 if ((token->ticketLen < MINKTCTICKETLEN)
699 || (token->ticketLen > MAXKTCTICKETLEN)) {
700 UNLOCK_GLOBAL_MUTEX return KABADPROTOCOL;
702 strings = answer_old.name;
703 len = strlen(strings); /* check client name */
704 if ((len < 1) || (len > MAXKTCNAMELEN)) {
705 UNLOCK_GLOBAL_MUTEX return KABADPROTOCOL;
707 strings += len + 1; /* check client instance */
708 len = strlen(strings);
709 if ((len < 0) || (len > MAXKTCNAMELEN)) {
710 UNLOCK_GLOBAL_MUTEX return KABADPROTOCOL;
713 len = strlen(strings); /* check client cell */
714 if ((len < 0) || (len > MAXKTCNAMELEN)) {
715 UNLOCK_GLOBAL_MUTEX return KABADPROTOCOL;
718 len = strlen(strings); /* check server name */
719 if ((len < 1) || (len > MAXKTCNAMELEN) || strcmp(name, strings)) {
720 UNLOCK_GLOBAL_MUTEX return KABADPROTOCOL;
723 len = strlen(strings); /* check server instance */
724 if ((len < 0) || (len > MAXKTCNAMELEN) || strcmp(instance, strings)) {
725 UNLOCK_GLOBAL_MUTEX return KABADPROTOCOL;
729 if ((strings - oanswer.SeqBody + token->ticketLen) - oanswer.SeqLen >=
730 ENCRYPTIONBLOCKSIZE) {
731 UNLOCK_GLOBAL_MUTEX return KABADPROTOCOL;
733 memcpy(token->ticket, strings, token->ticketLen);
737 UNLOCK_GLOBAL_MUTEX return KAINTERNALERROR;
740 UNLOCK_GLOBAL_MUTEX return 0;
744 ka_ChangePassword(char *name, char *instance, struct ubik_client * conn, /* Ubik connection to the AuthServer in
745 * the desired cell */
746 struct ktc_encryptionKey * oldkey,
747 struct ktc_encryptionKey * newkey)
752 #if defined(AFS_S390_LINUX20_ENV) && !defined(AFS_S390X_LINUX20_ENV)
754 ubik_Call_New(KAM_SetPassword, conn, 0, name, instance, 0, 0,
758 ubik_Call_New(KAM_SetPassword, conn, 0, name, instance, 0, *newkey);
760 UNLOCK_GLOBAL_MUTEX return code;