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>
39 static struct afsconf_dir
*conf
= 0;
40 static struct afsconf_cell explicit_cell_server_list
;
41 static struct afsconf_cell debug_cell_server_list
;
42 static int explicit = 0;
45 #ifdef ENCRYPTIONBLOCKSIZE
46 #undef ENCRYPTIONBLOCKSIZE
48 #define ENCRYPTIONBLOCKSIZE (sizeof(DES_cblock))
50 /* Copy the specified list of servers into a specially know cell named
51 "explicit". The cell can then be used to debug experimental servers. */
54 ka_ExplicitCell(char *cell
, afs_uint32 serverList
[])
59 ka_ExpandCell(cell
, explicit_cell_server_list
.name
, 0);
60 for (i
= 0; i
< MAXHOSTSPERCELL
; i
++)
62 explicit_cell_server_list
.numServers
= i
+ 1;
63 explicit_cell_server_list
.hostAddr
[i
].sin_family
= AF_INET
;
64 explicit_cell_server_list
.hostAddr
[i
].sin_addr
.s_addr
=
66 explicit_cell_server_list
.hostName
[i
][0] = 0;
67 explicit_cell_server_list
.hostAddr
[i
].sin_port
=
68 htons(AFSCONF_KAUTHPORT
);
69 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
70 explicit_cell_server_list
.hostAddr
[i
].sin_len
=
71 sizeof(struct sockaddr_in
);
80 myCellLookup(struct afsconf_dir
*conf
, char *cell
, char *service
,
81 struct afsconf_cell
*cellinfo
)
84 *cellinfo
= debug_cell_server_list
;
87 && (strcmp(cell
, explicit_cell_server_list
.name
) == 0)) {
88 *cellinfo
= explicit_cell_server_list
;
91 /* call the real one */
93 return afsconf_GetCellInfo(conf
, cell
, service
, cellinfo
);
97 ka_GetServers(char *cell
, struct afsconf_cell
* cellinfo
)
100 char cellname
[MAXKTCREALMLEN
];
103 if (cell
== NULL
|| strlen(cell
) == 0)
106 cell
= lcstring(cellname
, cell
, sizeof(cellname
));
109 conf
= afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH
);
115 code
= myCellLookup(conf
, cell
, AFSCONF_KAUTHSERVICE
, cellinfo
);
121 ka_GetSecurity(int service
, struct ktc_token
* token
,
122 struct rx_securityClass
** scP
, int *siP
)
123 { /* security class index */
127 case KA_AUTHENTICATION_SERVICE
:
128 case KA_TICKET_GRANTING_SERVICE
:
130 *scP
= rxnull_NewClientSecurityObject();
131 *siP
= RX_SECIDX_NULL
;
133 case KA_MAINTENANCE_SERVICE
:
137 rxkad_NewClientSecurityObject(rxkad_crypt
, &token
->sessionKey
,
138 token
->kvno
, token
->ticketLen
,
140 *siP
= RX_SECIDX_KAD
;
144 return KABADARGUMENT
;
147 printf("Failed gettting security object\n");
156 ka_SingleServerConn(char *cell
, char *server
, /* name of server to contact */
157 int service
, struct ktc_token
* token
,
158 struct ubik_client
** conn
)
161 struct rx_connection
*serverconns
[2];
162 struct rx_securityClass
*sc
;
163 int si
; /* security class index */
164 struct afsconf_cell cellinfo
; /* for cell auth server list */
167 char sname
[MAXHOSTCHARS
];
171 code
= ka_GetServers(cell
, &cellinfo
);
177 lcstring(sname
, server
, sizeof(sname
));
178 snamel
= strlen(sname
);
180 for (i
= 0; i
< cellinfo
.numServers
; i
++) {
181 if (strncmp(cellinfo
.hostName
[i
], sname
, snamel
) == 0) {
200 code
= ka_GetSecurity(service
, token
, &sc
, &si
);
205 #ifdef AFS_PTHREAD_ENV
207 rx_GetCachedConnection(cellinfo
.hostAddr
[match
].sin_addr
.s_addr
,
208 cellinfo
.hostAddr
[match
].sin_port
, service
, sc
,
212 rx_NewConnection(cellinfo
.hostAddr
[match
].sin_addr
.s_addr
,
213 cellinfo
.hostAddr
[match
].sin_port
, service
, sc
, si
);
215 serverconns
[1] = 0; /* terminate list */
217 /* next, pass list of server rx_connections (in serverconns), and a place
218 * to put the returned client structure that we'll use in all of our rpc
219 * calls (via ubik_Call) */
221 code
= ubik_ClientInit(serverconns
, conn
);
230 ka_AuthSpecificServersConn(int service
, struct ktc_token
* token
,
231 struct afsconf_cell
* cellinfo
,
232 struct ubik_client
** conn
)
235 struct rx_connection
*serverconns
[MAXSERVERS
];
236 struct rx_securityClass
*sc
;
237 int si
; /* security class index */
247 code
= ka_GetSecurity(service
, token
, &sc
, &si
);
253 for (i
= 0; i
< cellinfo
->numServers
; i
++)
254 #ifdef AFS_PTHREAD_ENV
256 rx_GetCachedConnection(cellinfo
->hostAddr
[i
].sin_addr
.s_addr
,
257 cellinfo
->hostAddr
[i
].sin_port
, service
,
261 rx_NewConnection(cellinfo
->hostAddr
[i
].sin_addr
.s_addr
,
262 cellinfo
->hostAddr
[i
].sin_port
, service
, sc
, si
);
264 serverconns
[cellinfo
->numServers
] = 0; /* terminate list */
266 /* next, pass list of server rx_connections (in serverconns), and a place
267 * to put the returned client structure that we'll use in all of our rpc
268 * calls (via ubik_Call) */
270 code
= ubik_ClientInit(serverconns
, conn
);
279 ka_AuthServerConn(char *cell
, int service
, struct ktc_token
* token
,
280 struct ubik_client
** conn
)
283 struct rx_connection
*serverconns
[MAXSERVERS
];
284 struct rx_securityClass
*sc
;
285 int si
; /* security class index */
287 struct afsconf_cell cellinfo
; /* for cell auth server list */
290 code
= ka_GetServers(cell
, &cellinfo
);
302 code
= ka_GetSecurity(service
, token
, &sc
, &si
);
308 for (i
= 0; i
< cellinfo
.numServers
; i
++)
309 #ifdef AFS_PTHREAD_ENV
311 rx_GetCachedConnection(cellinfo
.hostAddr
[i
].sin_addr
.s_addr
,
312 cellinfo
.hostAddr
[i
].sin_port
, service
, sc
,
316 rx_NewConnection(cellinfo
.hostAddr
[i
].sin_addr
.s_addr
,
317 cellinfo
.hostAddr
[i
].sin_port
, service
, sc
, si
);
319 serverconns
[cellinfo
.numServers
] = 0; /* terminate list */
321 /* next, pass list of server rx_connections (in serverconns), and a place
322 * to put the returned client structure that we'll use in all of our rpc
323 * calls (via ubik_Call) */
325 code
= ubik_ClientInit(serverconns
, conn
);
334 CheckTicketAnswer(ka_BBS
* oanswer
, afs_int32 challenge
,
335 struct ktc_token
*token
, struct ktc_principal
*caller
,
336 struct ktc_principal
*server
, char *label
,
337 afs_int32
* pwexpires
)
339 struct ka_ticketAnswer
*answer
;
342 answer
= (struct ka_ticketAnswer
*)oanswer
->SeqBody
;
344 if (challenge
!= ntohl(answer
->challenge
))
345 return KABADPROTOCOL
;
346 memcpy(&token
->sessionKey
, &answer
->sessionKey
,
347 sizeof(token
->sessionKey
));
348 token
->startTime
= ntohl(answer
->startTime
);
349 token
->endTime
= ntohl(answer
->endTime
);
350 token
->kvno
= (short)ntohl(answer
->kvno
);
351 token
->ticketLen
= ntohl(answer
->ticketLen
);
353 if (tkt_CheckTimes(token
->startTime
, token
->endTime
, time(0)) < 0)
354 return KABADPROTOCOL
;
355 if ((token
->ticketLen
< MINKTCTICKETLEN
)
356 || (token
->ticketLen
> MAXKTCTICKETLEN
))
357 return KABADPROTOCOL
;
360 char *strings
= answer
->name
;
363 #define chkstr(field) \
364 len = strlen (strings); \
365 if (len > MAXKTCNAMELEN) return KABADPROTOCOL;\
366 if ((field) && strcmp (field, strings)) return KABADPROTOCOL;\
370 len = strlen(strings); \
371 if (len > MAXKTCNAMELEN) return KABADPROTOCOL; \
375 chkstr(caller
->name
);
376 chkstr(caller
->instance
);
377 chkstr(caller
->cell
);
384 chkstr(server
->name
);
385 chkstr(server
->instance
);
391 if (oanswer
->SeqLen
-
392 ((strings
- oanswer
->SeqBody
) + token
->ticketLen
+ KA_LABELSIZE
)
393 >= (ENCRYPTIONBLOCKSIZE
+ 12)
395 return KABADPROTOCOL
;
397 memcpy(token
->ticket
, strings
, token
->ticketLen
);
398 strings
+= token
->ticketLen
;
399 if (memcmp(strings
, label
, KA_LABELSIZE
) != 0)
400 return KABADPROTOCOL
;
404 strings
+= KA_LABELSIZE
;
405 temp
= round_up_to_ebs((strings
- oanswer
->SeqBody
));
407 if (oanswer
->SeqLen
> temp
) {
408 strings
= oanswer
->SeqBody
+ temp
;
409 memcpy(&temp
, strings
, sizeof(afs_int32
));
410 tempc
= ntohl(temp
) >> 24;
411 /* don't forget this if you add any more fields!
412 * strings += sizeof(afs_int32);
424 /* call this instead of stub and we'll guarantee to find a host that's up.
425 * this doesn't handle UNOTSYNC very well, should use ubik_Call if you care
428 kawrap_ubik_Call(int (*aproc
) (), struct ubik_client
*aclient
,
429 afs_int32 aflags
, void *p1
, void *p2
, void *p3
, void *p4
,
430 void *p5
, void *p6
, void *p7
, void *p8
)
432 afs_int32 code
, lcode
;
436 /* First pass only checks servers known running. Second checks all.
437 * Once we've cycled through all the servers and still nothing, return
438 * error code from the last server tried.
440 for (pass
= 0, aflags
|= UPUBIKONLY
; pass
< 2;
441 pass
++, aflags
&= ~UPUBIKONLY
) {
444 do { /* Cycle through the servers */
447 ubik_CallIter(aproc
, aclient
, aflags
, &count
, (long) p1
,
448 (long) p2
, (long) p3
, (long) p4
,
449 (long) p5
, (long) p6
, (long) p7
,
450 (long) p8
, 0, 0, 0, 0, 0, 0, 0, 0);
451 } while ((code
== UNOQUORUM
) || (code
== UNOTSYNC
)
452 || (code
== KALOCKED
) || (code
== -1));
454 if (code
!= UNOSERVERS
)
458 /* If cycled through all the servers, return the last error code */
459 if ((code
== UNOSERVERS
) && lcode
) {
465 /* This is the interface to the AuthServer RPC routine Authenticate. It
466 formats the request packet, calls the encryption routine on the answer,
467 calls Authenticate, and decrypts the response. The response is checked for
468 correctness and its contents are copied into the token. */
471 KABADKEY = the key failed when converted to a key schedule. Probably bad
473 KAUBIKCALL - the call to Ubik returned an error, probably a communication
474 failure such as timeout.
475 KABADPROTOCOL - the returned packet was in error. Since a packet was
476 returned it can be presumed that the AuthServer correctly interpreted
477 the response. This may indicate an inauthentic AuthServer.
478 <other> - errors generated by the server process are returned directly.
482 ka_Authenticate(char *name
, char *instance
, char *cell
, struct ubik_client
* conn
, /* Ubik connection to the AuthServer in
483 * the desired cell */
484 int service
, /* ticket granting or admin service */
485 struct ktc_encryptionKey
* key
, Date start
, Date end
, /* ticket lifetime */
486 struct ktc_token
* token
, afs_int32
* pwexpires
)
487 { /* days until it expires */
489 DES_key_schedule schedule
;
491 struct ka_gettgtRequest request
;
492 struct ka_gettgtAnswer answer_old
;
493 struct ka_ticketAnswer answer
;
501 if ((code
= DES_key_sched(ktc_to_cblock(key
), &schedule
))) {
506 if (service
== KA_MAINTENANCE_SERVICE
) {
507 req_label
= KA_GETADM_REQ_LABEL
;
508 ans_label
= KA_GETADM_ANS_LABEL
;
509 } else if (service
== KA_TICKET_GRANTING_SERVICE
) {
510 req_label
= KA_GETTGT_REQ_LABEL
;
511 ans_label
= KA_GETTGT_ANS_LABEL
;
514 return KABADARGUMENT
;
517 request_time
= time(0);
518 request
.time
= htonl(request_time
);
519 memcpy(request
.label
, req_label
, sizeof(request
.label
));
520 arequest
.SeqLen
= sizeof(request
);
521 arequest
.SeqBody
= (char *)&request
;
522 DES_pcbc_encrypt(arequest
.SeqBody
, arequest
.SeqBody
, arequest
.SeqLen
,
523 &schedule
, ktc_to_cblockptr(key
), ENCRYPT
);
525 oanswer
.MaxSeqLen
= sizeof(answer
);
527 oanswer
.SeqBody
= (char *)&answer
;
531 kawrap_ubik_Call(KAA_AuthenticateV2
, conn
, 0, name
, instance
,
532 (void*)(uintptr_t)start
, (void*)(uintptr_t)end
, &arequest
, &oanswer
, 0, 0);
533 if (code
== RXGEN_OPCODE
) {
534 oanswer
.MaxSeqLen
= sizeof(answer
);
535 oanswer
.SeqBody
= (char *)&answer
;
538 ubik_KAA_Authenticate(conn
, 0, name
, instance
, start
, end
,
539 &arequest
, &oanswer
);
540 if (code
== RXGEN_OPCODE
) {
541 oanswer
.MaxSeqLen
= sizeof(answer_old
);
542 oanswer
.SeqBody
= (char *)&answer_old
;
545 ubik_KAA_Authenticate_old(conn
, 0, name
, instance
,
546 start
, end
, &arequest
, &oanswer
);
548 if (code
== RXGEN_OPCODE
) {
549 code
= KAOLDINTERFACE
;
554 if ((code
>= KAMINERROR
) && (code
<= KAMAXERROR
))
558 DES_pcbc_encrypt(oanswer
.SeqBody
, oanswer
.SeqBody
, oanswer
.SeqLen
,
559 &schedule
, ktc_to_cblockptr(key
), DECRYPT
);
565 struct ktc_principal caller
;
566 strcpy(caller
.name
, name
);
567 strcpy(caller
.instance
, instance
);
568 strcpy(caller
.cell
, "");
570 CheckTicketAnswer(&oanswer
, request_time
+ 1, token
, &caller
,
571 0, ans_label
, pwexpires
);
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
)) {
585 return KABADPROTOCOL
;
588 char *label
= ((char *)answer_old
.ticket
) + answer_old
.ticket_len
;
590 if (strncmp(label
, ans_label
, sizeof(answer_old
.label
))) {
592 return KABADPROTOCOL
;
594 token
->startTime
= start
;
595 token
->endTime
= end
;
596 token
->kvno
= ntohl(answer_old
.kvno
);
597 token
->ticketLen
= answer_old
.ticket_len
;
598 memcpy(token
->ticket
, answer_old
.ticket
, sizeof(token
->ticket
));
599 memcpy(&token
->sessionKey
, &answer_old
.sessionkey
,
600 sizeof(struct ktc_encryptionKey
));
605 return KAINTERNALERROR
;
613 ka_GetToken(char *name
, char *instance
, char *cell
, char *cname
, char *cinst
, struct ubik_client
* conn
, /* Ubik conn to cell's AuthServer */
614 Date start
, Date end
, /* desired ticket lifetime */
615 struct ktc_token
* auth_token
, char *auth_domain
,
616 struct ktc_token
* token
)
618 struct ka_getTicketTimes times
;
619 struct ka_getTicketAnswer answer_old
;
620 struct ka_ticketAnswer answer
;
627 DES_key_schedule schedule
;
632 aticket
.SeqLen
= auth_token
->ticketLen
;
633 aticket
.SeqBody
= auth_token
->ticket
;
635 code
= DES_key_sched(ktc_to_cblock(&auth_token
->sessionKey
), &schedule
);
641 times
.start
= htonl(start
);
642 times
.end
= htonl(end
);
643 DES_ecb_encrypt((DES_cblock
*)×
, (DES_cblock
*)×
, &schedule
,
646 atimes
.SeqLen
= sizeof(times
);
647 atimes
.SeqBody
= (char *)×
;
650 oanswer
.MaxSeqLen
= sizeof(answer
);
651 oanswer
.SeqBody
= (char *)&answer
;
655 ubik_KAT_GetTicket(conn
, 0, auth_token
->kvno
, auth_domain
,
656 &aticket
, name
, instance
, &atimes
, &oanswer
);
657 if (code
== RXGEN_OPCODE
) {
658 oanswer
.SeqLen
= 0; /* this may be set by first call */
659 oanswer
.MaxSeqLen
= sizeof(answer_old
);
660 oanswer
.SeqBody
= (char *)&answer_old
;
663 ubik_KAT_GetTicket_old(conn
, 0, auth_token
->kvno
,
664 auth_domain
, &aticket
, name
, instance
, &atimes
,
666 if (code
== RXGEN_OPCODE
) {
667 code
= KAOLDINTERFACE
;
672 if ((code
>= KAMINERROR
) && (code
<= KAMAXERROR
))
677 DES_pcbc_encrypt(oanswer
.SeqBody
, oanswer
.SeqBody
, oanswer
.SeqLen
,
678 &schedule
, ktc_to_cblockptr(&auth_token
->sessionKey
),
684 struct ktc_principal server
;
685 strcpy(server
.name
, name
);
686 strcpy(server
.instance
, instance
);
688 CheckTicketAnswer(&oanswer
, 0, token
, 0, &server
,
689 KA_GETTICKET_ANS_LABEL
, &pwexpires
);
697 token
->startTime
= ntohl(answer_old
.startTime
);
698 token
->endTime
= ntohl(answer_old
.endTime
);
699 token
->ticketLen
= ntohl(answer_old
.ticketLen
);
700 token
->kvno
= ntohl(answer_old
.kvno
);
701 memcpy(&token
->sessionKey
, &answer_old
.sessionKey
,
702 sizeof(token
->sessionKey
));
704 if (tkt_CheckTimes(token
->startTime
, token
->endTime
, time(0)) < 0) {
706 return KABADPROTOCOL
;
708 if ((token
->ticketLen
< MINKTCTICKETLEN
)
709 || (token
->ticketLen
> MAXKTCTICKETLEN
)) {
711 return KABADPROTOCOL
;
713 strings
= answer_old
.name
;
714 len
= strlen(strings
); /* check client name */
715 if ((len
< 1) || (len
> MAXKTCNAMELEN
)) {
717 return KABADPROTOCOL
;
719 strings
+= len
+ 1; /* check client instance */
720 len
= strlen(strings
);
721 if ((len
< 0) || (len
> MAXKTCNAMELEN
)) {
723 return KABADPROTOCOL
;
726 len
= strlen(strings
); /* check client cell */
727 if ((len
< 0) || (len
> MAXKTCNAMELEN
)) {
729 return KABADPROTOCOL
;
732 len
= strlen(strings
); /* check server name */
733 if ((len
< 1) || (len
> MAXKTCNAMELEN
) || strcmp(name
, strings
)) {
735 return KABADPROTOCOL
;
738 len
= strlen(strings
); /* check server instance */
739 if ((len
< 0) || (len
> MAXKTCNAMELEN
) || strcmp(instance
, strings
)) {
741 return KABADPROTOCOL
;
745 if ((strings
- oanswer
.SeqBody
+ token
->ticketLen
) - oanswer
.SeqLen
>=
746 ENCRYPTIONBLOCKSIZE
) {
748 return KABADPROTOCOL
;
750 memcpy(token
->ticket
, strings
, token
->ticketLen
);
755 return KAINTERNALERROR
;
763 ka_ChangePassword(char *name
, char *instance
, struct ubik_client
* conn
, /* Ubik connection to the AuthServer in
764 * the desired cell */
765 struct ktc_encryptionKey
* oldkey
,
766 struct ktc_encryptionKey
* newkey
)
772 ubik_KAM_SetPassword(conn
, UBIK_CALL_NEW
, name
, instance
, 0, *(EncryptionKey
*)newkey
);