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>
15 #ifdef IGNORE_SOME_GCC_WARNINGS
16 # pragma GCC diagnostic warning "-Wstrict-prototypes"
17 # pragma GCC diagnostic warning "-Wimplicit-function-declaration"
20 #define UBIK_LEGACY_CALLITER 1
23 #include <afs/pthread_glock.h>
24 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
37 #include <des_prototypes.h>
39 #include <afs/cellconfig.h>
42 #include <afs/afsutil.h>
47 #include "afs_usrops.h"
50 static struct afsconf_dir
*conf
= 0;
51 static struct afsconf_cell explicit_cell_server_list
;
52 static struct afsconf_cell debug_cell_server_list
;
53 static int explicit = 0;
56 #ifdef ENCRYPTIONBLOCKSIZE
57 #undef ENCRYPTIONBLOCKSIZE
59 #define ENCRYPTIONBLOCKSIZE (sizeof(des_cblock))
61 /* Copy the specified list of servers into a specially know cell named
62 "explicit". The cell can then be used to debug experimental servers. */
65 ka_ExplicitCell(char *cell
, afs_uint32 serverList
[])
70 ka_ExpandCell(cell
, explicit_cell_server_list
.name
, 0);
71 for (i
= 0; i
< MAXHOSTSPERCELL
; i
++)
73 explicit_cell_server_list
.numServers
= i
+ 1;
74 explicit_cell_server_list
.hostAddr
[i
].sin_family
= AF_INET
;
75 explicit_cell_server_list
.hostAddr
[i
].sin_addr
.s_addr
=
77 explicit_cell_server_list
.hostName
[i
][0] = 0;
78 explicit_cell_server_list
.hostAddr
[i
].sin_port
=
79 htons(AFSCONF_KAUTHPORT
);
80 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
81 explicit_cell_server_list
.hostAddr
[i
].sin_len
=
82 sizeof(struct sockaddr_in
);
91 myCellLookup(struct afsconf_dir
*conf
, char *cell
, char *service
,
92 struct afsconf_cell
*cellinfo
)
95 *cellinfo
= debug_cell_server_list
;
98 && (strcmp(cell
, explicit_cell_server_list
.name
) == 0)) {
99 *cellinfo
= explicit_cell_server_list
;
102 /* call the real one */
104 return afsconf_GetCellInfo(conf
, cell
, service
, cellinfo
);
108 ka_GetServers(char *cell
, struct afsconf_cell
* cellinfo
)
111 char cellname
[MAXKTCREALMLEN
];
114 if (cell
&& !strlen(cell
))
117 cell
= lcstring(cellname
, cell
, sizeof(cellname
));
123 conf
= afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH
);
130 code
= myCellLookup(conf
, cell
, AFSCONF_KAUTHSERVICE
, cellinfo
);
136 ka_GetSecurity(int service
, struct ktc_token
* token
,
137 struct rx_securityClass
** scP
, int *siP
)
138 { /* security class index */
142 case KA_AUTHENTICATION_SERVICE
:
143 case KA_TICKET_GRANTING_SERVICE
:
145 *scP
= rxnull_NewClientSecurityObject();
146 *siP
= RX_SCINDEX_NULL
;
148 case KA_MAINTENANCE_SERVICE
:
152 rxkad_NewClientSecurityObject(rxkad_crypt
, &token
->sessionKey
,
153 token
->kvno
, token
->ticketLen
,
155 *siP
= RX_SCINDEX_KAD
;
159 return KABADARGUMENT
;
162 printf("Failed gettting security object\n");
171 ka_SingleServerConn(char *cell
, char *server
, /* name of server to contact */
172 int service
, struct ktc_token
* token
,
173 struct ubik_client
** conn
)
176 struct rx_connection
*serverconns
[2];
177 struct rx_securityClass
*sc
;
178 int si
; /* security class index */
179 struct afsconf_cell cellinfo
; /* for cell auth server list */
182 char sname
[MAXHOSTCHARS
];
186 code
= ka_GetServers(cell
, &cellinfo
);
192 lcstring(sname
, server
, sizeof(sname
));
193 snamel
= strlen(sname
);
195 for (i
= 0; i
< cellinfo
.numServers
; i
++) {
196 if (strncmp(cellinfo
.hostName
[i
], sname
, snamel
) == 0) {
215 code
= ka_GetSecurity(service
, token
, &sc
, &si
);
220 #ifdef AFS_PTHREAD_ENV
222 rx_GetCachedConnection(cellinfo
.hostAddr
[match
].sin_addr
.s_addr
,
223 cellinfo
.hostAddr
[match
].sin_port
, service
, sc
,
227 rx_NewConnection(cellinfo
.hostAddr
[match
].sin_addr
.s_addr
,
228 cellinfo
.hostAddr
[match
].sin_port
, service
, sc
, si
);
230 serverconns
[1] = 0; /* terminate list */
232 /* next, pass list of server rx_connections (in serverconns), and a place
233 * to put the returned client structure that we'll use in all of our rpc
234 * calls (via ubik_Call) */
236 code
= ubik_ClientInit(serverconns
, conn
);
245 ka_AuthSpecificServersConn(int service
, struct ktc_token
* token
,
246 struct afsconf_cell
* cellinfo
,
247 struct ubik_client
** conn
)
250 struct rx_connection
*serverconns
[MAXSERVERS
];
251 struct rx_securityClass
*sc
;
252 int si
; /* security class index */
262 code
= ka_GetSecurity(service
, token
, &sc
, &si
);
268 for (i
= 0; i
< cellinfo
->numServers
; i
++)
269 #ifdef AFS_PTHREAD_ENV
271 rx_GetCachedConnection(cellinfo
->hostAddr
[i
].sin_addr
.s_addr
,
272 cellinfo
->hostAddr
[i
].sin_port
, service
,
276 rx_NewConnection(cellinfo
->hostAddr
[i
].sin_addr
.s_addr
,
277 cellinfo
->hostAddr
[i
].sin_port
, service
, sc
, si
);
279 serverconns
[cellinfo
->numServers
] = 0; /* terminate list */
281 /* next, pass list of server rx_connections (in serverconns), and a place
282 * to put the returned client structure that we'll use in all of our rpc
283 * calls (via ubik_Call) */
285 code
= ubik_ClientInit(serverconns
, conn
);
294 ka_AuthServerConn(char *cell
, int service
, struct ktc_token
* token
,
295 struct ubik_client
** conn
)
298 struct rx_connection
*serverconns
[MAXSERVERS
];
299 struct rx_securityClass
*sc
;
300 int si
; /* security class index */
302 struct afsconf_cell cellinfo
; /* for cell auth server list */
305 code
= ka_GetServers(cell
, &cellinfo
);
317 code
= ka_GetSecurity(service
, token
, &sc
, &si
);
323 for (i
= 0; i
< cellinfo
.numServers
; i
++)
324 #ifdef AFS_PTHREAD_ENV
326 rx_GetCachedConnection(cellinfo
.hostAddr
[i
].sin_addr
.s_addr
,
327 cellinfo
.hostAddr
[i
].sin_port
, service
, sc
,
331 rx_NewConnection(cellinfo
.hostAddr
[i
].sin_addr
.s_addr
,
332 cellinfo
.hostAddr
[i
].sin_port
, service
, sc
, si
);
334 serverconns
[cellinfo
.numServers
] = 0; /* terminate list */
336 /* next, pass list of server rx_connections (in serverconns), and a place
337 * to put the returned client structure that we'll use in all of our rpc
338 * calls (via ubik_Call) */
340 code
= ubik_ClientInit(serverconns
, conn
);
349 CheckTicketAnswer(ka_BBS
* oanswer
, afs_int32 challenge
,
350 struct ktc_token
*token
, struct ktc_principal
*caller
,
351 struct ktc_principal
*server
, char *label
,
352 afs_int32
* pwexpires
)
354 struct ka_ticketAnswer
*answer
;
357 answer
= (struct ka_ticketAnswer
*)oanswer
->SeqBody
;
359 if (challenge
!= ntohl(answer
->challenge
))
360 return KABADPROTOCOL
;
361 memcpy(&token
->sessionKey
, &answer
->sessionKey
,
362 sizeof(token
->sessionKey
));
363 token
->startTime
= ntohl(answer
->startTime
);
364 token
->endTime
= ntohl(answer
->endTime
);
365 token
->kvno
= (short)ntohl(answer
->kvno
);
366 token
->ticketLen
= ntohl(answer
->ticketLen
);
368 if (tkt_CheckTimes(token
->startTime
, token
->endTime
, time(0)) < 0)
369 return KABADPROTOCOL
;
370 if ((token
->ticketLen
< MINKTCTICKETLEN
)
371 || (token
->ticketLen
> MAXKTCTICKETLEN
))
372 return KABADPROTOCOL
;
375 char *strings
= answer
->name
;
378 #define chkstr(field) \
379 len = strlen (strings); \
380 if (len > MAXKTCNAMELEN) return KABADPROTOCOL;\
381 if ((field) && strcmp (field, strings)) return KABADPROTOCOL;\
385 len = strlen(strings); \
386 if (len > MAXKTCNAMELEN) return KABADPROTOCOL; \
390 chkstr(caller
->name
);
391 chkstr(caller
->instance
);
392 chkstr(caller
->cell
);
399 chkstr(server
->name
);
400 chkstr(server
->instance
);
406 if (oanswer
->SeqLen
-
407 ((strings
- oanswer
->SeqBody
) + token
->ticketLen
+ KA_LABELSIZE
)
408 >= (ENCRYPTIONBLOCKSIZE
+ 12)
410 return KABADPROTOCOL
;
412 memcpy(token
->ticket
, strings
, token
->ticketLen
);
413 strings
+= token
->ticketLen
;
414 if (memcmp(strings
, label
, KA_LABELSIZE
) != 0)
415 return KABADPROTOCOL
;
419 strings
+= KA_LABELSIZE
;
420 temp
= round_up_to_ebs((strings
- oanswer
->SeqBody
));
422 if (oanswer
->SeqLen
> temp
) {
423 strings
= oanswer
->SeqBody
+ temp
;
424 memcpy(&temp
, strings
, sizeof(afs_int32
));
425 tempc
= ntohl(temp
) >> 24;
426 /* don't forget this if you add any more fields!
427 * strings += sizeof(afs_int32);
439 /* call this instead of stub and we'll guarantee to find a host that's up.
440 * this doesn't handle UNOTSYNC very well, should use ubik_Call if you care
443 kawrap_ubik_Call(int (*aproc
) (), struct ubik_client
*aclient
,
444 afs_int32 aflags
, void *p1
, void *p2
, void *p3
, void *p4
,
445 void *p5
, void *p6
, void *p7
, void *p8
)
447 afs_int32 code
, lcode
;
451 /* First pass only checks servers known running. Second checks all.
452 * Once we've cycled through all the servers and still nothing, return
453 * error code from the last server tried.
455 for (pass
= 0, aflags
|= UPUBIKONLY
; pass
< 2;
456 pass
++, aflags
&= ~UPUBIKONLY
) {
459 do { /* Cycle through the servers */
462 ubik_CallIter(aproc
, aclient
, aflags
, &count
, (long) p1
,
463 (long) p2
, (long) p3
, (long) p4
,
464 (long) p5
, (long) p6
, (long) p7
,
465 (long) p8
, 0, 0, 0, 0, 0, 0, 0, 0);
466 } while ((code
== UNOQUORUM
) || (code
== UNOTSYNC
)
467 || (code
== KALOCKED
) || (code
== -1));
469 if (code
!= UNOSERVERS
)
473 /* If cycled through all the servers, return the last error code */
474 if ((code
== UNOSERVERS
) && lcode
) {
480 /* This is the interface to the AuthServer RPC routine Authenticate. It
481 formats the request packet, calls the encryption routine on the answer,
482 calls Authenticate, and decrypts the response. The response is checked for
483 correctness and its contents are copied into the token. */
486 KABADKEY = the key failed when converted to a key schedule. Probably bad
488 KAUBIKCALL - the call to Ubik returned an error, probably a communication
489 failure such as timeout.
490 KABADPROTOCOL - the returned packet was in error. Since a packet was
491 returned it can be presumed that the AuthServer correctly interpreted
492 the response. This may indicate an inauthentic AuthServer.
493 <other> - errors generated by the server process are returned directly.
497 ka_Authenticate(char *name
, char *instance
, char *cell
, struct ubik_client
* conn
, /* Ubik connection to the AuthServer in
498 * the desired cell */
499 int service
, /* ticket granting or admin service */
500 struct ktc_encryptionKey
* key
, Date start
, Date end
, /* ticket lifetime */
501 struct ktc_token
* token
, afs_int32
* pwexpires
)
502 { /* days until it expires */
504 des_key_schedule schedule
;
506 struct ka_gettgtRequest request
;
507 struct ka_gettgtAnswer answer_old
;
508 struct ka_ticketAnswer answer
;
516 if ((code
= des_key_sched(ktc_to_cblock(key
), schedule
))) {
521 if (service
== KA_MAINTENANCE_SERVICE
) {
522 req_label
= KA_GETADM_REQ_LABEL
;
523 ans_label
= KA_GETADM_ANS_LABEL
;
524 } else if (service
== KA_TICKET_GRANTING_SERVICE
) {
525 req_label
= KA_GETTGT_REQ_LABEL
;
526 ans_label
= KA_GETTGT_ANS_LABEL
;
529 return KABADARGUMENT
;
532 request_time
= time(0);
533 request
.time
= htonl(request_time
);
534 memcpy(request
.label
, req_label
, sizeof(request
.label
));
535 arequest
.SeqLen
= sizeof(request
);
536 arequest
.SeqBody
= (char *)&request
;
537 des_pcbc_encrypt(arequest
.SeqBody
, arequest
.SeqBody
, arequest
.SeqLen
,
538 schedule
, ktc_to_cblockptr(key
), ENCRYPT
);
540 oanswer
.MaxSeqLen
= sizeof(answer
);
542 oanswer
.SeqBody
= (char *)&answer
;
546 kawrap_ubik_Call(KAA_AuthenticateV2
, conn
, 0, name
, instance
,
547 (void*)(uintptr_t)start
, (void*)(uintptr_t)end
, &arequest
, &oanswer
, 0, 0);
548 if (code
== RXGEN_OPCODE
) {
549 oanswer
.MaxSeqLen
= sizeof(answer
);
550 oanswer
.SeqBody
= (char *)&answer
;
553 ubik_KAA_Authenticate(conn
, 0, name
, instance
, start
, end
,
554 &arequest
, &oanswer
);
555 if (code
== RXGEN_OPCODE
) {
556 oanswer
.MaxSeqLen
= sizeof(answer_old
);
557 oanswer
.SeqBody
= (char *)&answer_old
;
560 ubik_KAA_Authenticate_old(conn
, 0, name
, instance
,
561 start
, end
, &arequest
, &oanswer
);
563 if (code
== RXGEN_OPCODE
) {
564 code
= KAOLDINTERFACE
;
569 if ((code
>= KAMINERROR
) && (code
<= KAMAXERROR
))
573 des_pcbc_encrypt(oanswer
.SeqBody
, oanswer
.SeqBody
, oanswer
.SeqLen
,
574 schedule
, ktc_to_cblockptr(key
), DECRYPT
);
580 struct ktc_principal caller
;
581 strcpy(caller
.name
, name
);
582 strcpy(caller
.instance
, instance
);
583 strcpy(caller
.cell
, "");
585 CheckTicketAnswer(&oanswer
, request_time
+ 1, token
, &caller
,
586 0, ans_label
, pwexpires
);
594 answer_old
.time
= ntohl(answer_old
.time
);
595 answer_old
.ticket_len
= ntohl(answer_old
.ticket_len
);
596 if ((answer_old
.time
!= request_time
+ 1)
597 || (answer_old
.ticket_len
< MINKTCTICKETLEN
)
598 || (answer_old
.ticket_len
> MAXKTCTICKETLEN
)) {
600 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
,
615 sizeof(struct ktc_encryptionKey
));
620 return KAINTERNALERROR
;
628 ka_GetToken(char *name
, char *instance
, char *cell
, char *cname
, char *cinst
, struct ubik_client
* conn
, /* Ubik conn to cell's AuthServer */
629 Date start
, Date end
, /* desired ticket lifetime */
630 struct ktc_token
* auth_token
, char *auth_domain
,
631 struct ktc_token
* token
)
633 struct ka_getTicketTimes times
;
634 struct ka_getTicketAnswer answer_old
;
635 struct ka_ticketAnswer answer
;
642 des_key_schedule schedule
;
647 aticket
.SeqLen
= auth_token
->ticketLen
;
648 aticket
.SeqBody
= auth_token
->ticket
;
650 code
= des_key_sched(ktc_to_cblock(&auth_token
->sessionKey
), schedule
);
656 times
.start
= htonl(start
);
657 times
.end
= htonl(end
);
658 des_ecb_encrypt(×
, ×
, schedule
, ENCRYPT
);
660 atimes
.SeqLen
= sizeof(times
);
661 atimes
.SeqBody
= (char *)×
;
664 oanswer
.MaxSeqLen
= sizeof(answer
);
665 oanswer
.SeqBody
= (char *)&answer
;
669 ubik_KAT_GetTicket(conn
, 0, auth_token
->kvno
, auth_domain
,
670 &aticket
, name
, instance
, &atimes
, &oanswer
);
671 if (code
== RXGEN_OPCODE
) {
672 oanswer
.SeqLen
= 0; /* this may be set by first call */
673 oanswer
.MaxSeqLen
= sizeof(answer_old
);
674 oanswer
.SeqBody
= (char *)&answer_old
;
677 ubik_KAT_GetTicket_old(conn
, 0, auth_token
->kvno
,
678 auth_domain
, &aticket
, name
, instance
, &atimes
,
680 if (code
== RXGEN_OPCODE
) {
681 code
= KAOLDINTERFACE
;
686 if ((code
>= KAMINERROR
) && (code
<= KAMAXERROR
))
691 des_pcbc_encrypt(oanswer
.SeqBody
, oanswer
.SeqBody
, oanswer
.SeqLen
,
692 schedule
, ktc_to_cblockptr(&auth_token
->sessionKey
), DECRYPT
);
697 struct ktc_principal server
;
698 strcpy(server
.name
, name
);
699 strcpy(server
.instance
, instance
);
701 CheckTicketAnswer(&oanswer
, 0, token
, 0, &server
,
702 KA_GETTICKET_ANS_LABEL
, &pwexpires
);
710 token
->startTime
= ntohl(answer_old
.startTime
);
711 token
->endTime
= ntohl(answer_old
.endTime
);
712 token
->ticketLen
= ntohl(answer_old
.ticketLen
);
713 token
->kvno
= ntohl(answer_old
.kvno
);
714 memcpy(&token
->sessionKey
, &answer_old
.sessionKey
,
715 sizeof(token
->sessionKey
));
717 if (tkt_CheckTimes(token
->startTime
, token
->endTime
, time(0)) < 0) {
719 return KABADPROTOCOL
;
721 if ((token
->ticketLen
< MINKTCTICKETLEN
)
722 || (token
->ticketLen
> MAXKTCTICKETLEN
)) {
724 return KABADPROTOCOL
;
726 strings
= answer_old
.name
;
727 len
= strlen(strings
); /* check client name */
728 if ((len
< 1) || (len
> MAXKTCNAMELEN
)) {
730 return KABADPROTOCOL
;
732 strings
+= len
+ 1; /* check client instance */
733 len
= strlen(strings
);
734 if ((len
< 0) || (len
> MAXKTCNAMELEN
)) {
736 return KABADPROTOCOL
;
739 len
= strlen(strings
); /* check client cell */
740 if ((len
< 0) || (len
> MAXKTCNAMELEN
)) {
742 return KABADPROTOCOL
;
745 len
= strlen(strings
); /* check server name */
746 if ((len
< 1) || (len
> MAXKTCNAMELEN
) || strcmp(name
, strings
)) {
748 return KABADPROTOCOL
;
751 len
= strlen(strings
); /* check server instance */
752 if ((len
< 0) || (len
> MAXKTCNAMELEN
) || strcmp(instance
, strings
)) {
754 return KABADPROTOCOL
;
758 if ((strings
- oanswer
.SeqBody
+ token
->ticketLen
) - oanswer
.SeqLen
>=
759 ENCRYPTIONBLOCKSIZE
) {
761 return KABADPROTOCOL
;
763 memcpy(token
->ticket
, strings
, token
->ticketLen
);
768 return KAINTERNALERROR
;
776 ka_ChangePassword(char *name
, char *instance
, struct ubik_client
* conn
, /* Ubik connection to the AuthServer in
777 * the desired cell */
778 struct ktc_encryptionKey
* oldkey
,
779 struct ktc_encryptionKey
* newkey
)
785 ubik_KAM_SetPassword(conn
, UBIK_CALL_NEW
, name
, instance
, 0, *(EncryptionKey
*)newkey
);