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>
35RCSID("$Id$");
36
37static FILE *logfile;
38
39/*
40 *
41 */
42
43struct 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
60static struct client **clients;
61static int num_clients;
62
63static int
64init_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
84static int
85accept_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
105static int
106acquire_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
122static int
123toast_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
133static int
134goodbye(struct client *client)
135{
136    put32(client, eGoodBye);
137    return GSMERR_OK;
138}
139
140static int
141get_targetname(struct client *client,
142	       char **target)
143{
144    put32(client, eGetTargetName);
145    retstring(client, *target);
146    return GSMERR_OK;
147}
148
149static int32_t
150encrypt_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
164static int32_t
165decrypt_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
179static int32_t
180wrap_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
197static int32_t
198unwrap_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
215static int32_t
216get_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
230static int32_t
231verify_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
246static int32_t
247get_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
258static int32_t
259get_moniker(struct client *client,
260	    char **moniker)
261{
262    put32(client, eGetMoniker);
263    retstring(client, *moniker);
264    return GSMERR_OK;
265}
266
267static int
268wait_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
313static int
314build_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
405out:
406    return val;
407}
408
409static void
410test_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
430static int32_t
431test_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
469static int32_t
470test_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
515static int32_t
516test_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
563static int
564log_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    }
602out:
603
604    return 0;
605}
606
607static void
608connect_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
703static struct client *
704get_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
717static int version_flag;
718static int help_flag;
719static int wrap_ext = 0;
720static char *logfile_str;
721static getarg_strings principals;
722static getarg_strings slaves;
723
724struct 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
739static void
740usage(int ret)
741{
742    arg_printusage (args,
743		    sizeof(args) / sizeof(args[0]),
744		    NULL,
745		    "");
746    exit (ret);
747}
748
749int
750main(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
947out:
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}
964