]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - crypto/heimdal/appl/gssmask/gssmaestro.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / crypto / heimdal / appl / gssmask / gssmaestro.c
1 /*
2  * Copyright (c) 2006 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
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.
16  *
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.
20  *
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.
32  */
33
34 #include <common.h>
35 RCSID("$Id$");
36
37 static FILE *logfile;
38
39 /*
40  *
41  */
42
43 struct client {
44     char *name;
45     struct sockaddr *sa;
46     socklen_t salen;
47     krb5_storage *sock;
48     int32_t capabilities;
49     char *target_name;
50     char *moniker;
51     krb5_storage *logsock;
52     int have_log;
53 #ifdef ENABLE_PTHREAD_SUPPORT
54     pthread_t thr;
55 #else
56     pid_t child;
57 #endif
58 };
59
60 static struct client **clients;
61 static int num_clients;
62
63 static int
64 init_sec_context(struct client *client,
65                  int32_t *hContext, int32_t *hCred,
66                  int32_t flags,
67                  const char *targetname,
68                  const krb5_data *itoken, krb5_data *otoken)
69 {
70     int32_t val;
71     krb5_data_zero(otoken);
72     put32(client, eInitContext);
73     put32(client, *hContext);
74     put32(client, *hCred);
75     put32(client, flags);
76     putstring(client, targetname);
77     putdata(client, *itoken);
78     ret32(client, *hContext);
79     ret32(client, val);
80     retdata(client, *otoken);
81     return val;
82 }
83
84 static int
85 accept_sec_context(struct client *client,
86                    int32_t *hContext,
87                    int32_t flags,
88                    const krb5_data *itoken,
89                    krb5_data *otoken,
90                    int32_t *hDelegCred)
91 {
92     int32_t val;
93     krb5_data_zero(otoken);
94     put32(client, eAcceptContext);
95     put32(client, *hContext);
96     put32(client, flags);
97     putdata(client, *itoken);
98     ret32(client, *hContext);
99     ret32(client, val);
100     retdata(client, *otoken);
101     ret32(client, *hDelegCred);
102     return val;
103 }
104
105 static int
106 acquire_cred(struct client *client,
107              const char *username,
108              const char *password,
109              int32_t flags,
110              int32_t *hCred)
111 {
112     int32_t val;
113     put32(client, eAcquireCreds);
114     putstring(client, username);
115     putstring(client, password);
116     put32(client, flags);
117     ret32(client, val);
118     ret32(client, *hCred);
119     return val;
120 }
121
122 static int
123 toast_resource(struct client *client,
124                int32_t hCred)
125 {
126     int32_t val;
127     put32(client, eToastResource);
128     put32(client, hCred);
129     ret32(client, val);
130     return val;
131 }
132
133 static int
134 goodbye(struct client *client)
135 {
136     put32(client, eGoodBye);
137     return GSMERR_OK;
138 }
139
140 static int
141 get_targetname(struct client *client,
142                char **target)
143 {
144     put32(client, eGetTargetName);
145     retstring(client, *target);
146     return GSMERR_OK;
147 }
148
149 static int32_t
150 encrypt_token(struct client *client, int32_t hContext, int32_t flags,
151            krb5_data *in, krb5_data *out)
152 {
153     int32_t val;
154     put32(client, eEncrypt);
155     put32(client, hContext);
156     put32(client, flags);
157     put32(client, 0);
158     putdata(client, *in);
159     ret32(client, val);
160     retdata(client, *out);
161     return val;
162 }
163
164 static int32_t
165 decrypt_token(struct client *client, int32_t hContext, int flags,
166              krb5_data *in, krb5_data *out)
167 {
168     int32_t val;
169     put32(client, eDecrypt);
170     put32(client, hContext);
171     put32(client, flags);
172     put32(client, 0);
173     putdata(client, *in);
174     ret32(client, val);
175     retdata(client, *out);
176     return val;
177 }
178
179 static int32_t
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,
182                krb5_data *out)
183 {
184     int32_t val;
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);
192     ret32(client, val);
193     retdata(client, *out);
194     return val;
195 }
196
197 static int32_t
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,
200                krb5_data *out)
201 {
202     int32_t val;
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);
210     ret32(client, val);
211     retdata(client, *out);
212     return val;
213 }
214
215 static int32_t
216 get_mic(struct client *client, int32_t hContext,
217         krb5_data *in, krb5_data *mic)
218 {
219     int32_t val;
220     put32(client, eSign);
221     put32(client, hContext);
222     put32(client, 0);
223     put32(client, 0);
224     putdata(client, *in);
225     ret32(client, val);
226     retdata(client, *mic);
227     return val;
228 }
229
230 static int32_t
231 verify_mic(struct client *client, int32_t hContext,
232            krb5_data *in, krb5_data *mic)
233 {
234     int32_t val;
235     put32(client, eVerify);
236     put32(client, hContext);
237     put32(client, 0);
238     put32(client, 0);
239     putdata(client, *in);
240     putdata(client, *mic);
241     ret32(client, val);
242     return val;
243 }
244
245
246 static int32_t
247 get_version_capa(struct client *client,
248                  int32_t *version, int32_t *capa,
249                  char **version_str)
250 {
251     put32(client, eGetVersionAndCapabilities);
252     ret32(client, *version);
253     ret32(client, *capa);
254     retstring(client, *version_str);
255     return GSMERR_OK;
256 }
257
258 static int32_t
259 get_moniker(struct client *client,
260             char **moniker)
261 {
262     put32(client, eGetMoniker);
263     retstring(client, *moniker);
264     return GSMERR_OK;
265 }
266
267 static int
268 wait_log(struct client *c)
269 {
270     int32_t port;
271     struct sockaddr_storage sast;
272     socklen_t salen = sizeof(sast);
273     int fd, fd2, ret;
274
275     memset(&sast, 0, sizeof(sast));
276
277     assert(sizeof(sast) >= c->salen);
278
279     fd = socket(c->sa->sa_family, SOCK_STREAM, 0);
280     if (fd < 0)
281         err(1, "failed to build socket for %s's logging port", c->moniker);
282
283     ((struct sockaddr *)&sast)->sa_family = c->sa->sa_family;
284     ret = bind(fd, (struct sockaddr *)&sast, c->salen);
285     if (ret < 0)
286         err(1, "failed to bind %s's logging port", c->moniker);
287
288     if (listen(fd, SOMAXCONN) < 0)
289         err(1, "failed to listen %s's logging port", c->moniker);
290
291     salen = sizeof(sast);
292     ret = getsockname(fd, (struct sockaddr *)&sast, &salen);
293     if (ret < 0)
294         err(1, "failed to get address of local socket for %s", c->moniker);
295
296     port = socket_get_port((struct sockaddr *)&sast);
297
298     put32(c, eSetLoggingSocket);
299     put32(c, ntohs(port));
300
301     salen = sizeof(sast);
302     fd2 = accept(fd, (struct sockaddr *)&sast, &salen);
303     if (fd2 < 0)
304         err(1, "failed to accept local socket for %s", c->moniker);
305     close(fd);
306
307     return fd2;
308 }
309
310
311
312
313 static int
314 build_context(struct client *ipeer, struct client *apeer,
315               int32_t flags, int32_t hCred,
316               int32_t *iContext, int32_t *aContext, int32_t *hDelegCred)
317 {
318     int32_t val = GSMERR_ERROR, ic = 0, ac = 0, deleg = 0;
319     krb5_data itoken, otoken;
320     int iDone = 0, aDone = 0;
321     int step = 0;
322     int first_call = 0x80;
323
324     if (apeer->target_name == NULL)
325         errx(1, "apeer %s have no target name", apeer->name);
326
327     krb5_data_zero(&itoken);
328
329     while (!iDone || !aDone) {
330
331         if (iDone) {
332             warnx("iPeer already done, aPeer want extra rtt");
333             val = GSMERR_ERROR;
334             goto out;
335         }
336
337         val = init_sec_context(ipeer, &ic, &hCred, flags|first_call,
338                                apeer->target_name, &itoken, &otoken);
339         step++;
340         switch(val) {
341         case GSMERR_OK:
342             iDone = 1;
343             if (aDone)
344                 continue;
345             break;
346         case GSMERR_CONTINUE_NEEDED:
347             break;
348         default:
349             warnx("iPeer %s failed with %d (step %d)",
350                   ipeer->name, (int)val, step);
351             goto out;
352         }
353
354         if (aDone) {
355             warnx("aPeer already done, iPeer want extra rtt");
356             val = GSMERR_ERROR;
357             goto out;
358         }
359
360         val = accept_sec_context(apeer, &ac, flags|first_call,
361                                  &otoken, &itoken, &deleg);
362         step++;
363         switch(val) {
364         case GSMERR_OK:
365             aDone = 1;
366             if (iDone)
367                 continue;
368             break;
369         case GSMERR_CONTINUE_NEEDED:
370             break;
371         default:
372             warnx("aPeer %s failed with %d (step %d)",
373                  apeer->name, (int)val, step);
374             val = GSMERR_ERROR;
375             goto out;
376         }
377         first_call = 0;
378         val = GSMERR_OK;
379     }
380
381     if (iContext == NULL || val != GSMERR_OK) {
382         if (ic)
383             toast_resource(ipeer, ic);
384         if (iContext)
385             *iContext = 0;
386     } else
387         *iContext = ic;
388
389     if (aContext == NULL || val != GSMERR_OK) {
390         if (ac)
391             toast_resource(apeer, ac);
392         if (aContext)
393             *aContext = 0;
394     } else
395         *aContext = ac;
396
397     if (hDelegCred == NULL || val != GSMERR_OK) {
398         if (deleg)
399             toast_resource(apeer, deleg);
400         if (hDelegCred)
401             *hDelegCred = 0;
402     } else
403         *hDelegCred = deleg;
404
405 out:
406     return val;
407 }
408
409 static void
410 test_mic(struct client *c1, int32_t hc1, struct client *c2, int32_t hc2)
411 {
412     krb5_data msg, mic;
413     int32_t val;
414
415     msg.data = "foo";
416     msg.length = 3;
417
418     krb5_data_zero(&mic);
419
420     val = get_mic(c1, hc1, &msg, &mic);
421     if (val)
422         errx(1, "get_mic failed to host: %s", c1->moniker);
423     val = verify_mic(c2, hc2, &msg, &mic);
424     if (val)
425         errx(1, "verify_mic failed to host: %s", c2->moniker);
426
427     krb5_data_free(&mic);
428 }
429
430 static int32_t
431 test_wrap(struct client *c1, int32_t hc1, struct client *c2, int32_t hc2,
432           int conf)
433 {
434     krb5_data msg, wrapped, out;
435     int32_t val;
436
437     msg.data = "foo";
438     msg.length = 3;
439
440     krb5_data_zero(&wrapped);
441     krb5_data_zero(&out);
442
443     val = encrypt_token(c1, hc1, conf, &msg, &wrapped);
444     if (val) {
445         warnx("encrypt_token failed to host: %s", c1->moniker);
446         return val;
447     }
448     val = decrypt_token(c2, hc2, conf, &wrapped, &out);
449     if (val) {
450         krb5_data_free(&wrapped);
451         warnx("decrypt_token failed to host: %s", c2->moniker);
452         return val;
453     }
454
455     if (msg.length != out.length) {
456         warnx("decrypted'ed token have wrong length (%lu != %lu)",
457               (unsigned long)msg.length, (unsigned long)out.length);
458         val = GSMERR_ERROR;
459     } else if (memcmp(msg.data, out.data, msg.length) != 0) {
460         warnx("decryptd'ed token have wrong data");
461         val = GSMERR_ERROR;
462     }
463
464     krb5_data_free(&wrapped);
465     krb5_data_free(&out);
466     return val;
467 }
468
469 static int32_t
470 test_wrap_ext(struct client *c1, int32_t hc1, struct client *c2, int32_t hc2,
471               int conf, int bflags)
472 {
473     krb5_data header, msg, trailer, wrapped, out;
474     int32_t val;
475
476     header.data = "header";
477     header.length = 6;
478
479     msg.data = "0123456789abcdef"; /* padded for most enctypes */
480     msg.length = 32;
481
482     trailer.data = "trailer";
483     trailer.length = 7;
484
485     krb5_data_zero(&wrapped);
486     krb5_data_zero(&out);
487
488     val = wrap_token_ext(c1, hc1, conf, bflags, &header, &msg, &trailer, &wrapped);
489     if (val) {
490         warnx("encrypt_token failed to host: %s", c1->moniker);
491         return val;
492     }
493     val = unwrap_token_ext(c2, hc2, conf, bflags, &header, &wrapped, &trailer, &out);
494     if (val) {
495         krb5_data_free(&wrapped);
496         warnx("decrypt_token failed to host: %s", c2->moniker);
497         return val;
498     }
499
500     if (msg.length != out.length) {
501         warnx("decrypted'ed token have wrong length (%lu != %lu)",
502               (unsigned long)msg.length, (unsigned long)out.length);
503         val = GSMERR_ERROR;
504     } else if (memcmp(msg.data, out.data, msg.length) != 0) {
505         warnx("decryptd'ed token have wrong data");
506         val = GSMERR_ERROR;
507     }
508
509     krb5_data_free(&wrapped);
510     krb5_data_free(&out);
511     return val;
512 }
513
514
515 static int32_t
516 test_token(struct client *c1, int32_t hc1, struct client *c2, int32_t hc2, int wrap_ext)
517 {
518     int32_t val;
519     int i;
520
521     for (i = 0; i < 10; i++) {
522         /* mic */
523         test_mic(c1, hc1, c2, hc2);
524         test_mic(c2, hc2, c1, hc1);
525
526         /* wrap */
527         val = test_wrap(c1, hc1, c2, hc2, 0);
528         if (val) return val;
529         val = test_wrap(c2, hc2, c1, hc1, 0);
530         if (val) return val;
531
532         val = test_wrap(c1, hc1, c2, hc2, 1);
533         if (val) return val;
534         val = test_wrap(c2, hc2, c1, hc1, 1);
535         if (val) return val;
536
537         if (wrap_ext) {
538             /* wrap ext */
539             val = test_wrap_ext(c1, hc1, c2, hc2, 1, 0);
540             if (val) return val;
541             val = test_wrap_ext(c2, hc2, c1, hc1, 1, 0);
542             if (val) return val;
543
544             val = test_wrap_ext(c1, hc1, c2, hc2, 1, 1);
545             if (val) return val;
546             val = test_wrap_ext(c2, hc2, c1, hc1, 1, 1);
547             if (val) return val;
548
549             val = test_wrap_ext(c1, hc1, c2, hc2, 0, 0);
550             if (val) return val;
551             val = test_wrap_ext(c2, hc2, c1, hc1, 0, 0);
552             if (val) return val;
553
554             val = test_wrap_ext(c1, hc1, c2, hc2, 0, 1);
555             if (val) return val;
556             val = test_wrap_ext(c2, hc2, c1, hc1, 0, 1);
557             if (val) return val;
558         }
559     }
560     return GSMERR_OK;
561 }
562
563 static int
564 log_function(void *ptr)
565 {
566     struct client *c = ptr;
567     int32_t cmd, line;
568     char *file, *string;
569
570     while (1) {
571         if (krb5_ret_int32(c->logsock, &cmd))
572             goto out;
573
574         switch (cmd) {
575         case eLogSetMoniker:
576             if (krb5_ret_string(c->logsock, &file))
577                 goto out;
578             free(file);
579             break;
580         case eLogInfo:
581         case eLogFailure:
582             if (krb5_ret_string(c->logsock, &file))
583                 goto out;
584             if (krb5_ret_int32(c->logsock, &line))
585                 goto out;
586             if (krb5_ret_string(c->logsock, &string))
587                 goto out;
588             printf("%s:%lu: %s\n",
589                    file, (unsigned long)line, string);
590             fprintf(logfile, "%s:%lu: %s\n",
591                     file, (unsigned long)line, string);
592             fflush(logfile);
593             free(file);
594             free(string);
595             if (krb5_store_int32(c->logsock, 0))
596                 goto out;
597             break;
598         default:
599             errx(1, "client send bad log command: %d", (int)cmd);
600         }
601     }
602 out:
603
604     return 0;
605 }
606
607 static void
608 connect_client(const char *slave)
609 {
610     char *name, *port;
611     struct client *c = ecalloc(1, sizeof(*c));
612     struct addrinfo hints, *res0, *res;
613     int ret, fd;
614
615     name = estrdup(slave);
616     port = strchr(name, ':');
617     if (port == NULL)
618         errx(1, "port missing from %s", name);
619     *port++ = 0;
620
621     c->name = estrdup(slave);
622
623     memset(&hints, 0, sizeof(hints));
624     hints.ai_family = PF_UNSPEC;
625     hints.ai_socktype = SOCK_STREAM;
626
627     ret = getaddrinfo(name, port, &hints, &res0);
628     if (ret)
629         errx(1, "error resolving %s", name);
630
631     for (res = res0, fd = -1; res; res = res->ai_next) {
632         fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
633         if (fd < 0)
634             continue;
635         if (connect(fd, res->ai_addr, res->ai_addrlen) < 0) {
636             close(fd);
637             fd = -1;
638             continue;
639         }
640         c->sa = ecalloc(1, res->ai_addrlen);
641         memcpy(c->sa, res->ai_addr, res->ai_addrlen);
642         c->salen = res->ai_addrlen;
643         break;  /* okay we got one */
644     }
645     if (fd < 0)
646         err(1, "connect to host: %s", name);
647     freeaddrinfo(res);
648
649     c->sock = krb5_storage_from_fd(fd);
650     close(fd);
651     if (c->sock == NULL)
652         errx(1, "krb5_storage_from_fd");
653
654     {
655         int32_t version;
656         char *str = NULL;
657         get_version_capa(c, &version, &c->capabilities, &str);
658         if (str) {
659             free(str);
660         }
661         if (c->capabilities & HAS_MONIKER)
662             get_moniker(c, &c->moniker);
663         else
664             c->moniker = c->name;
665         if (c->capabilities & ISSERVER)
666             get_targetname(c, &c->target_name);
667     }
668
669     if (logfile) {
670         int fd;
671
672         printf("starting log socket to client %s\n", c->moniker);
673
674         fd = wait_log(c);
675
676         c->logsock = krb5_storage_from_fd(fd);
677         close(fd);
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);
682 #else
683         c->child = fork();
684         if (c->child == -1)
685             errx(1, "failed to fork");
686         else if (c->child == 0) {
687             log_function(c);
688             fclose(logfile);
689             exit(0);
690         }
691 #endif
692    }
693
694
695     clients = erealloc(clients, (num_clients + 1) * sizeof(*clients));
696
697     clients[num_clients] = c;
698     num_clients++;
699
700     free(name);
701 }
702
703 static struct client *
704 get_client(const char *slave)
705 {
706     size_t i;
707     for (i = 0; i < num_clients; i++)
708         if (strcmp(slave, clients[i]->name) == 0)
709             return clients[i];
710     errx(1, "failed to find client %s", slave);
711 }
712
713 /*
714  *
715  */
716
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;
723
724 struct getargs args[] = {
725     { "principals", 0,  arg_strings,    &principals,    "Test principal",
726       NULL },
727     { "slaves", 0,  arg_strings,        &slaves,        "Slaves",
728       NULL },
729     { "log-file", 0, arg_string,        &logfile_str,   "Logfile",
730       NULL },
731     { "wrap-ext", 0,  arg_flag,         &wrap_ext,      "test wrap extended",
732       NULL },
733     { "version", 0,  arg_flag,          &version_flag,  "Print version",
734       NULL },
735     { "help",    0,  arg_flag,          &help_flag,     NULL,
736       NULL }
737 };
738
739 static void
740 usage(int ret)
741 {
742     arg_printusage (args,
743                     sizeof(args) / sizeof(args[0]),
744                     NULL,
745                     "");
746     exit (ret);
747 }
748
749 int
750 main(int argc, char **argv)
751 {
752     int optidx= 0;
753     char *user;
754     char *password;
755     char ***list, **p;
756     size_t num_list, i, j, k;
757     int failed = 0;
758
759     setprogname (argv[0]);
760
761     if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
762         usage (1);
763
764     if (help_flag)
765         usage (0);
766
767     if (version_flag) {
768         print_version (NULL);
769         return 0;
770     }
771
772     if (optidx != argc)
773         usage (1);
774
775     if (principals.num_strings == 0)
776         errx(1, "no principals");
777
778     user = estrdup(principals.strings[0]);
779     password = strchr(user, ':');
780     if (password == NULL)
781         errx(1, "password missing from %s", user);
782     *password++ = 0;
783
784     if (slaves.num_strings == 0)
785         errx(1, "no principals");
786
787     if (logfile_str) {
788         printf("open logfile %s\n", logfile_str);
789         logfile = fopen(logfile_str, "w+");
790         if (logfile == NULL)
791             err(1, "failed to open: %s", logfile_str);
792     }
793
794     /*
795      *
796      */
797
798     list = permutate_all(&slaves, &num_list);
799
800     /*
801      * Set up connection to all clients
802      */
803
804     printf("Connecting to slaves\n");
805     for (i = 0; i < slaves.num_strings; i++)
806         connect_client(slaves.strings[i]);
807
808     /*
809      * Test acquire credentials
810      */
811
812     printf("Test acquire credentials\n");
813     for (i = 0; i < slaves.num_strings; i++) {
814         int32_t hCred, val;
815
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);
820             failed = 1;
821         } else
822             toast_resource(clients[i], hCred);
823     }
824
825     if (failed)
826         goto out;
827
828     /*
829      * First test if all slaves can build context to them-self.
830      */
831
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];
837
838         if (c->target_name == NULL)
839             continue;
840
841         printf("%s connects to self using %s\n",
842                c->moniker, c->target_name);
843
844         val = acquire_cred(c, user, password, 1, &hCred);
845         if (val != GSMERR_OK)
846             errx(1, "failed to acquire_cred: %d", (int)val);
847
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);
857             if (delegCred)
858                 toast_resource(c, delegCred);
859         } else {
860             warnx("build_context failed: %d", (int)val);
861         }
862         /*
863          *
864          */
865
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);
873             if (delegCred)
874                 toast_resource(c, delegCred);
875         } else {
876             warnx("build_context failed: %d", (int)val);
877         }
878
879         toast_resource(c, hCred);
880     }
881     /*
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
884      * circle.
885      *
886      * Only follow the delegated credential, but test "all"
887      * flags. (XXX only do deleg|mutual right now.
888      */
889
890     printf("\"All\" permutation tests\n");
891
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;
896
897         p = list[i];
898
899         client = get_client(p[0]);
900
901         val = acquire_cred(client, user, password, 1, &hCred);
902         if (val != GSMERR_OK)
903             errx(1, "failed to acquire_cred: %d", (int)val);
904
905         for (j = 1; j < num_clients + 1; j++) {
906             server = get_client(p[j % num_clients]);
907
908             if (server->target_name == NULL)
909                 break;
910
911             for (k = 1; k < j; k++)
912                 printf("\t");
913             printf("%s -> %s\n", client->moniker, server->moniker);
914
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);
922                 break;
923             }
924
925             val = test_token(client, clientC, server, serverC, wrap_ext);
926             if (val)
927                 break;
928
929             toast_resource(client, clientC);
930             toast_resource(server, serverC);
931             if (!delegCred) {
932                 warnx("no delegated cred on %s", server->moniker);
933                 break;
934             }
935             toast_resource(client, hCred);
936             hCred = delegCred;
937             client = server;
938         }
939         if (hCred)
940             toast_resource(client, hCred);
941     }
942
943     /*
944      * Close all connections to clients
945      */
946
947 out:
948     printf("sending goodbye and waiting for log sockets\n");
949     for (i = 0; i < num_clients; i++) {
950         goodbye(clients[i]);
951         if (clients[i]->logsock) {
952 #ifdef ENABLE_PTHREAD_SUPPORT
953             pthread_join(&clients[i]->thr, NULL);
954 #else
955             waitpid(clients[i]->child, NULL, 0);
956 #endif
957         }
958     }
959
960     printf("done\n");
961
962     return 0;
963 }