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 wrap_token_ext(struct client
*client
, int32_t hContext
, int32_t flags
,
181 int32_t bflags
, krb5_data
*header
, krb5_data
*in
, krb5_data
*trailer
,
185 put32(client
, eWrapExt
);
186 put32(client
, hContext
);
187 put32(client
, flags
);
188 put32(client
, bflags
);
189 putdata(client
, *header
);
190 putdata(client
, *in
);
191 putdata(client
, *trailer
);
193 retdata(client
, *out
);
198 unwrap_token_ext(struct client
*client
, int32_t hContext
, int32_t flags
,
199 int32_t bflags
, krb5_data
*header
, krb5_data
*in
, krb5_data
*trailer
,
203 put32(client
, eUnwrapExt
);
204 put32(client
, hContext
);
205 put32(client
, flags
);
206 put32(client
, bflags
);
207 putdata(client
, *header
);
208 putdata(client
, *in
);
209 putdata(client
, *trailer
);
211 retdata(client
, *out
);
216 get_mic(struct client
*client
, int32_t hContext
,
217 krb5_data
*in
, krb5_data
*mic
)
220 put32(client
, eSign
);
221 put32(client
, hContext
);
224 putdata(client
, *in
);
226 retdata(client
, *mic
);
231 verify_mic(struct client
*client
, int32_t hContext
,
232 krb5_data
*in
, krb5_data
*mic
)
235 put32(client
, eVerify
);
236 put32(client
, hContext
);
239 putdata(client
, *in
);
240 putdata(client
, *mic
);
247 get_version_capa(struct client
*client
,
248 int32_t *version
, int32_t *capa
,
251 put32(client
, eGetVersionAndCapabilities
);
252 ret32(client
, *version
);
253 ret32(client
, *capa
);
254 retstring(client
, *version_str
);
259 get_moniker(struct client
*client
,
262 put32(client
, eGetMoniker
);
263 retstring(client
, *moniker
);
268 wait_log(struct client
*c
)
271 struct sockaddr_storage sast
;
272 socklen_t salen
= sizeof(sast
);
273 krb5_socket_t sock
, sock2
;
276 memset(&sast
, 0, sizeof(sast
));
278 assert(sizeof(sast
) >= c
->salen
);
280 sock
= socket(c
->sa
->sa_family
, SOCK_STREAM
, 0);
281 if (sock
== rk_INVALID_SOCKET
)
282 err(1, "failed to build socket for %s's logging port", c
->moniker
);
284 sast
.ss_family
= c
->sa
->sa_family
;
285 ret
= bind(sock
, (struct sockaddr
*)&sast
, c
->salen
);
287 err(1, "failed to bind %s's logging port", c
->moniker
);
289 if (listen(sock
, SOMAXCONN
) < 0)
290 err(1, "failed to listen %s's logging port", c
->moniker
);
292 salen
= sizeof(sast
);
293 ret
= getsockname(sock
, (struct sockaddr
*)&sast
, &salen
);
295 err(1, "failed to get address of local socket for %s", c
->moniker
);
297 port
= socket_get_port((struct sockaddr
*)&sast
);
299 put32(c
, eSetLoggingSocket
);
300 put32(c
, ntohs(port
));
302 salen
= sizeof(sast
);
303 sock2
= accept(sock
, (struct sockaddr
*)&sast
, &salen
);
304 if (sock2
== rk_INVALID_SOCKET
)
305 err(1, "failed to accept local socket for %s", c
->moniker
);
306 rk_closesocket(sock
);
315 build_context(struct client
*ipeer
, struct client
*apeer
,
316 int32_t flags
, int32_t hCred
,
317 int32_t *iContext
, int32_t *aContext
, int32_t *hDelegCred
)
319 int32_t val
= GSMERR_ERROR
, ic
= 0, ac
= 0, deleg
= 0;
320 krb5_data itoken
, otoken
;
321 int iDone
= 0, aDone
= 0;
323 int first_call
= 0x80;
325 if (apeer
->target_name
== NULL
)
326 errx(1, "apeer %s have no target name", apeer
->name
);
328 krb5_data_zero(&itoken
);
330 while (!iDone
|| !aDone
) {
333 warnx("iPeer already done, aPeer want extra rtt");
338 val
= init_sec_context(ipeer
, &ic
, &hCred
, flags
|first_call
,
339 apeer
->target_name
, &itoken
, &otoken
);
347 case GSMERR_CONTINUE_NEEDED
:
350 warnx("iPeer %s failed with %d (step %d)",
351 ipeer
->name
, (int)val
, step
);
356 warnx("aPeer already done, iPeer want extra rtt");
361 val
= accept_sec_context(apeer
, &ac
, flags
|first_call
,
362 &otoken
, &itoken
, &deleg
);
370 case GSMERR_CONTINUE_NEEDED
:
373 warnx("aPeer %s failed with %d (step %d)",
374 apeer
->name
, (int)val
, step
);
382 if (iContext
== NULL
|| val
!= GSMERR_OK
) {
384 toast_resource(ipeer
, ic
);
390 if (aContext
== NULL
|| val
!= GSMERR_OK
) {
392 toast_resource(apeer
, ac
);
398 if (hDelegCred
== NULL
|| val
!= GSMERR_OK
) {
400 toast_resource(apeer
, deleg
);
411 test_mic(struct client
*c1
, int32_t hc1
, struct client
*c2
, int32_t hc2
)
419 krb5_data_zero(&mic
);
421 val
= get_mic(c1
, hc1
, &msg
, &mic
);
423 errx(1, "get_mic failed to host: %s", c1
->moniker
);
424 val
= verify_mic(c2
, hc2
, &msg
, &mic
);
426 errx(1, "verify_mic failed to host: %s", c2
->moniker
);
428 krb5_data_free(&mic
);
432 test_wrap(struct client
*c1
, int32_t hc1
, struct client
*c2
, int32_t hc2
,
435 krb5_data msg
, wrapped
, out
;
441 krb5_data_zero(&wrapped
);
442 krb5_data_zero(&out
);
444 val
= encrypt_token(c1
, hc1
, conf
, &msg
, &wrapped
);
446 warnx("encrypt_token failed to host: %s", c1
->moniker
);
449 val
= decrypt_token(c2
, hc2
, conf
, &wrapped
, &out
);
451 krb5_data_free(&wrapped
);
452 warnx("decrypt_token failed to host: %s", c2
->moniker
);
456 if (msg
.length
!= out
.length
) {
457 warnx("decrypted'ed token have wrong length (%lu != %lu)",
458 (unsigned long)msg
.length
, (unsigned long)out
.length
);
460 } else if (memcmp(msg
.data
, out
.data
, msg
.length
) != 0) {
461 warnx("decryptd'ed token have wrong data");
465 krb5_data_free(&wrapped
);
466 krb5_data_free(&out
);
471 test_wrap_ext(struct client
*c1
, int32_t hc1
, struct client
*c2
, int32_t hc2
,
472 int conf
, int bflags
)
474 krb5_data header
, msg
, trailer
, wrapped
, out
;
477 header
.data
= "header";
480 msg
.data
= "0123456789abcdef"; /* padded for most enctypes */
483 trailer
.data
= "trailer";
486 krb5_data_zero(&wrapped
);
487 krb5_data_zero(&out
);
489 val
= wrap_token_ext(c1
, hc1
, conf
, bflags
, &header
, &msg
, &trailer
, &wrapped
);
491 warnx("encrypt_token failed to host: %s", c1
->moniker
);
494 val
= unwrap_token_ext(c2
, hc2
, conf
, bflags
, &header
, &wrapped
, &trailer
, &out
);
496 krb5_data_free(&wrapped
);
497 warnx("decrypt_token failed to host: %s", c2
->moniker
);
501 if (msg
.length
!= out
.length
) {
502 warnx("decrypted'ed token have wrong length (%lu != %lu)",
503 (unsigned long)msg
.length
, (unsigned long)out
.length
);
505 } else if (memcmp(msg
.data
, out
.data
, msg
.length
) != 0) {
506 warnx("decryptd'ed token have wrong data");
510 krb5_data_free(&wrapped
);
511 krb5_data_free(&out
);
517 test_token(struct client
*c1
, int32_t hc1
, struct client
*c2
, int32_t hc2
, int wrap_ext
)
522 for (i
= 0; i
< 10; i
++) {
524 test_mic(c1
, hc1
, c2
, hc2
);
525 test_mic(c2
, hc2
, c1
, hc1
);
528 val
= test_wrap(c1
, hc1
, c2
, hc2
, 0);
530 val
= test_wrap(c2
, hc2
, c1
, hc1
, 0);
533 val
= test_wrap(c1
, hc1
, c2
, hc2
, 1);
535 val
= test_wrap(c2
, hc2
, c1
, hc1
, 1);
540 val
= test_wrap_ext(c1
, hc1
, c2
, hc2
, 1, 0);
542 val
= test_wrap_ext(c2
, hc2
, c1
, hc1
, 1, 0);
545 val
= test_wrap_ext(c1
, hc1
, c2
, hc2
, 1, 1);
547 val
= test_wrap_ext(c2
, hc2
, c1
, hc1
, 1, 1);
550 val
= test_wrap_ext(c1
, hc1
, c2
, hc2
, 0, 0);
552 val
= test_wrap_ext(c2
, hc2
, c1
, hc1
, 0, 0);
555 val
= test_wrap_ext(c1
, hc1
, c2
, hc2
, 0, 1);
557 val
= test_wrap_ext(c2
, hc2
, c1
, hc1
, 0, 1);
565 log_function(void *ptr
)
567 struct client
*c
= ptr
;
572 if (krb5_ret_int32(c
->logsock
, &cmd
))
577 if (krb5_ret_string(c
->logsock
, &file
))
583 if (krb5_ret_string(c
->logsock
, &file
))
585 if (krb5_ret_int32(c
->logsock
, &line
))
587 if (krb5_ret_string(c
->logsock
, &string
))
589 printf("%s:%lu: %s\n",
590 file
, (unsigned long)line
, string
);
591 fprintf(logfile
, "%s:%lu: %s\n",
592 file
, (unsigned long)line
, string
);
596 if (krb5_store_int32(c
->logsock
, 0))
600 errx(1, "client send bad log command: %d", (int)cmd
);
609 connect_client(const char *slave
)
612 struct client
*c
= ecalloc(1, sizeof(*c
));
613 struct addrinfo hints
, *res0
, *res
;
617 name
= estrdup(slave
);
618 port
= strchr(name
, ':');
620 errx(1, "port missing from %s", name
);
623 c
->name
= estrdup(slave
);
625 memset(&hints
, 0, sizeof(hints
));
626 hints
.ai_family
= PF_UNSPEC
;
627 hints
.ai_socktype
= SOCK_STREAM
;
629 ret
= getaddrinfo(name
, port
, &hints
, &res0
);
631 errx(1, "error resolving %s", name
);
633 for (res
= res0
, sock
= rk_INVALID_SOCKET
; res
; res
= res
->ai_next
) {
634 sock
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
635 if (sock
== rk_INVALID_SOCKET
)
637 if (connect(sock
, res
->ai_addr
, res
->ai_addrlen
) < 0) {
638 rk_closesocket(sock
);
639 sock
= rk_INVALID_SOCKET
;
642 c
->sa
= ecalloc(1, res
->ai_addrlen
);
643 memcpy(c
->sa
, res
->ai_addr
, res
->ai_addrlen
);
644 c
->salen
= res
->ai_addrlen
;
645 break; /* okay we got one */
647 if (sock
== rk_INVALID_SOCKET
)
648 err(1, "connect to host: %s", name
);
651 c
->sock
= krb5_storage_from_socket(sock
);
652 rk_closesocket(sock
);
654 errx(1, "krb5_storage_from_fd");
659 get_version_capa(c
, &version
, &c
->capabilities
, &str
);
663 if (c
->capabilities
& HAS_MONIKER
)
664 get_moniker(c
, &c
->moniker
);
666 c
->moniker
= c
->name
;
667 if (c
->capabilities
& ISSERVER
)
668 get_targetname(c
, &c
->target_name
);
672 printf("starting log socket to client %s\n", c
->moniker
);
676 c
->logsock
= krb5_storage_from_socket(sock
);
677 rk_closesocket(sock
);
678 if (c
->logsock
== NULL
)
679 errx(1, "failed to create log krb5_storage");
680 #ifdef ENABLE_PTHREAD_SUPPORT
681 pthread_create(&c
->thr
, NULL
, log_function
, c
);
685 errx(1, "failed to fork");
686 else if (c
->child
== 0) {
695 clients
= erealloc(clients
, (num_clients
+ 1) * sizeof(*clients
));
697 clients
[num_clients
] = c
;
703 static struct client
*
704 get_client(const char *slave
)
707 for (i
= 0; i
< num_clients
; i
++)
708 if (strcmp(slave
, clients
[i
]->name
) == 0)
710 errx(1, "failed to find client %s", slave
);
717 static int version_flag
;
718 static int help_flag
;
719 static int wrap_ext
= 0;
720 static char *logfile_str
;
721 static getarg_strings principals
;
722 static getarg_strings slaves
;
724 struct getargs args
[] = {
725 { "principals", 0, arg_strings
, &principals
, "Test principal",
727 { "slaves", 0, arg_strings
, &slaves
, "Slaves",
729 { "log-file", 0, arg_string
, &logfile_str
, "Logfile",
731 { "wrap-ext", 0, arg_flag
, &wrap_ext
, "test wrap extended",
733 { "version", 0, arg_flag
, &version_flag
, "Print version",
735 { "help", 0, arg_flag
, &help_flag
, NULL
,
742 arg_printusage (args
,
743 sizeof(args
) / sizeof(args
[0]),
750 main(int argc
, char **argv
)
756 size_t num_list
, i
, j
, k
;
759 setprogname (argv
[0]);
761 if (getarg (args
, sizeof(args
) / sizeof(args
[0]), argc
, argv
, &optidx
))
768 print_version (NULL
);
775 if (principals
.num_strings
== 0)
776 errx(1, "no principals");
778 user
= estrdup(principals
.strings
[0]);
779 password
= strchr(user
, ':');
780 if (password
== NULL
)
781 errx(1, "password missing from %s", user
);
784 if (slaves
.num_strings
== 0)
785 errx(1, "no principals");
788 printf("open logfile %s\n", logfile_str
);
789 logfile
= fopen(logfile_str
, "w+");
791 err(1, "failed to open: %s", logfile_str
);
798 list
= permutate_all(&slaves
, &num_list
);
801 * Set up connection to all clients
804 printf("Connecting to slaves\n");
805 for (i
= 0; i
< slaves
.num_strings
; i
++)
806 connect_client(slaves
.strings
[i
]);
809 * Test acquire credentials
812 printf("Test acquire credentials\n");
813 for (i
= 0; i
< slaves
.num_strings
; i
++) {
816 val
= acquire_cred(clients
[i
], user
, password
, 1, &hCred
);
817 if (val
!= GSMERR_OK
) {
818 warnx("Failed to acquire_cred on host %s: %d",
819 clients
[i
]->moniker
, (int)val
);
822 toast_resource(clients
[i
], hCred
);
829 * First test if all slaves can build context to them-self.
832 printf("Self context tests\n");
833 for (i
= 0; i
< num_clients
; i
++) {
834 int32_t hCred
, val
, delegCred
;
835 int32_t clientC
, serverC
;
836 struct client
*c
= clients
[i
];
838 if (c
->target_name
== NULL
)
841 printf("%s connects to self using %s\n",
842 c
->moniker
, c
->target_name
);
844 val
= acquire_cred(c
, user
, password
, 1, &hCred
);
845 if (val
!= GSMERR_OK
)
846 errx(1, "failed to acquire_cred: %d", (int)val
);
848 val
= build_context(c
, c
,
849 GSS_C_REPLAY_FLAG
|GSS_C_SEQUENCE_FLAG
|
850 GSS_C_INTEG_FLAG
|GSS_C_CONF_FLAG
|
851 GSS_C_DELEG_FLAG
|GSS_C_MUTUAL_FLAG
,
852 hCred
, &clientC
, &serverC
, &delegCred
);
853 if (val
== GSMERR_OK
) {
854 test_token(c
, clientC
, c
, serverC
, wrap_ext
);
855 toast_resource(c
, clientC
);
856 toast_resource(c
, serverC
);
858 toast_resource(c
, delegCred
);
860 warnx("build_context failed: %d", (int)val
);
866 val
= build_context(c
, c
,
867 GSS_C_INTEG_FLAG
|GSS_C_CONF_FLAG
,
868 hCred
, &clientC
, &serverC
, &delegCred
);
869 if (val
== GSMERR_OK
) {
870 test_token(c
, clientC
, c
, serverC
, wrap_ext
);
871 toast_resource(c
, clientC
);
872 toast_resource(c
, serverC
);
874 toast_resource(c
, delegCred
);
876 warnx("build_context failed: %d", (int)val
);
879 toast_resource(c
, hCred
);
882 * Build contexts though all entries in each lists, including the
883 * step from the last entry to the first, ie treat the list as a
886 * Only follow the delegated credential, but test "all"
887 * flags. (XXX only do deleg|mutual right now.
890 printf("\"All\" permutation tests\n");
892 for (i
= 0; i
< num_list
; i
++) {
893 int32_t hCred
, val
, delegCred
= 0;
894 int32_t clientC
= 0, serverC
= 0;
895 struct client
*client
, *server
;
899 client
= get_client(p
[0]);
901 val
= acquire_cred(client
, user
, password
, 1, &hCred
);
902 if (val
!= GSMERR_OK
)
903 errx(1, "failed to acquire_cred: %d", (int)val
);
905 for (j
= 1; j
< num_clients
+ 1; j
++) {
906 server
= get_client(p
[j
% num_clients
]);
908 if (server
->target_name
== NULL
)
911 for (k
= 1; k
< j
; k
++)
913 printf("%s -> %s\n", client
->moniker
, server
->moniker
);
915 val
= build_context(client
, server
,
916 GSS_C_REPLAY_FLAG
|GSS_C_SEQUENCE_FLAG
|
917 GSS_C_INTEG_FLAG
|GSS_C_CONF_FLAG
|
918 GSS_C_DELEG_FLAG
|GSS_C_MUTUAL_FLAG
,
919 hCred
, &clientC
, &serverC
, &delegCred
);
920 if (val
!= GSMERR_OK
) {
921 warnx("build_context failed: %d", (int)val
);
925 val
= test_token(client
, clientC
, server
, serverC
, wrap_ext
);
929 toast_resource(client
, clientC
);
930 toast_resource(server
, serverC
);
932 warnx("no delegated cred on %s", server
->moniker
);
935 toast_resource(client
, hCred
);
940 toast_resource(client
, hCred
);
944 * Close all connections to clients
948 printf("sending goodbye and waiting for log sockets\n");
949 for (i
= 0; i
< num_clients
; i
++) {
951 if (clients
[i
]->logsock
) {
952 #ifdef ENABLE_PTHREAD_SUPPORT
953 pthread_join(&clients
[i
]->thr
, NULL
);
955 waitpid(clients
[i
]->child
, NULL
, 0);