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
init_sec_context(struct client * client,int32_t * hContext,int32_t * hCred,int32_t flags,const char * targetname,const krb5_data * itoken,krb5_data * otoken)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
accept_sec_context(struct client * client,int32_t * hContext,int32_t flags,const krb5_data * itoken,krb5_data * otoken,int32_t * hDelegCred)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
acquire_cred(struct client * client,const char * username,const char * password,int32_t flags,int32_t * hCred)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
toast_resource(struct client * client,int32_t hCred)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
goodbye(struct client * client)134 goodbye(struct client *client)
135 {
136 put32(client, eGoodBye);
137 return GSMERR_OK;
138 }
139
140 static int
get_targetname(struct client * client,char ** target)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
encrypt_token(struct client * client,int32_t hContext,int32_t flags,krb5_data * in,krb5_data * out)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
decrypt_token(struct client * client,int32_t hContext,int flags,krb5_data * in,krb5_data * out)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
wrap_token_ext(struct client * client,int32_t hContext,int32_t flags,int32_t bflags,krb5_data * header,krb5_data * in,krb5_data * trailer,krb5_data * out)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
unwrap_token_ext(struct client * client,int32_t hContext,int32_t flags,int32_t bflags,krb5_data * header,krb5_data * in,krb5_data * trailer,krb5_data * out)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
get_mic(struct client * client,int32_t hContext,krb5_data * in,krb5_data * mic)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
verify_mic(struct client * client,int32_t hContext,krb5_data * in,krb5_data * mic)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
get_version_capa(struct client * client,int32_t * version,int32_t * capa,char ** version_str)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
get_moniker(struct client * client,char ** moniker)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
wait_log(struct client * c)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
build_context(struct client * ipeer,struct client * apeer,int32_t flags,int32_t hCred,int32_t * iContext,int32_t * aContext,int32_t * hDelegCred)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
test_mic(struct client * c1,int32_t hc1,struct client * c2,int32_t hc2)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
test_wrap(struct client * c1,int32_t hc1,struct client * c2,int32_t hc2,int conf)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
test_wrap_ext(struct client * c1,int32_t hc1,struct client * c2,int32_t hc2,int conf,int bflags)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
test_token(struct client * c1,int32_t hc1,struct client * c2,int32_t hc2,int wrap_ext)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
log_function(void * ptr)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
connect_client(const char * slave)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 *
get_client(const char * slave)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
usage(int ret)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
main(int argc,char ** argv)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 }
964