No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / dist / heimdal / appl / gssmask / gssmaestro.c
blob12b81569852c1aea1c5ae9a3364e26e261ea65c3
1 /*
2 * Copyright (c) 2006 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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.
34 #include <common.h>
35 __RCSID("$Heimdal: gssmaestro.c 21605 2007-07-17 06:51:57Z lha $"
36 "$NetBSD$");
38 static FILE *logfile;
44 struct client {
45 char *name;
46 struct sockaddr *sa;
47 socklen_t salen;
48 krb5_storage *sock;
49 int32_t capabilities;
50 char *target_name;
51 char *moniker;
52 krb5_storage *logsock;
53 int have_log;
54 #ifdef ENABLE_PTHREAD_SUPPORT
55 pthread_t thr;
56 #else
57 pid_t child;
58 #endif
61 static struct client **clients;
62 static int num_clients;
64 static int
65 init_sec_context(struct client *client,
66 int32_t *hContext, int32_t *hCred,
67 int32_t flags,
68 const char *targetname,
69 const krb5_data *itoken, krb5_data *otoken)
71 int32_t val;
72 krb5_data_zero(otoken);
73 put32(client, eInitContext);
74 put32(client, *hContext);
75 put32(client, *hCred);
76 put32(client, flags);
77 putstring(client, targetname);
78 putdata(client, *itoken);
79 ret32(client, *hContext);
80 ret32(client, val);
81 retdata(client, *otoken);
82 return val;
85 static int
86 accept_sec_context(struct client *client,
87 int32_t *hContext,
88 int32_t flags,
89 const krb5_data *itoken,
90 krb5_data *otoken,
91 int32_t *hDelegCred)
93 int32_t val;
94 krb5_data_zero(otoken);
95 put32(client, eAcceptContext);
96 put32(client, *hContext);
97 put32(client, flags);
98 putdata(client, *itoken);
99 ret32(client, *hContext);
100 ret32(client, val);
101 retdata(client, *otoken);
102 ret32(client, *hDelegCred);
103 return val;
106 static int
107 acquire_cred(struct client *client,
108 const char *username,
109 const char *password,
110 int32_t flags,
111 int32_t *hCred)
113 int32_t val;
114 put32(client, eAcquireCreds);
115 putstring(client, username);
116 putstring(client, password);
117 put32(client, flags);
118 ret32(client, val);
119 ret32(client, *hCred);
120 return val;
123 static int
124 toast_resource(struct client *client,
125 int32_t hCred)
127 int32_t val;
128 put32(client, eToastResource);
129 put32(client, hCred);
130 ret32(client, val);
131 return val;
134 static int
135 goodbye(struct client *client)
137 put32(client, eGoodBye);
138 return GSMERR_OK;
141 static int
142 get_targetname(struct client *client,
143 char **target)
145 put32(client, eGetTargetName);
146 retstring(client, *target);
147 return GSMERR_OK;
150 static int32_t
151 encrypt_token(struct client *client, int32_t hContext, int32_t flags,
152 krb5_data *in, krb5_data *out)
154 int32_t val;
155 put32(client, eEncrypt);
156 put32(client, hContext);
157 put32(client, flags);
158 put32(client, 0);
159 putdata(client, *in);
160 ret32(client, val);
161 retdata(client, *out);
162 return val;
165 static int32_t
166 decrypt_token(struct client *client, int32_t hContext, int flags,
167 krb5_data *in, krb5_data *out)
169 int32_t val;
170 put32(client, eDecrypt);
171 put32(client, hContext);
172 put32(client, flags);
173 put32(client, 0);
174 putdata(client, *in);
175 ret32(client, val);
176 retdata(client, *out);
177 return val;
180 static int32_t
181 get_mic(struct client *client, int32_t hContext,
182 krb5_data *in, krb5_data *mic)
184 int32_t val;
185 put32(client, eSign);
186 put32(client, hContext);
187 put32(client, 0);
188 put32(client, 0);
189 putdata(client, *in);
190 ret32(client, val);
191 retdata(client, *mic);
192 return val;
195 static int32_t
196 verify_mic(struct client *client, int32_t hContext,
197 krb5_data *in, krb5_data *mic)
199 int32_t val;
200 put32(client, eVerify);
201 put32(client, hContext);
202 put32(client, 0);
203 put32(client, 0);
204 putdata(client, *in);
205 putdata(client, *mic);
206 ret32(client, val);
207 return val;
211 static int32_t
212 get_version_capa(struct client *client,
213 int32_t *version, int32_t *capa,
214 char **version_str)
216 put32(client, eGetVersionAndCapabilities);
217 ret32(client, *version);
218 ret32(client, *capa);
219 retstring(client, *version_str);
220 return GSMERR_OK;
223 static int32_t
224 get_moniker(struct client *client,
225 char **moniker)
227 put32(client, eGetMoniker);
228 retstring(client, *moniker);
229 return GSMERR_OK;
232 static int
233 wait_log(struct client *c)
235 int32_t port;
236 struct sockaddr_storage sast;
237 socklen_t salen = sizeof(sast);
238 int fd, fd2, ret;
240 memset(&sast, 0, sizeof(sast));
242 assert(sizeof(sast) >= c->salen);
244 fd = socket(c->sa->sa_family, SOCK_STREAM, 0);
245 if (fd < 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);
250 if (ret < 0)
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);
258 if (ret < 0)
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);
268 if (fd2 < 0)
269 err(1, "failed to accept local socket for %s", c->moniker);
270 close(fd);
272 return fd2;
278 static int
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;
286 int step = 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) {
296 if (iDone) {
297 warnx("iPeer already done, aPeer want extra rtt");
298 val = GSMERR_ERROR;
299 goto out;
302 val = init_sec_context(ipeer, &ic, &hCred, flags|first_call,
303 apeer->target_name, &itoken, &otoken);
304 step++;
305 switch(val) {
306 case GSMERR_OK:
307 iDone = 1;
308 if (aDone)
309 continue;
310 break;
311 case GSMERR_CONTINUE_NEEDED:
312 break;
313 default:
314 warnx("iPeer %s failed with %d (step %d)",
315 ipeer->name, (int)val, step);
316 goto out;
319 if (aDone) {
320 warnx("aPeer already done, iPeer want extra rtt");
321 val = GSMERR_ERROR;
322 goto out;
325 val = accept_sec_context(apeer, &ac, flags|first_call,
326 &otoken, &itoken, &deleg);
327 step++;
328 switch(val) {
329 case GSMERR_OK:
330 aDone = 1;
331 if (iDone)
332 continue;
333 break;
334 case GSMERR_CONTINUE_NEEDED:
335 break;
336 default:
337 warnx("aPeer %s failed with %d (step %d)",
338 apeer->name, (int)val, step);
339 val = GSMERR_ERROR;
340 goto out;
342 first_call = 0;
343 val = GSMERR_OK;
346 if (iContext == NULL || val != GSMERR_OK) {
347 if (ic)
348 toast_resource(ipeer, ic);
349 if (iContext)
350 *iContext = 0;
351 } else
352 *iContext = ic;
354 if (aContext == NULL || val != GSMERR_OK) {
355 if (ac)
356 toast_resource(apeer, ac);
357 if (aContext)
358 *aContext = 0;
359 } else
360 *aContext = ac;
362 if (hDelegCred == NULL || val != GSMERR_OK) {
363 if (deleg)
364 toast_resource(apeer, deleg);
365 if (hDelegCred)
366 *hDelegCred = 0;
367 } else
368 *hDelegCred = deleg;
370 out:
371 return val;
374 static void
375 test_mic(struct client *c1, int32_t hc1, struct client *c2, int32_t hc2)
377 krb5_data msg, mic;
378 int32_t val;
380 msg.data = "foo";
381 msg.length = 3;
383 krb5_data_zero(&mic);
385 val = get_mic(c1, hc1, &msg, &mic);
386 if (val)
387 errx(1, "get_mic failed to host: %s", c1->moniker);
388 val = verify_mic(c2, hc2, &msg, &mic);
389 if (val)
390 errx(1, "verify_mic failed to host: %s", c2->moniker);
392 krb5_data_free(&mic);
395 static int32_t
396 test_wrap(struct client *c1, int32_t hc1, struct client *c2, int32_t hc2,
397 int conf)
399 krb5_data msg, wrapped, out;
400 int32_t val;
402 msg.data = "foo";
403 msg.length = 3;
405 krb5_data_zero(&wrapped);
406 krb5_data_zero(&out);
408 val = encrypt_token(c1, hc1, conf, &msg, &wrapped);
409 if (val) {
410 warnx("encrypt_token failed to host: %s", c1->moniker);
411 return val;
413 val = decrypt_token(c2, hc2, conf, &wrapped, &out);
414 if (val) {
415 krb5_data_free(&wrapped);
416 warnx("decrypt_token failed to host: %s", c2->moniker);
417 return val;
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);
423 val = GSMERR_ERROR;
424 } else if (memcmp(msg.data, out.data, msg.length) != 0) {
425 warnx("decryptd'ed token have wrong data");
426 val = GSMERR_ERROR;
429 krb5_data_free(&wrapped);
430 krb5_data_free(&out);
431 return val;
434 static int32_t
435 test_token(struct client *c1, int32_t hc1, struct client *c2, int32_t hc2)
437 int32_t val;
438 int i;
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);
444 if (val) return val;
445 val = test_wrap(c2, hc2, c1, hc1, 0);
446 if (val) return val;
447 val = test_wrap(c1, hc1, c2, hc2, 1);
448 if (val) return val;
449 val = test_wrap(c2, hc2, c1, hc1, 1);
450 if (val) return val;
452 return GSMERR_OK;
455 static int
456 log_function(void *ptr)
458 struct client *c = ptr;
459 int32_t cmd, line;
460 char *file, *string;
462 while (1) {
463 if (krb5_ret_int32(c->logsock, &cmd))
464 goto out;
466 switch (cmd) {
467 case eLogSetMoniker:
468 if (krb5_ret_string(c->logsock, &file))
469 goto out;
470 free(file);
471 break;
472 case eLogInfo:
473 case eLogFailure:
474 if (krb5_ret_string(c->logsock, &file))
475 goto out;
476 if (krb5_ret_int32(c->logsock, &line))
477 goto out;
478 if (krb5_ret_string(c->logsock, &string))
479 goto out;
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);
484 fflush(logfile);
485 free(file);
486 free(string);
487 if (krb5_store_int32(c->logsock, 0))
488 goto out;
489 break;
490 default:
491 errx(1, "client send bad log command: %d", (int)cmd);
494 out:
496 return 0;
499 static void
500 connect_client(const char *slave)
502 char *name, *port;
503 struct client *c = ecalloc(1, sizeof(*c));
504 struct addrinfo hints, *res0, *res;
505 int ret, fd;
507 name = estrdup(slave);
508 port = strchr(name, ':');
509 if (port == NULL)
510 errx(1, "port missing from %s", name);
511 *port++ = 0;
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);
520 if (ret)
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);
525 if (fd < 0)
526 continue;
527 if (connect(fd, res->ai_addr, res->ai_addrlen) < 0) {
528 close(fd);
529 fd = -1;
530 continue;
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 */
537 if (fd < 0)
538 err(1, "connect to host: %s", name);
539 freeaddrinfo(res);
541 c->sock = krb5_storage_from_fd(fd);
542 close(fd);
543 if (c->sock == NULL)
544 errx(1, "krb5_storage_from_fd");
547 int32_t version;
548 char *str = NULL;
549 get_version_capa(c, &version, &c->capabilities, &str);
550 if (str) {
551 free(str);
553 if (c->capabilities & HAS_MONIKER)
554 get_moniker(c, &c->moniker);
555 else
556 c->moniker = c->name;
557 if (c->capabilities & ISSERVER)
558 get_targetname(c, &c->target_name);
561 if (logfile) {
562 int fd;
564 printf("starting log socket to client %s\n", c->moniker);
566 fd = wait_log(c);
568 c->logsock = krb5_storage_from_fd(fd);
569 close(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);
574 #else
575 c->child = fork();
576 if (c->child == -1)
577 errx(1, "failed to fork");
578 else if (c->child == 0) {
579 log_function(c);
580 fclose(logfile);
581 exit(0);
583 #endif
587 clients = erealloc(clients, (num_clients + 1) * sizeof(*clients));
589 clients[num_clients] = c;
590 num_clients++;
592 free(name);
595 static struct client *
596 get_client(const char *slave)
598 size_t i;
599 for (i = 0; i < num_clients; i++)
600 if (strcmp(slave, clients[i]->name) == 0)
601 return clients[i];
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",
617 NULL },
618 { "slaves", 0, arg_strings, &slaves, "Slaves",
619 NULL },
620 { "log-file", 0, arg_string, &logfile_str, "Logfile",
621 NULL },
622 { "version", 0, arg_flag, &version_flag, "Print version",
623 NULL },
624 { "help", 0, arg_flag, &help_flag, NULL,
625 NULL }
628 static void
629 usage(int ret)
631 arg_printusage (args,
632 sizeof(args) / sizeof(args[0]),
633 NULL,
634 "");
635 exit (ret);
639 main(int argc, char **argv)
641 int optidx= 0;
642 char *user;
643 char *password;
644 char ***list, **p;
645 size_t num_list, i, j, k;
646 int failed = 0;
648 setprogname (argv[0]);
650 if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
651 usage (1);
653 if (help_flag)
654 usage (0);
656 if (version_flag) {
657 print_version (NULL);
658 return 0;
661 if (optidx != argc)
662 usage (1);
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);
671 *password++ = 0;
673 if (slaves.num_strings == 0)
674 errx(1, "no principals");
676 if (logfile_str) {
677 printf("open logfile %s\n", logfile_str);
678 logfile = fopen(logfile_str, "w+");
679 if (logfile == NULL)
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++) {
703 int32_t hCred, val;
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);
709 failed = 1;
710 } else
711 toast_resource(clients[i], hCred);
714 if (failed)
715 goto out;
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)
728 continue;
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);
746 if (delegCred)
747 toast_resource(c, delegCred);
748 } else {
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);
762 if (delegCred)
763 toast_resource(c, delegCred);
764 } else {
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
773 * circle.
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;
786 p = list[i];
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)
798 break;
800 for (k = 1; k < j; k++)
801 printf("\t");
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);
811 break;
814 val = test_token(client, clientC, server, serverC);
815 if (val)
816 break;
818 toast_resource(client, clientC);
819 toast_resource(server, serverC);
820 if (!delegCred) {
821 warnx("no delegated cred on %s", server->moniker);
822 break;
824 toast_resource(client, hCred);
825 hCred = delegCred;
826 client = server;
828 if (hCred)
829 toast_resource(client, hCred);
833 * Close all connections to clients
836 out:
837 printf("sending goodbye and waiting for log sockets\n");
838 for (i = 0; i < num_clients; i++) {
839 goodbye(clients[i]);
840 if (clients[i]->logsock) {
841 #ifdef ENABLE_PTHREAD_SUPPORT
842 pthread_join(&clients[i]->thr, NULL);
843 #else
844 waitpid(clients[i]->child, NULL, 0);
845 #endif
849 printf("done\n");
851 return 0;