9ccf1de4088124662c26430f741c7f1e6a192cbc
[samba.git] / source4 / 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     krb5_socket_t sock, sock2;
274     int ret;
275
276     memset(&sast, 0, sizeof(sast));
277
278     assert(sizeof(sast) >= c->salen);
279
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);
283
284     sast.ss_family = c->sa->sa_family;
285     ret = bind(sock, (struct sockaddr *)&sast, c->salen);
286     if (ret < 0)
287         err(1, "failed to bind %s's logging port", c->moniker);
288
289     if (listen(sock, SOMAXCONN) < 0)
290         err(1, "failed to listen %s's logging port", c->moniker);
291
292     salen = sizeof(sast);
293     ret = getsockname(sock, (struct sockaddr *)&sast, &salen);
294     if (ret < 0)
295         err(1, "failed to get address of local socket for %s", c->moniker);
296
297     port = socket_get_port((struct sockaddr *)&sast);
298
299     put32(c, eSetLoggingSocket);
300     put32(c, ntohs(port));
301
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);
307
308     return sock2;
309 }
310
311
312
313
314 static int
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)
318 {
319     int32_t val = GSMERR_ERROR, ic = 0, ac = 0, deleg = 0;
320     krb5_data itoken, otoken;
321     int iDone = 0, aDone = 0;
322     int step = 0;
323     int first_call = 0x80;
324
325     if (apeer->target_name == NULL)
326         errx(1, "apeer %s have no target name", apeer->name);
327
328     krb5_data_zero(&itoken);
329
330     while (!iDone || !aDone) {
331
332         if (iDone) {
333             warnx("iPeer already done, aPeer want extra rtt");
334             val = GSMERR_ERROR;
335             goto out;
336         }
337
338         val = init_sec_context(ipeer, &ic, &hCred, flags|first_call,
339                                apeer->target_name, &itoken, &otoken);
340         step++;
341         switch(val) {
342         case GSMERR_OK:
343             iDone = 1;
344             if (aDone)
345                 continue;
346             break;
347         case GSMERR_CONTINUE_NEEDED:
348             break;
349         default:
350             warnx("iPeer %s failed with %d (step %d)",
351                   ipeer->name, (int)val, step);
352             goto out;
353         }
354
355         if (aDone) {
356             warnx("aPeer already done, iPeer want extra rtt");
357             val = GSMERR_ERROR;
358             goto out;
359         }
360
361         val = accept_sec_context(apeer, &ac, flags|first_call,
362                                  &otoken, &itoken, &deleg);
363         step++;
364         switch(val) {
365         case GSMERR_OK:
366             aDone = 1;
367             if (iDone)
368                 continue;
369             break;
370         case GSMERR_CONTINUE_NEEDED:
371             break;
372         default:
373             warnx("aPeer %s failed with %d (step %d)",
374                  apeer->name, (int)val, step);
375             val = GSMERR_ERROR;
376             goto out;
377         }
378         first_call = 0;
379         val = GSMERR_OK;
380     }
381
382     if (iContext == NULL || val != GSMERR_OK) {
383         if (ic)
384             toast_resource(ipeer, ic);
385         if (iContext)
386             *iContext = 0;
387     } else
388         *iContext = ic;
389
390     if (aContext == NULL || val != GSMERR_OK) {
391         if (ac)
392             toast_resource(apeer, ac);
393         if (aContext)
394             *aContext = 0;
395     } else
396         *aContext = ac;
397
398     if (hDelegCred == NULL || val != GSMERR_OK) {
399         if (deleg)
400             toast_resource(apeer, deleg);
401         if (hDelegCred)
402             *hDelegCred = 0;
403     } else
404         *hDelegCred = deleg;
405
406 out:
407     return val;
408 }
409
410 static void
411 test_mic(struct client *c1, int32_t hc1, struct client *c2, int32_t hc2)
412 {
413     krb5_data msg, mic;
414     int32_t val;
415
416     msg.data = "foo";
417     msg.length = 3;
418
419     krb5_data_zero(&mic);
420
421     val = get_mic(c1, hc1, &msg, &mic);
422     if (val)
423         errx(1, "get_mic failed to host: %s", c1->moniker);
424     val = verify_mic(c2, hc2, &msg, &mic);
425     if (val)
426         errx(1, "verify_mic failed to host: %s", c2->moniker);
427
428     krb5_data_free(&mic);
429 }
430
431 static int32_t
432 test_wrap(struct client *c1, int32_t hc1, struct client *c2, int32_t hc2,
433           int conf)
434 {
435     krb5_data msg, wrapped, out;
436     int32_t val;
437
438     msg.data = "foo";
439     msg.length = 3;
440
441     krb5_data_zero(&wrapped);
442     krb5_data_zero(&out);
443
444     val = encrypt_token(c1, hc1, conf, &msg, &wrapped);
445     if (val) {
446         warnx("encrypt_token failed to host: %s", c1->moniker);
447         return val;
448     }
449     val = decrypt_token(c2, hc2, conf, &wrapped, &out);
450     if (val) {
451         krb5_data_free(&wrapped);
452         warnx("decrypt_token failed to host: %s", c2->moniker);
453         return val;
454     }
455
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);
459         val = GSMERR_ERROR;
460     } else if (memcmp(msg.data, out.data, msg.length) != 0) {
461         warnx("decryptd'ed token have wrong data");
462         val = GSMERR_ERROR;
463     }
464
465     krb5_data_free(&wrapped);
466     krb5_data_free(&out);
467     return val;
468 }
469
470 static int32_t
471 test_wrap_ext(struct client *c1, int32_t hc1, struct client *c2, int32_t hc2,
472               int conf, int bflags)
473 {
474     krb5_data header, msg, trailer, wrapped, out;
475     int32_t val;
476
477     header.data = "header";
478     header.length = sizeof("header") - 1;
479
480     msg.data = "0123456789abcdef"; /* padded for most enctypes */
481     msg.length = sizeof("0123456789abcdef") - 1;
482
483     trailer.data = "trailer";
484     trailer.length = 7;
485
486     krb5_data_zero(&wrapped);
487     krb5_data_zero(&out);
488
489     val = wrap_token_ext(c1, hc1, conf, bflags, &header, &msg, &trailer, &wrapped);
490     if (val) {
491         warnx("encrypt_token failed to host: %s", c1->moniker);
492         return val;
493     }
494     val = unwrap_token_ext(c2, hc2, conf, bflags, &header, &wrapped, &trailer, &out);
495     if (val) {
496         krb5_data_free(&wrapped);
497         warnx("decrypt_token failed to host: %s", c2->moniker);
498         return val;
499     }
500
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);
504         val = GSMERR_ERROR;
505     } else if (memcmp(msg.data, out.data, msg.length) != 0) {
506         warnx("decryptd'ed token have wrong data");
507         val = GSMERR_ERROR;
508     }
509
510     krb5_data_free(&wrapped);
511     krb5_data_free(&out);
512     return val;
513 }
514
515
516 static int32_t
517 test_token(struct client *c1, int32_t hc1, struct client *c2, int32_t hc2, int wrap_ext)
518 {
519     int32_t val;
520     int i;
521
522     for (i = 0; i < 10; i++) {
523         /* mic */
524         test_mic(c1, hc1, c2, hc2);
525         test_mic(c2, hc2, c1, hc1);
526
527         /* wrap */
528         val = test_wrap(c1, hc1, c2, hc2, 0);
529         if (val) return val;
530         val = test_wrap(c2, hc2, c1, hc1, 0);
531         if (val) return val;
532
533         val = test_wrap(c1, hc1, c2, hc2, 1);
534         if (val) return val;
535         val = test_wrap(c2, hc2, c1, hc1, 1);
536         if (val) return val;
537
538         if (wrap_ext) {
539             /* wrap ext */
540             val = test_wrap_ext(c1, hc1, c2, hc2, 1, 0);
541             if (val) return val;
542             val = test_wrap_ext(c2, hc2, c1, hc1, 1, 0);
543             if (val) return val;
544
545             val = test_wrap_ext(c1, hc1, c2, hc2, 1, 1);
546             if (val) return val;
547             val = test_wrap_ext(c2, hc2, c1, hc1, 1, 1);
548             if (val) return val;
549
550             val = test_wrap_ext(c1, hc1, c2, hc2, 0, 0);
551             if (val) return val;
552             val = test_wrap_ext(c2, hc2, c1, hc1, 0, 0);
553             if (val) return val;
554
555             val = test_wrap_ext(c1, hc1, c2, hc2, 0, 1);
556             if (val) return val;
557             val = test_wrap_ext(c2, hc2, c1, hc1, 0, 1);
558             if (val) return val;
559         }
560     }
561     return GSMERR_OK;
562 }
563
564 static int
565 log_function(void *ptr)
566 {
567     struct client *c = ptr;
568     int32_t cmd, line;
569     char *file = NULL, *string = NULL;
570
571     while (1) {
572         if (krb5_ret_int32(c->logsock, &cmd))
573             goto out;
574
575         switch (cmd) {
576         case eLogSetMoniker:
577             if (krb5_ret_string(c->logsock, &file))
578                 goto out;
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             if (krb5_store_int32(c->logsock, 0))
594                 goto out;
595             break;
596         default:
597             errx(1, "client send bad log command: %d", (int)cmd);
598         }
599     }
600 out:
601     free(file);
602     free(string);
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;
614     krb5_socket_t sock;
615
616     name = estrdup(slave);
617     port = strchr(name, ':');
618     if (port == NULL)
619         errx(1, "port missing from %s", name);
620     *port++ = 0;
621
622     c->name = estrdup(slave);
623
624     memset(&hints, 0, sizeof(hints));
625     hints.ai_family = PF_UNSPEC;
626     hints.ai_socktype = SOCK_STREAM;
627
628     ret = getaddrinfo(name, port, &hints, &res0);
629     if (ret)
630         errx(1, "error resolving %s", name);
631
632     for (res = res0, sock = rk_INVALID_SOCKET; res; res = res->ai_next) {
633         sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
634         if (sock == rk_INVALID_SOCKET)
635             continue;
636         if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
637             rk_closesocket(sock);
638             sock = rk_INVALID_SOCKET;
639             continue;
640         }
641         c->sa = ecalloc(1, res->ai_addrlen);
642         memcpy(c->sa, res->ai_addr, res->ai_addrlen);
643         c->salen = res->ai_addrlen;
644         break;  /* okay we got one */
645     }
646     if (sock == rk_INVALID_SOCKET)
647         err(1, "connect to host: %s", name);
648     freeaddrinfo(res0);
649
650     c->sock = krb5_storage_from_socket(sock);
651     rk_closesocket(sock);
652     if (c->sock == NULL)
653         errx(1, "krb5_storage_from_fd");
654
655     {
656         int32_t version;
657         char *str = NULL;
658         get_version_capa(c, &version, &c->capabilities, &str);
659         if (str) {
660             free(str);
661         }
662         if (c->capabilities & HAS_MONIKER)
663             get_moniker(c, &c->moniker);
664         else
665             c->moniker = c->name;
666         if (c->capabilities & ISSERVER)
667             get_targetname(c, &c->target_name);
668     }
669
670     if (logfile) {
671         printf("starting log socket to client %s\n", c->moniker);
672
673         sock = wait_log(c);
674
675         c->logsock = krb5_storage_from_socket(sock);
676         rk_closesocket(sock);
677         if (c->logsock == NULL)
678             errx(1, "failed to create log krb5_storage");
679 #ifdef ENABLE_PTHREAD_SUPPORT
680         pthread_create(&c->thr, NULL, log_function, c);
681 #else
682         c->child = fork();
683         if (c->child == -1)
684             errx(1, "failed to fork");
685         else if (c->child == 0) {
686             log_function(c);
687             fclose(logfile);
688             exit(0);
689         }
690 #endif
691    }
692
693
694     clients = erealloc(clients, (num_clients + 1) * sizeof(*clients));
695
696     clients[num_clients] = c;
697     num_clients++;
698
699     free(name);
700 }
701
702 static struct client *
703 get_client(const char *slave)
704 {
705     size_t i;
706     for (i = 0; i < num_clients; i++)
707         if (strcmp(slave, clients[i]->name) == 0)
708             return clients[i];
709     errx(1, "failed to find client %s", slave);
710 }
711
712 /*
713  *
714  */
715
716 static int version_flag;
717 static int help_flag;
718 static int wrap_ext = 0;
719 static char *logfile_str;
720 static getarg_strings principals;
721 static getarg_strings slaves;
722
723 struct getargs args[] = {
724     { "principals", 0,  arg_strings,    &principals,    "Test principal",
725       NULL },
726     { "slaves", 0,  arg_strings,        &slaves,        "Slaves",
727       NULL },
728     { "log-file", 0, arg_string,        &logfile_str,   "Logfile",
729       NULL },
730     { "wrap-ext", 0,  arg_flag,         &wrap_ext,      "test wrap extended",
731       NULL },
732     { "version", 0,  arg_flag,          &version_flag,  "Print version",
733       NULL },
734     { "help",    0,  arg_flag,          &help_flag,     NULL,
735       NULL }
736 };
737
738 static void
739 usage(int ret)
740 {
741     arg_printusage (args,
742                     sizeof(args) / sizeof(args[0]),
743                     NULL,
744                     "");
745     exit (ret);
746 }
747
748 int
749 main(int argc, char **argv)
750 {
751     int optidx= 0;
752     char *user;
753     char *password;
754     char ***list, **p;
755     size_t num_list, i, j, k;
756     int failed = 0;
757
758     setprogname (argv[0]);
759
760     if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
761         usage (1);
762
763     if (help_flag)
764         usage (0);
765
766     if (version_flag) {
767         print_version (NULL);
768         return 0;
769     }
770
771     if (optidx != argc)
772         usage (1);
773
774     if (principals.num_strings == 0)
775         errx(1, "no principals");
776
777     user = estrdup(principals.strings[0]);
778     password = strchr(user, ':');
779     if (password == NULL)
780         errx(1, "password missing from %s", user);
781     *password++ = 0;
782
783     if (slaves.num_strings == 0)
784         errx(1, "no principals");
785
786     if (logfile_str) {
787         printf("open logfile %s\n", logfile_str);
788         logfile = fopen(logfile_str, "w+");
789         if (logfile == NULL)
790             err(1, "failed to open: %s", logfile_str);
791     }
792
793     /*
794      *
795      */
796
797     list = permutate_all(&slaves, &num_list);
798
799     /*
800      * Set up connection to all clients
801      */
802
803     printf("Connecting to slaves\n");
804     for (i = 0; i < slaves.num_strings; i++)
805         connect_client(slaves.strings[i]);
806
807     /*
808      * Test acquire credentials
809      */
810
811     printf("Test acquire credentials\n");
812     for (i = 0; i < slaves.num_strings; i++) {
813         int32_t hCred, val;
814
815         val = acquire_cred(clients[i], user, password, 1, &hCred);
816         if (val != GSMERR_OK) {
817             warnx("Failed to acquire_cred on host %s: %d",
818                  clients[i]->moniker, (int)val);
819             failed = 1;
820         } else
821             toast_resource(clients[i], hCred);
822     }
823
824     if (failed)
825         goto out;
826
827     /*
828      * First test if all slaves can build context to them-self.
829      */
830
831     printf("Self context tests\n");
832     for (i = 0; i < num_clients; i++) {
833         int32_t hCred, val, delegCred;
834         int32_t clientC, serverC;
835         struct client *c = clients[i];
836
837         if (c->target_name == NULL)
838             continue;
839
840         printf("%s connects to self using %s\n",
841                c->moniker, c->target_name);
842
843         val = acquire_cred(c, user, password, 1, &hCred);
844         if (val != GSMERR_OK)
845             errx(1, "failed to acquire_cred: %d", (int)val);
846
847         val = build_context(c, c,
848                             GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG|
849                             GSS_C_INTEG_FLAG|GSS_C_CONF_FLAG|
850                             GSS_C_DELEG_FLAG|GSS_C_MUTUAL_FLAG,
851                             hCred, &clientC, &serverC, &delegCred);
852         if (val == GSMERR_OK) {
853             test_token(c, clientC, c, serverC, wrap_ext);
854             toast_resource(c, clientC);
855             toast_resource(c, serverC);
856             if (delegCred)
857                 toast_resource(c, delegCred);
858         } else {
859             warnx("build_context failed: %d", (int)val);
860         }
861         /*
862          *
863          */
864
865         val = build_context(c, c,
866                             GSS_C_INTEG_FLAG|GSS_C_CONF_FLAG,
867                             hCred, &clientC, &serverC, &delegCred);
868         if (val == GSMERR_OK) {
869             test_token(c, clientC, c, serverC, wrap_ext);
870             toast_resource(c, clientC);
871             toast_resource(c, serverC);
872             if (delegCred)
873                 toast_resource(c, delegCred);
874         } else {
875             warnx("build_context failed: %d", (int)val);
876         }
877
878         toast_resource(c, hCred);
879     }
880     /*
881      * Build contexts though all entries in each lists, including the
882      * step from the last entry to the first, ie treat the list as a
883      * circle.
884      *
885      * Only follow the delegated credential, but test "all"
886      * flags. (XXX only do deleg|mutual right now.
887      */
888
889     printf("\"All\" permutation tests\n");
890
891     for (i = 0; i < num_list; i++) {
892         int32_t hCred, val, delegCred = 0;
893         int32_t clientC = 0, serverC = 0;
894         struct client *client, *server;
895
896         p = list[i];
897
898         client = get_client(p[0]);
899
900         val = acquire_cred(client, user, password, 1, &hCred);
901         if (val != GSMERR_OK)
902             errx(1, "failed to acquire_cred: %d", (int)val);
903
904         for (j = 1; j < num_clients + 1; j++) {
905             server = get_client(p[j % num_clients]);
906
907             if (server->target_name == NULL)
908                 break;
909
910             for (k = 1; k < j; k++)
911                 printf("\t");
912             printf("%s -> %s\n", client->moniker, server->moniker);
913
914             val = build_context(client, server,
915                                 GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG|
916                                 GSS_C_INTEG_FLAG|GSS_C_CONF_FLAG|
917                                 GSS_C_DELEG_FLAG|GSS_C_MUTUAL_FLAG,
918                                 hCred, &clientC, &serverC, &delegCred);
919             if (val != GSMERR_OK) {
920                 warnx("build_context failed: %d", (int)val);
921                 break;
922             }
923
924             val = test_token(client, clientC, server, serverC, wrap_ext);
925             if (val)
926                 break;
927
928             toast_resource(client, clientC);
929             toast_resource(server, serverC);
930             if (!delegCred) {
931                 warnx("no delegated cred on %s", server->moniker);
932                 break;
933             }
934             toast_resource(client, hCred);
935             hCred = delegCred;
936             client = server;
937         }
938         if (hCred)
939             toast_resource(client, hCred);
940     }
941
942     /*
943      * Close all connections to clients
944      */
945
946 out:
947     printf("sending goodbye and waiting for log sockets\n");
948     for (i = 0; i < num_clients; i++) {
949         goodbye(clients[i]);
950         if (clients[i]->logsock) {
951 #ifdef ENABLE_PTHREAD_SUPPORT
952             pthread_join(&clients[i]->thr, NULL);
953 #else
954             waitpid(clients[i]->child, NULL, 0);
955 #endif
956         }
957     }
958
959     printf("done\n");
960
961     return 0;
962 }