2 * Copyright (c) 2006 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of KTH nor the names of its contributors may be
18 * used to endorse or promote products derived from this software without
19 * specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
22 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51 krb5_storage
*logsock
;
53 #ifdef ENABLE_PTHREAD_SUPPORT
60 static struct client
**clients
;
61 static int num_clients
;
64 init_sec_context(struct client
*client
,
65 int32_t *hContext
, int32_t *hCred
,
67 const char *targetname
,
68 const krb5_data
*itoken
, krb5_data
*otoken
)
71 krb5_data_zero(otoken
);
72 put32(client
, eInitContext
);
73 put32(client
, *hContext
);
74 put32(client
, *hCred
);
76 putstring(client
, targetname
);
77 putdata(client
, *itoken
);
78 ret32(client
, *hContext
);
80 retdata(client
, *otoken
);
85 accept_sec_context(struct client
*client
,
88 const krb5_data
*itoken
,
93 krb5_data_zero(otoken
);
94 put32(client
, eAcceptContext
);
95 put32(client
, *hContext
);
97 putdata(client
, *itoken
);
98 ret32(client
, *hContext
);
100 retdata(client
, *otoken
);
101 ret32(client
, *hDelegCred
);
106 acquire_cred(struct client
*client
,
107 const char *username
,
108 const char *password
,
113 put32(client
, eAcquireCreds
);
114 putstring(client
, username
);
115 putstring(client
, password
);
116 put32(client
, flags
);
118 ret32(client
, *hCred
);
123 toast_resource(struct client
*client
,
127 put32(client
, eToastResource
);
128 put32(client
, hCred
);
134 goodbye(struct client
*client
)
136 put32(client
, eGoodBye
);
141 get_targetname(struct client
*client
,
144 put32(client
, eGetTargetName
);
145 retstring(client
, *target
);
150 encrypt_token(struct client
*client
, int32_t hContext
, int32_t flags
,
151 krb5_data
*in
, krb5_data
*out
)
154 put32(client
, eEncrypt
);
155 put32(client
, hContext
);
156 put32(client
, flags
);
158 putdata(client
, *in
);
160 retdata(client
, *out
);
165 decrypt_token(struct client
*client
, int32_t hContext
, int flags
,
166 krb5_data
*in
, krb5_data
*out
)
169 put32(client
, eDecrypt
);
170 put32(client
, hContext
);
171 put32(client
, flags
);
173 putdata(client
, *in
);
175 retdata(client
, *out
);
180 get_mic(struct client
*client
, int32_t hContext
,
181 krb5_data
*in
, krb5_data
*mic
)
184 put32(client
, eSign
);
185 put32(client
, hContext
);
188 putdata(client
, *in
);
190 retdata(client
, *mic
);
195 verify_mic(struct client
*client
, int32_t hContext
,
196 krb5_data
*in
, krb5_data
*mic
)
199 put32(client
, eVerify
);
200 put32(client
, hContext
);
203 putdata(client
, *in
);
204 putdata(client
, *mic
);
211 get_version_capa(struct client
*client
,
212 int32_t *version
, int32_t *capa
,
215 put32(client
, eGetVersionAndCapabilities
);
216 ret32(client
, *version
);
217 ret32(client
, *capa
);
218 retstring(client
, *version_str
);
223 get_moniker(struct client
*client
,
226 put32(client
, eGetMoniker
);
227 retstring(client
, *moniker
);
232 wait_log(struct client
*c
)
235 struct sockaddr_storage sast
;
236 socklen_t salen
= sizeof(sast
);
239 memset(&sast
, 0, sizeof(sast
));
241 assert(sizeof(sast
) >= c
->salen
);
243 fd
= socket(c
->sa
->sa_family
, SOCK_STREAM
, 0);
245 err(1, "failed to build socket for %s's logging port", c
->moniker
);
247 ((struct sockaddr
*)&sast
)->sa_family
= c
->sa
->sa_family
;
248 ret
= bind(fd
, (struct sockaddr
*)&sast
, c
->salen
);
250 err(1, "failed to bind %s's logging port", c
->moniker
);
252 if (listen(fd
, SOMAXCONN
) < 0)
253 err(1, "failed to listen %s's logging port", c
->moniker
);
255 salen
= sizeof(sast
);
256 ret
= getsockname(fd
, (struct sockaddr
*)&sast
, &salen
);
258 err(1, "failed to get address of local socket for %s", c
->moniker
);
260 port
= socket_get_port((struct sockaddr
*)&sast
);
262 put32(c
, eSetLoggingSocket
);
263 put32(c
, ntohs(port
));
265 salen
= sizeof(sast
);
266 fd2
= accept(fd
, (struct sockaddr
*)&sast
, &salen
);
268 err(1, "failed to accept local socket for %s", c
->moniker
);
278 build_context(struct client
*ipeer
, struct client
*apeer
,
279 int32_t flags
, int32_t hCred
,
280 int32_t *iContext
, int32_t *aContext
, int32_t *hDelegCred
)
282 int32_t val
= GSMERR_ERROR
, ic
= 0, ac
= 0, deleg
= 0;
283 krb5_data itoken
, otoken
;
284 int iDone
= 0, aDone
= 0;
286 int first_call
= 0x80;
288 if (apeer
->target_name
== NULL
)
289 errx(1, "apeer %s have no target name", apeer
->name
);
291 krb5_data_zero(&itoken
);
293 while (!iDone
|| !aDone
) {
296 warnx("iPeer already done, aPeer want extra rtt");
301 val
= init_sec_context(ipeer
, &ic
, &hCred
, flags
|first_call
,
302 apeer
->target_name
, &itoken
, &otoken
);
310 case GSMERR_CONTINUE_NEEDED
:
313 warnx("iPeer %s failed with %d (step %d)",
314 ipeer
->name
, (int)val
, step
);
319 warnx("aPeer already done, iPeer want extra rtt");
324 val
= accept_sec_context(apeer
, &ac
, flags
|first_call
,
325 &otoken
, &itoken
, &deleg
);
333 case GSMERR_CONTINUE_NEEDED
:
336 warnx("aPeer %s failed with %d (step %d)",
337 apeer
->name
, (int)val
, step
);
345 if (iContext
== NULL
|| val
!= GSMERR_OK
) {
347 toast_resource(ipeer
, ic
);
353 if (aContext
== NULL
|| val
!= GSMERR_OK
) {
355 toast_resource(apeer
, ac
);
361 if (hDelegCred
== NULL
|| val
!= GSMERR_OK
) {
363 toast_resource(apeer
, deleg
);
374 test_mic(struct client
*c1
, int32_t hc1
, struct client
*c2
, int32_t hc2
)
382 krb5_data_zero(&mic
);
384 val
= get_mic(c1
, hc1
, &msg
, &mic
);
386 errx(1, "get_mic failed to host: %s", c1
->moniker
);
387 val
= verify_mic(c2
, hc2
, &msg
, &mic
);
389 errx(1, "verify_mic failed to host: %s", c2
->moniker
);
391 krb5_data_free(&mic
);
395 test_wrap(struct client
*c1
, int32_t hc1
, struct client
*c2
, int32_t hc2
,
398 krb5_data msg
, wrapped
, out
;
404 krb5_data_zero(&wrapped
);
405 krb5_data_zero(&out
);
407 val
= encrypt_token(c1
, hc1
, conf
, &msg
, &wrapped
);
409 warnx("encrypt_token failed to host: %s", c1
->moniker
);
412 val
= decrypt_token(c2
, hc2
, conf
, &wrapped
, &out
);
414 krb5_data_free(&wrapped
);
415 warnx("decrypt_token failed to host: %s", c2
->moniker
);
419 if (msg
.length
!= out
.length
) {
420 warnx("decrypted'ed token have wrong length (%lu != %lu)",
421 (unsigned long)msg
.length
, (unsigned long)out
.length
);
423 } else if (memcmp(msg
.data
, out
.data
, msg
.length
) != 0) {
424 warnx("decryptd'ed token have wrong data");
428 krb5_data_free(&wrapped
);
429 krb5_data_free(&out
);
434 test_token(struct client
*c1
, int32_t hc1
, struct client
*c2
, int32_t hc2
)
439 for (i
= 0; i
< 10; i
++) {
440 test_mic(c1
, hc1
, c2
, hc2
);
441 test_mic(c2
, hc2
, c1
, hc1
);
442 val
= test_wrap(c1
, hc1
, c2
, hc2
, 0);
444 val
= test_wrap(c2
, hc2
, c1
, hc1
, 0);
446 val
= test_wrap(c1
, hc1
, c2
, hc2
, 1);
448 val
= test_wrap(c2
, hc2
, c1
, hc1
, 1);
455 log_function(void *ptr
)
457 struct client
*c
= ptr
;
462 if (krb5_ret_int32(c
->logsock
, &cmd
))
467 if (krb5_ret_string(c
->logsock
, &file
))
473 if (krb5_ret_string(c
->logsock
, &file
))
475 if (krb5_ret_int32(c
->logsock
, &line
))
477 if (krb5_ret_string(c
->logsock
, &string
))
479 printf("%s:%lu: %s\n",
480 file
, (unsigned long)line
, string
);
481 fprintf(logfile
, "%s:%lu: %s\n",
482 file
, (unsigned long)line
, string
);
486 if (krb5_store_int32(c
->logsock
, 0))
490 errx(1, "client send bad log command: %d", (int)cmd
);
499 connect_client(const char *slave
)
502 struct client
*c
= ecalloc(1, sizeof(*c
));
503 struct addrinfo hints
, *res0
, *res
;
506 name
= estrdup(slave
);
507 port
= strchr(name
, ':');
509 errx(1, "port missing from %s", name
);
512 c
->name
= estrdup(slave
);
514 memset(&hints
, 0, sizeof(hints
));
515 hints
.ai_family
= PF_UNSPEC
;
516 hints
.ai_socktype
= SOCK_STREAM
;
518 ret
= getaddrinfo(name
, port
, &hints
, &res0
);
520 errx(1, "error resolving %s", name
);
522 for (res
= res0
, fd
= -1; res
; res
= res
->ai_next
) {
523 fd
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
526 if (connect(fd
, res
->ai_addr
, res
->ai_addrlen
) < 0) {
531 c
->sa
= ecalloc(1, res
->ai_addrlen
);
532 memcpy(c
->sa
, res
->ai_addr
, res
->ai_addrlen
);
533 c
->salen
= res
->ai_addrlen
;
534 break; /* okay we got one */
537 err(1, "connect to host: %s", name
);
540 c
->sock
= krb5_storage_from_fd(fd
);
543 errx(1, "krb5_storage_from_fd");
548 get_version_capa(c
, &version
, &c
->capabilities
, &str
);
552 if (c
->capabilities
& HAS_MONIKER
)
553 get_moniker(c
, &c
->moniker
);
555 c
->moniker
= c
->name
;
556 if (c
->capabilities
& ISSERVER
)
557 get_targetname(c
, &c
->target_name
);
563 printf("starting log socket to client %s\n", c
->moniker
);
567 c
->logsock
= krb5_storage_from_fd(fd
);
569 if (c
->logsock
== NULL
)
570 errx(1, "failed to create log krb5_storage");
571 #ifdef ENABLE_PTHREAD_SUPPORT
572 pthread_create(&c
->thr
, NULL
, log_function
, c
);
576 errx(1, "failed to fork");
577 else if (c
->child
== 0) {
586 clients
= erealloc(clients
, (num_clients
+ 1) * sizeof(*clients
));
588 clients
[num_clients
] = c
;
594 static struct client
*
595 get_client(const char *slave
)
598 for (i
= 0; i
< num_clients
; i
++)
599 if (strcmp(slave
, clients
[i
]->name
) == 0)
601 errx(1, "failed to find client %s", slave
);
608 static int version_flag
;
609 static int help_flag
;
610 static char *logfile_str
;
611 static getarg_strings principals
;
612 static getarg_strings slaves
;
614 struct getargs args
[] = {
615 { "principals", 0, arg_strings
, &principals
, "Test principal",
617 { "slaves", 0, arg_strings
, &slaves
, "Slaves",
619 { "log-file", 0, arg_string
, &logfile_str
, "Logfile",
621 { "version", 0, arg_flag
, &version_flag
, "Print version",
623 { "help", 0, arg_flag
, &help_flag
, NULL
,
630 arg_printusage (args
,
631 sizeof(args
) / sizeof(args
[0]),
638 main(int argc
, char **argv
)
644 size_t num_list
, i
, j
, k
;
647 setprogname (argv
[0]);
649 if (getarg (args
, sizeof(args
) / sizeof(args
[0]), argc
, argv
, &optidx
))
656 print_version (NULL
);
663 if (principals
.num_strings
== 0)
664 errx(1, "no principals");
666 user
= estrdup(principals
.strings
[0]);
667 password
= strchr(user
, ':');
668 if (password
== NULL
)
669 errx(1, "password missing from %s", user
);
672 if (slaves
.num_strings
== 0)
673 errx(1, "no principals");
676 printf("open logfile %s\n", logfile_str
);
677 logfile
= fopen(logfile_str
, "w+");
679 err(1, "failed to open: %s", logfile_str
);
686 list
= permutate_all(&slaves
, &num_list
);
689 * Set up connection to all clients
692 printf("Connecting to slaves\n");
693 for (i
= 0; i
< slaves
.num_strings
; i
++)
694 connect_client(slaves
.strings
[i
]);
697 * Test acquire credentials
700 printf("Test acquire credentials\n");
701 for (i
= 0; i
< slaves
.num_strings
; i
++) {
704 val
= acquire_cred(clients
[i
], user
, password
, 1, &hCred
);
705 if (val
!= GSMERR_OK
) {
706 warnx("Failed to acquire_cred on host %s: %d",
707 clients
[i
]->moniker
, (int)val
);
710 toast_resource(clients
[i
], hCred
);
717 * First test if all slaves can build context to them-self.
720 printf("Self context tests\n");
721 for (i
= 0; i
< num_clients
; i
++) {
722 int32_t hCred
, val
, delegCred
;
723 int32_t clientC
, serverC
;
724 struct client
*c
= clients
[i
];
726 if (c
->target_name
== NULL
)
729 printf("%s connects to self using %s\n",
730 c
->moniker
, c
->target_name
);
732 val
= acquire_cred(c
, user
, password
, 1, &hCred
);
733 if (val
!= GSMERR_OK
)
734 errx(1, "failed to acquire_cred: %d", (int)val
);
736 val
= build_context(c
, c
,
737 GSS_C_REPLAY_FLAG
|GSS_C_SEQUENCE_FLAG
|
738 GSS_C_INTEG_FLAG
|GSS_C_CONF_FLAG
|
739 GSS_C_DELEG_FLAG
|GSS_C_MUTUAL_FLAG
,
740 hCred
, &clientC
, &serverC
, &delegCred
);
741 if (val
== GSMERR_OK
) {
742 test_token(c
, clientC
, c
, serverC
);
743 toast_resource(c
, clientC
);
744 toast_resource(c
, serverC
);
746 toast_resource(c
, delegCred
);
748 warnx("build_context failed: %d", (int)val
);
754 val
= build_context(c
, c
,
755 GSS_C_INTEG_FLAG
|GSS_C_CONF_FLAG
,
756 hCred
, &clientC
, &serverC
, &delegCred
);
757 if (val
== GSMERR_OK
) {
758 test_token(c
, clientC
, c
, serverC
);
759 toast_resource(c
, clientC
);
760 toast_resource(c
, serverC
);
762 toast_resource(c
, delegCred
);
764 warnx("build_context failed: %d", (int)val
);
767 toast_resource(c
, hCred
);
770 * Build contexts though all entries in each lists, including the
771 * step from the last entry to the first, ie treat the list as a
774 * Only follow the delegated credential, but test "all"
775 * flags. (XXX only do deleg|mutual right now.
778 printf("\"All\" permutation tests\n");
780 for (i
= 0; i
< num_list
; i
++) {
781 int32_t hCred
, val
, delegCred
= 0;
782 int32_t clientC
= 0, serverC
= 0;
783 struct client
*client
, *server
;
787 client
= get_client(p
[0]);
789 val
= acquire_cred(client
, user
, password
, 1, &hCred
);
790 if (val
!= GSMERR_OK
)
791 errx(1, "failed to acquire_cred: %d", (int)val
);
793 for (j
= 1; j
< num_clients
+ 1; j
++) {
794 server
= get_client(p
[j
% num_clients
]);
796 if (server
->target_name
== NULL
)
799 for (k
= 1; k
< j
; k
++)
801 printf("%s -> %s\n", client
->moniker
, server
->moniker
);
803 val
= build_context(client
, server
,
804 GSS_C_REPLAY_FLAG
|GSS_C_SEQUENCE_FLAG
|
805 GSS_C_INTEG_FLAG
|GSS_C_CONF_FLAG
|
806 GSS_C_DELEG_FLAG
|GSS_C_MUTUAL_FLAG
,
807 hCred
, &clientC
, &serverC
, &delegCred
);
808 if (val
!= GSMERR_OK
) {
809 warnx("build_context failed: %d", (int)val
);
813 val
= test_token(client
, clientC
, server
, serverC
);
817 toast_resource(client
, clientC
);
818 toast_resource(server
, serverC
);
820 warnx("no delegated cred on %s", server
->moniker
);
823 toast_resource(client
, hCred
);
828 toast_resource(client
, hCred
);
832 * Close all connections to clients
836 printf("sending goodbye and waiting for log sockets\n");
837 for (i
= 0; i
< num_clients
; i
++) {
839 if (clients
[i
]->logsock
) {
840 #ifdef ENABLE_PTHREAD_SUPPORT
841 pthread_join(&clients
[i
]->thr
, NULL
);
843 waitpid(clients
[i
]->child
, NULL
, 0);