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.
35 __RCSID("$Heimdal: gssmaestro.c 21605 2007-07-17 06:51:57Z lha $"
52 krb5_storage
*logsock
;
54 #ifdef ENABLE_PTHREAD_SUPPORT
61 static struct client
**clients
;
62 static int num_clients
;
65 init_sec_context(struct client
*client
,
66 int32_t *hContext
, int32_t *hCred
,
68 const char *targetname
,
69 const krb5_data
*itoken
, krb5_data
*otoken
)
72 krb5_data_zero(otoken
);
73 put32(client
, eInitContext
);
74 put32(client
, *hContext
);
75 put32(client
, *hCred
);
77 putstring(client
, targetname
);
78 putdata(client
, *itoken
);
79 ret32(client
, *hContext
);
81 retdata(client
, *otoken
);
86 accept_sec_context(struct client
*client
,
89 const krb5_data
*itoken
,
94 krb5_data_zero(otoken
);
95 put32(client
, eAcceptContext
);
96 put32(client
, *hContext
);
98 putdata(client
, *itoken
);
99 ret32(client
, *hContext
);
101 retdata(client
, *otoken
);
102 ret32(client
, *hDelegCred
);
107 acquire_cred(struct client
*client
,
108 const char *username
,
109 const char *password
,
114 put32(client
, eAcquireCreds
);
115 putstring(client
, username
);
116 putstring(client
, password
);
117 put32(client
, flags
);
119 ret32(client
, *hCred
);
124 toast_resource(struct client
*client
,
128 put32(client
, eToastResource
);
129 put32(client
, hCred
);
135 goodbye(struct client
*client
)
137 put32(client
, eGoodBye
);
142 get_targetname(struct client
*client
,
145 put32(client
, eGetTargetName
);
146 retstring(client
, *target
);
151 encrypt_token(struct client
*client
, int32_t hContext
, int32_t flags
,
152 krb5_data
*in
, krb5_data
*out
)
155 put32(client
, eEncrypt
);
156 put32(client
, hContext
);
157 put32(client
, flags
);
159 putdata(client
, *in
);
161 retdata(client
, *out
);
166 decrypt_token(struct client
*client
, int32_t hContext
, int flags
,
167 krb5_data
*in
, krb5_data
*out
)
170 put32(client
, eDecrypt
);
171 put32(client
, hContext
);
172 put32(client
, flags
);
174 putdata(client
, *in
);
176 retdata(client
, *out
);
181 get_mic(struct client
*client
, int32_t hContext
,
182 krb5_data
*in
, krb5_data
*mic
)
185 put32(client
, eSign
);
186 put32(client
, hContext
);
189 putdata(client
, *in
);
191 retdata(client
, *mic
);
196 verify_mic(struct client
*client
, int32_t hContext
,
197 krb5_data
*in
, krb5_data
*mic
)
200 put32(client
, eVerify
);
201 put32(client
, hContext
);
204 putdata(client
, *in
);
205 putdata(client
, *mic
);
212 get_version_capa(struct client
*client
,
213 int32_t *version
, int32_t *capa
,
216 put32(client
, eGetVersionAndCapabilities
);
217 ret32(client
, *version
);
218 ret32(client
, *capa
);
219 retstring(client
, *version_str
);
224 get_moniker(struct client
*client
,
227 put32(client
, eGetMoniker
);
228 retstring(client
, *moniker
);
233 wait_log(struct client
*c
)
236 struct sockaddr_storage sast
;
237 socklen_t salen
= sizeof(sast
);
240 memset(&sast
, 0, sizeof(sast
));
242 assert(sizeof(sast
) >= c
->salen
);
244 fd
= socket(c
->sa
->sa_family
, SOCK_STREAM
, 0);
246 err(1, "failed to build socket for %s's logging port", c
->moniker
);
248 ((struct sockaddr
*)&sast
)->sa_family
= c
->sa
->sa_family
;
249 ret
= bind(fd
, (struct sockaddr
*)&sast
, c
->salen
);
251 err(1, "failed to bind %s's logging port", c
->moniker
);
253 if (listen(fd
, SOMAXCONN
) < 0)
254 err(1, "failed to listen %s's logging port", c
->moniker
);
256 salen
= sizeof(sast
);
257 ret
= getsockname(fd
, (struct sockaddr
*)&sast
, &salen
);
259 err(1, "failed to get address of local socket for %s", c
->moniker
);
261 port
= socket_get_port((struct sockaddr
*)&sast
);
263 put32(c
, eSetLoggingSocket
);
264 put32(c
, ntohs(port
));
266 salen
= sizeof(sast
);
267 fd2
= accept(fd
, (struct sockaddr
*)&sast
, &salen
);
269 err(1, "failed to accept local socket for %s", c
->moniker
);
279 build_context(struct client
*ipeer
, struct client
*apeer
,
280 int32_t flags
, int32_t hCred
,
281 int32_t *iContext
, int32_t *aContext
, int32_t *hDelegCred
)
283 int32_t val
= GSMERR_ERROR
, ic
= 0, ac
= 0, deleg
= 0;
284 krb5_data itoken
, otoken
;
285 int iDone
= 0, aDone
= 0;
287 int first_call
= 0x80;
289 if (apeer
->target_name
== NULL
)
290 errx(1, "apeer %s have no target name", apeer
->name
);
292 krb5_data_zero(&itoken
);
294 while (!iDone
|| !aDone
) {
297 warnx("iPeer already done, aPeer want extra rtt");
302 val
= init_sec_context(ipeer
, &ic
, &hCred
, flags
|first_call
,
303 apeer
->target_name
, &itoken
, &otoken
);
311 case GSMERR_CONTINUE_NEEDED
:
314 warnx("iPeer %s failed with %d (step %d)",
315 ipeer
->name
, (int)val
, step
);
320 warnx("aPeer already done, iPeer want extra rtt");
325 val
= accept_sec_context(apeer
, &ac
, flags
|first_call
,
326 &otoken
, &itoken
, &deleg
);
334 case GSMERR_CONTINUE_NEEDED
:
337 warnx("aPeer %s failed with %d (step %d)",
338 apeer
->name
, (int)val
, step
);
346 if (iContext
== NULL
|| val
!= GSMERR_OK
) {
348 toast_resource(ipeer
, ic
);
354 if (aContext
== NULL
|| val
!= GSMERR_OK
) {
356 toast_resource(apeer
, ac
);
362 if (hDelegCred
== NULL
|| val
!= GSMERR_OK
) {
364 toast_resource(apeer
, deleg
);
375 test_mic(struct client
*c1
, int32_t hc1
, struct client
*c2
, int32_t hc2
)
383 krb5_data_zero(&mic
);
385 val
= get_mic(c1
, hc1
, &msg
, &mic
);
387 errx(1, "get_mic failed to host: %s", c1
->moniker
);
388 val
= verify_mic(c2
, hc2
, &msg
, &mic
);
390 errx(1, "verify_mic failed to host: %s", c2
->moniker
);
392 krb5_data_free(&mic
);
396 test_wrap(struct client
*c1
, int32_t hc1
, struct client
*c2
, int32_t hc2
,
399 krb5_data msg
, wrapped
, out
;
405 krb5_data_zero(&wrapped
);
406 krb5_data_zero(&out
);
408 val
= encrypt_token(c1
, hc1
, conf
, &msg
, &wrapped
);
410 warnx("encrypt_token failed to host: %s", c1
->moniker
);
413 val
= decrypt_token(c2
, hc2
, conf
, &wrapped
, &out
);
415 krb5_data_free(&wrapped
);
416 warnx("decrypt_token failed to host: %s", c2
->moniker
);
420 if (msg
.length
!= out
.length
) {
421 warnx("decrypted'ed token have wrong length (%lu != %lu)",
422 (unsigned long)msg
.length
, (unsigned long)out
.length
);
424 } else if (memcmp(msg
.data
, out
.data
, msg
.length
) != 0) {
425 warnx("decryptd'ed token have wrong data");
429 krb5_data_free(&wrapped
);
430 krb5_data_free(&out
);
435 test_token(struct client
*c1
, int32_t hc1
, struct client
*c2
, int32_t hc2
)
440 for (i
= 0; i
< 10; i
++) {
441 test_mic(c1
, hc1
, c2
, hc2
);
442 test_mic(c2
, hc2
, c1
, hc1
);
443 val
= test_wrap(c1
, hc1
, c2
, hc2
, 0);
445 val
= test_wrap(c2
, hc2
, c1
, hc1
, 0);
447 val
= test_wrap(c1
, hc1
, c2
, hc2
, 1);
449 val
= test_wrap(c2
, hc2
, c1
, hc1
, 1);
456 log_function(void *ptr
)
458 struct client
*c
= ptr
;
463 if (krb5_ret_int32(c
->logsock
, &cmd
))
468 if (krb5_ret_string(c
->logsock
, &file
))
474 if (krb5_ret_string(c
->logsock
, &file
))
476 if (krb5_ret_int32(c
->logsock
, &line
))
478 if (krb5_ret_string(c
->logsock
, &string
))
480 printf("%s:%lu: %s\n",
481 file
, (unsigned long)line
, string
);
482 fprintf(logfile
, "%s:%lu: %s\n",
483 file
, (unsigned long)line
, string
);
487 if (krb5_store_int32(c
->logsock
, 0))
491 errx(1, "client send bad log command: %d", (int)cmd
);
500 connect_client(const char *slave
)
503 struct client
*c
= ecalloc(1, sizeof(*c
));
504 struct addrinfo hints
, *res0
, *res
;
507 name
= estrdup(slave
);
508 port
= strchr(name
, ':');
510 errx(1, "port missing from %s", name
);
513 c
->name
= estrdup(slave
);
515 memset(&hints
, 0, sizeof(hints
));
516 hints
.ai_family
= PF_UNSPEC
;
517 hints
.ai_socktype
= SOCK_STREAM
;
519 ret
= getaddrinfo(name
, port
, &hints
, &res0
);
521 errx(1, "error resolving %s", name
);
523 for (res
= res0
, fd
= -1; res
; res
= res
->ai_next
) {
524 fd
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
527 if (connect(fd
, res
->ai_addr
, res
->ai_addrlen
) < 0) {
532 c
->sa
= ecalloc(1, res
->ai_addrlen
);
533 memcpy(c
->sa
, res
->ai_addr
, res
->ai_addrlen
);
534 c
->salen
= res
->ai_addrlen
;
535 break; /* okay we got one */
538 err(1, "connect to host: %s", name
);
541 c
->sock
= krb5_storage_from_fd(fd
);
544 errx(1, "krb5_storage_from_fd");
549 get_version_capa(c
, &version
, &c
->capabilities
, &str
);
553 if (c
->capabilities
& HAS_MONIKER
)
554 get_moniker(c
, &c
->moniker
);
556 c
->moniker
= c
->name
;
557 if (c
->capabilities
& ISSERVER
)
558 get_targetname(c
, &c
->target_name
);
564 printf("starting log socket to client %s\n", c
->moniker
);
568 c
->logsock
= krb5_storage_from_fd(fd
);
570 if (c
->logsock
== NULL
)
571 errx(1, "failed to create log krb5_storage");
572 #ifdef ENABLE_PTHREAD_SUPPORT
573 pthread_create(&c
->thr
, NULL
, log_function
, c
);
577 errx(1, "failed to fork");
578 else if (c
->child
== 0) {
587 clients
= erealloc(clients
, (num_clients
+ 1) * sizeof(*clients
));
589 clients
[num_clients
] = c
;
595 static struct client
*
596 get_client(const char *slave
)
599 for (i
= 0; i
< num_clients
; i
++)
600 if (strcmp(slave
, clients
[i
]->name
) == 0)
602 errx(1, "failed to find client %s", slave
);
609 static int version_flag
;
610 static int help_flag
;
611 static char *logfile_str
;
612 static getarg_strings principals
;
613 static getarg_strings slaves
;
615 struct getargs args
[] = {
616 { "principals", 0, arg_strings
, &principals
, "Test principal",
618 { "slaves", 0, arg_strings
, &slaves
, "Slaves",
620 { "log-file", 0, arg_string
, &logfile_str
, "Logfile",
622 { "version", 0, arg_flag
, &version_flag
, "Print version",
624 { "help", 0, arg_flag
, &help_flag
, NULL
,
631 arg_printusage (args
,
632 sizeof(args
) / sizeof(args
[0]),
639 main(int argc
, char **argv
)
645 size_t num_list
, i
, j
, k
;
648 setprogname (argv
[0]);
650 if (getarg (args
, sizeof(args
) / sizeof(args
[0]), argc
, argv
, &optidx
))
657 print_version (NULL
);
664 if (principals
.num_strings
== 0)
665 errx(1, "no principals");
667 user
= estrdup(principals
.strings
[0]);
668 password
= strchr(user
, ':');
669 if (password
== NULL
)
670 errx(1, "password missing from %s", user
);
673 if (slaves
.num_strings
== 0)
674 errx(1, "no principals");
677 printf("open logfile %s\n", logfile_str
);
678 logfile
= fopen(logfile_str
, "w+");
680 err(1, "failed to open: %s", logfile_str
);
687 list
= permutate_all(&slaves
, &num_list
);
690 * Set up connection to all clients
693 printf("Connecting to slaves\n");
694 for (i
= 0; i
< slaves
.num_strings
; i
++)
695 connect_client(slaves
.strings
[i
]);
698 * Test acquire credentials
701 printf("Test acquire credentials\n");
702 for (i
= 0; i
< slaves
.num_strings
; i
++) {
705 val
= acquire_cred(clients
[i
], user
, password
, 1, &hCred
);
706 if (val
!= GSMERR_OK
) {
707 warnx("Failed to acquire_cred on host %s: %d",
708 clients
[i
]->moniker
, (int)val
);
711 toast_resource(clients
[i
], hCred
);
718 * First test if all slaves can build context to them-self.
721 printf("Self context tests\n");
722 for (i
= 0; i
< num_clients
; i
++) {
723 int32_t hCred
, val
, delegCred
;
724 int32_t clientC
, serverC
;
725 struct client
*c
= clients
[i
];
727 if (c
->target_name
== NULL
)
730 printf("%s connects to self using %s\n",
731 c
->moniker
, c
->target_name
);
733 val
= acquire_cred(c
, user
, password
, 1, &hCred
);
734 if (val
!= GSMERR_OK
)
735 errx(1, "failed to acquire_cred: %d", (int)val
);
737 val
= build_context(c
, c
,
738 GSS_C_REPLAY_FLAG
|GSS_C_SEQUENCE_FLAG
|
739 GSS_C_INTEG_FLAG
|GSS_C_CONF_FLAG
|
740 GSS_C_DELEG_FLAG
|GSS_C_MUTUAL_FLAG
,
741 hCred
, &clientC
, &serverC
, &delegCred
);
742 if (val
== GSMERR_OK
) {
743 test_token(c
, clientC
, c
, serverC
);
744 toast_resource(c
, clientC
);
745 toast_resource(c
, serverC
);
747 toast_resource(c
, delegCred
);
749 warnx("build_context failed: %d", (int)val
);
755 val
= build_context(c
, c
,
756 GSS_C_INTEG_FLAG
|GSS_C_CONF_FLAG
,
757 hCred
, &clientC
, &serverC
, &delegCred
);
758 if (val
== GSMERR_OK
) {
759 test_token(c
, clientC
, c
, serverC
);
760 toast_resource(c
, clientC
);
761 toast_resource(c
, serverC
);
763 toast_resource(c
, delegCred
);
765 warnx("build_context failed: %d", (int)val
);
768 toast_resource(c
, hCred
);
771 * Build contexts though all entries in each lists, including the
772 * step from the last entry to the first, ie treat the list as a
775 * Only follow the delegated credential, but test "all"
776 * flags. (XXX only do deleg|mutual right now.
779 printf("\"All\" permutation tests\n");
781 for (i
= 0; i
< num_list
; i
++) {
782 int32_t hCred
, val
, delegCred
= 0;
783 int32_t clientC
= 0, serverC
= 0;
784 struct client
*client
, *server
;
788 client
= get_client(p
[0]);
790 val
= acquire_cred(client
, user
, password
, 1, &hCred
);
791 if (val
!= GSMERR_OK
)
792 errx(1, "failed to acquire_cred: %d", (int)val
);
794 for (j
= 1; j
< num_clients
+ 1; j
++) {
795 server
= get_client(p
[j
% num_clients
]);
797 if (server
->target_name
== NULL
)
800 for (k
= 1; k
< j
; k
++)
802 printf("%s -> %s\n", client
->moniker
, server
->moniker
);
804 val
= build_context(client
, server
,
805 GSS_C_REPLAY_FLAG
|GSS_C_SEQUENCE_FLAG
|
806 GSS_C_INTEG_FLAG
|GSS_C_CONF_FLAG
|
807 GSS_C_DELEG_FLAG
|GSS_C_MUTUAL_FLAG
,
808 hCred
, &clientC
, &serverC
, &delegCred
);
809 if (val
!= GSMERR_OK
) {
810 warnx("build_context failed: %d", (int)val
);
814 val
= test_token(client
, clientC
, server
, serverC
);
818 toast_resource(client
, clientC
);
819 toast_resource(server
, serverC
);
821 warnx("no delegated cred on %s", server
->moniker
);
824 toast_resource(client
, hCred
);
829 toast_resource(client
, hCred
);
833 * Close all connections to clients
837 printf("sending goodbye and waiting for log sockets\n");
838 for (i
= 0; i
< num_clients
; i
++) {
840 if (clients
[i
]->logsock
) {
841 #ifdef ENABLE_PTHREAD_SUPPORT
842 pthread_join(&clients
[i
]->thr
, NULL
);
844 waitpid(clients
[i
]->child
, NULL
, 0);