1178825Sdfr/*
2233294Sstas * Copyright (c) 2006 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
5178825Sdfr *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
9178825Sdfr *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17178825Sdfr * 3. Neither the name of KTH nor the names of its contributors may be
18178825Sdfr *    used to endorse or promote products derived from this software without
19178825Sdfr *    specific prior written permission.
20178825Sdfr *
21178825Sdfr * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
22178825Sdfr * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24178825Sdfr * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
25178825Sdfr * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26178825Sdfr * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27178825Sdfr * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28178825Sdfr * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29178825Sdfr * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30178825Sdfr * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31178825Sdfr * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34178825Sdfr#include <common.h>
35233294SstasRCSID("$Id$");
36178825Sdfr
37178825Sdfrstatic FILE *logfile;
38178825Sdfr
39178825Sdfr/*
40178825Sdfr *
41178825Sdfr */
42178825Sdfr
43178825Sdfrstruct client {
44178825Sdfr    char *name;
45178825Sdfr    struct sockaddr *sa;
46178825Sdfr    socklen_t salen;
47178825Sdfr    krb5_storage *sock;
48178825Sdfr    int32_t capabilities;
49178825Sdfr    char *target_name;
50178825Sdfr    char *moniker;
51178825Sdfr    krb5_storage *logsock;
52178825Sdfr    int have_log;
53178825Sdfr#ifdef ENABLE_PTHREAD_SUPPORT
54178825Sdfr    pthread_t thr;
55178825Sdfr#else
56178825Sdfr    pid_t child;
57178825Sdfr#endif
58178825Sdfr};
59178825Sdfr
60178825Sdfrstatic struct client **clients;
61178825Sdfrstatic int num_clients;
62178825Sdfr
63178825Sdfrstatic int
64233294Sstasinit_sec_context(struct client *client,
65178825Sdfr		 int32_t *hContext, int32_t *hCred,
66233294Sstas		 int32_t flags,
67178825Sdfr		 const char *targetname,
68178825Sdfr		 const krb5_data *itoken, krb5_data *otoken)
69178825Sdfr{
70178825Sdfr    int32_t val;
71178825Sdfr    krb5_data_zero(otoken);
72178825Sdfr    put32(client, eInitContext);
73178825Sdfr    put32(client, *hContext);
74178825Sdfr    put32(client, *hCred);
75178825Sdfr    put32(client, flags);
76178825Sdfr    putstring(client, targetname);
77178825Sdfr    putdata(client, *itoken);
78178825Sdfr    ret32(client, *hContext);
79178825Sdfr    ret32(client, val);
80178825Sdfr    retdata(client, *otoken);
81178825Sdfr    return val;
82178825Sdfr}
83178825Sdfr
84178825Sdfrstatic int
85233294Sstasaccept_sec_context(struct client *client,
86178825Sdfr		   int32_t *hContext,
87178825Sdfr		   int32_t flags,
88178825Sdfr		   const krb5_data *itoken,
89178825Sdfr		   krb5_data *otoken,
90178825Sdfr		   int32_t *hDelegCred)
91178825Sdfr{
92178825Sdfr    int32_t val;
93178825Sdfr    krb5_data_zero(otoken);
94178825Sdfr    put32(client, eAcceptContext);
95178825Sdfr    put32(client, *hContext);
96178825Sdfr    put32(client, flags);
97178825Sdfr    putdata(client, *itoken);
98178825Sdfr    ret32(client, *hContext);
99178825Sdfr    ret32(client, val);
100178825Sdfr    retdata(client, *otoken);
101178825Sdfr    ret32(client, *hDelegCred);
102178825Sdfr    return val;
103178825Sdfr}
104178825Sdfr
105178825Sdfrstatic int
106233294Sstasacquire_cred(struct client *client,
107178825Sdfr	     const char *username,
108178825Sdfr	     const char *password,
109178825Sdfr	     int32_t flags,
110178825Sdfr	     int32_t *hCred)
111178825Sdfr{
112178825Sdfr    int32_t val;
113178825Sdfr    put32(client, eAcquireCreds);
114178825Sdfr    putstring(client, username);
115178825Sdfr    putstring(client, password);
116178825Sdfr    put32(client, flags);
117178825Sdfr    ret32(client, val);
118178825Sdfr    ret32(client, *hCred);
119178825Sdfr    return val;
120178825Sdfr}
121178825Sdfr
122178825Sdfrstatic int
123233294Sstastoast_resource(struct client *client,
124178825Sdfr	       int32_t hCred)
125178825Sdfr{
126178825Sdfr    int32_t val;
127178825Sdfr    put32(client, eToastResource);
128178825Sdfr    put32(client, hCred);
129178825Sdfr    ret32(client, val);
130178825Sdfr    return val;
131178825Sdfr}
132178825Sdfr
133178825Sdfrstatic int
134178825Sdfrgoodbye(struct client *client)
135178825Sdfr{
136178825Sdfr    put32(client, eGoodBye);
137178825Sdfr    return GSMERR_OK;
138178825Sdfr}
139178825Sdfr
140178825Sdfrstatic int
141233294Sstasget_targetname(struct client *client,
142178825Sdfr	       char **target)
143178825Sdfr{
144178825Sdfr    put32(client, eGetTargetName);
145178825Sdfr    retstring(client, *target);
146178825Sdfr    return GSMERR_OK;
147178825Sdfr}
148178825Sdfr
149178825Sdfrstatic int32_t
150178825Sdfrencrypt_token(struct client *client, int32_t hContext, int32_t flags,
151178825Sdfr	   krb5_data *in, krb5_data *out)
152178825Sdfr{
153178825Sdfr    int32_t val;
154178825Sdfr    put32(client, eEncrypt);
155178825Sdfr    put32(client, hContext);
156178825Sdfr    put32(client, flags);
157178825Sdfr    put32(client, 0);
158178825Sdfr    putdata(client, *in);
159178825Sdfr    ret32(client, val);
160178825Sdfr    retdata(client, *out);
161178825Sdfr    return val;
162178825Sdfr}
163178825Sdfr
164178825Sdfrstatic int32_t
165233294Sstasdecrypt_token(struct client *client, int32_t hContext, int flags,
166178825Sdfr	     krb5_data *in, krb5_data *out)
167178825Sdfr{
168178825Sdfr    int32_t val;
169178825Sdfr    put32(client, eDecrypt);
170178825Sdfr    put32(client, hContext);
171178825Sdfr    put32(client, flags);
172178825Sdfr    put32(client, 0);
173178825Sdfr    putdata(client, *in);
174178825Sdfr    ret32(client, val);
175178825Sdfr    retdata(client, *out);
176178825Sdfr    return val;
177178825Sdfr}
178178825Sdfr
179178825Sdfrstatic int32_t
180233294Sstaswrap_token_ext(struct client *client, int32_t hContext, int32_t flags,
181233294Sstas	       int32_t bflags, krb5_data *header, krb5_data *in, krb5_data *trailer,
182233294Sstas	       krb5_data *out)
183233294Sstas{
184233294Sstas    int32_t val;
185233294Sstas    put32(client, eWrapExt);
186233294Sstas    put32(client, hContext);
187233294Sstas    put32(client, flags);
188233294Sstas    put32(client, bflags);
189233294Sstas    putdata(client, *header);
190233294Sstas    putdata(client, *in);
191233294Sstas    putdata(client, *trailer);
192233294Sstas    ret32(client, val);
193233294Sstas    retdata(client, *out);
194233294Sstas    return val;
195233294Sstas}
196233294Sstas
197233294Sstasstatic int32_t
198233294Sstasunwrap_token_ext(struct client *client, int32_t hContext, int32_t flags,
199233294Sstas	       int32_t bflags, krb5_data *header, krb5_data *in, krb5_data *trailer,
200233294Sstas	       krb5_data *out)
201233294Sstas{
202233294Sstas    int32_t val;
203233294Sstas    put32(client, eUnwrapExt);
204233294Sstas    put32(client, hContext);
205233294Sstas    put32(client, flags);
206233294Sstas    put32(client, bflags);
207233294Sstas    putdata(client, *header);
208233294Sstas    putdata(client, *in);
209233294Sstas    putdata(client, *trailer);
210233294Sstas    ret32(client, val);
211233294Sstas    retdata(client, *out);
212233294Sstas    return val;
213233294Sstas}
214233294Sstas
215233294Sstasstatic int32_t
216178825Sdfrget_mic(struct client *client, int32_t hContext,
217178825Sdfr	krb5_data *in, krb5_data *mic)
218178825Sdfr{
219178825Sdfr    int32_t val;
220178825Sdfr    put32(client, eSign);
221178825Sdfr    put32(client, hContext);
222178825Sdfr    put32(client, 0);
223178825Sdfr    put32(client, 0);
224178825Sdfr    putdata(client, *in);
225178825Sdfr    ret32(client, val);
226178825Sdfr    retdata(client, *mic);
227178825Sdfr    return val;
228178825Sdfr}
229178825Sdfr
230178825Sdfrstatic int32_t
231233294Sstasverify_mic(struct client *client, int32_t hContext,
232178825Sdfr	   krb5_data *in, krb5_data *mic)
233178825Sdfr{
234178825Sdfr    int32_t val;
235178825Sdfr    put32(client, eVerify);
236178825Sdfr    put32(client, hContext);
237178825Sdfr    put32(client, 0);
238178825Sdfr    put32(client, 0);
239178825Sdfr    putdata(client, *in);
240178825Sdfr    putdata(client, *mic);
241178825Sdfr    ret32(client, val);
242178825Sdfr    return val;
243178825Sdfr}
244178825Sdfr
245178825Sdfr
246178825Sdfrstatic int32_t
247233294Sstasget_version_capa(struct client *client,
248178825Sdfr		 int32_t *version, int32_t *capa,
249178825Sdfr		 char **version_str)
250178825Sdfr{
251178825Sdfr    put32(client, eGetVersionAndCapabilities);
252178825Sdfr    ret32(client, *version);
253178825Sdfr    ret32(client, *capa);
254178825Sdfr    retstring(client, *version_str);
255178825Sdfr    return GSMERR_OK;
256178825Sdfr}
257178825Sdfr
258178825Sdfrstatic int32_t
259233294Sstasget_moniker(struct client *client,
260178825Sdfr	    char **moniker)
261178825Sdfr{
262178825Sdfr    put32(client, eGetMoniker);
263178825Sdfr    retstring(client, *moniker);
264178825Sdfr    return GSMERR_OK;
265178825Sdfr}
266178825Sdfr
267178825Sdfrstatic int
268178825Sdfrwait_log(struct client *c)
269178825Sdfr{
270178825Sdfr    int32_t port;
271178825Sdfr    struct sockaddr_storage sast;
272178825Sdfr    socklen_t salen = sizeof(sast);
273178825Sdfr    int fd, fd2, ret;
274178825Sdfr
275178825Sdfr    memset(&sast, 0, sizeof(sast));
276178825Sdfr
277178825Sdfr    assert(sizeof(sast) >= c->salen);
278178825Sdfr
279178825Sdfr    fd = socket(c->sa->sa_family, SOCK_STREAM, 0);
280178825Sdfr    if (fd < 0)
281178825Sdfr	err(1, "failed to build socket for %s's logging port", c->moniker);
282178825Sdfr
283178825Sdfr    ((struct sockaddr *)&sast)->sa_family = c->sa->sa_family;
284178825Sdfr    ret = bind(fd, (struct sockaddr *)&sast, c->salen);
285178825Sdfr    if (ret < 0)
286178825Sdfr	err(1, "failed to bind %s's logging port", c->moniker);
287178825Sdfr
288178825Sdfr    if (listen(fd, SOMAXCONN) < 0)
289178825Sdfr	err(1, "failed to listen %s's logging port", c->moniker);
290178825Sdfr
291178825Sdfr    salen = sizeof(sast);
292178825Sdfr    ret = getsockname(fd, (struct sockaddr *)&sast, &salen);
293178825Sdfr    if (ret < 0)
294178825Sdfr	err(1, "failed to get address of local socket for %s", c->moniker);
295178825Sdfr
296178825Sdfr    port = socket_get_port((struct sockaddr *)&sast);
297178825Sdfr
298178825Sdfr    put32(c, eSetLoggingSocket);
299178825Sdfr    put32(c, ntohs(port));
300178825Sdfr
301178825Sdfr    salen = sizeof(sast);
302178825Sdfr    fd2 = accept(fd, (struct sockaddr *)&sast, &salen);
303178825Sdfr    if (fd2 < 0)
304178825Sdfr	err(1, "failed to accept local socket for %s", c->moniker);
305178825Sdfr    close(fd);
306178825Sdfr
307178825Sdfr    return fd2;
308178825Sdfr}
309178825Sdfr
310178825Sdfr
311178825Sdfr
312178825Sdfr
313178825Sdfrstatic int
314178825Sdfrbuild_context(struct client *ipeer, struct client *apeer,
315178825Sdfr	      int32_t flags, int32_t hCred,
316178825Sdfr	      int32_t *iContext, int32_t *aContext, int32_t *hDelegCred)
317178825Sdfr{
318178825Sdfr    int32_t val = GSMERR_ERROR, ic = 0, ac = 0, deleg = 0;
319178825Sdfr    krb5_data itoken, otoken;
320178825Sdfr    int iDone = 0, aDone = 0;
321178825Sdfr    int step = 0;
322178825Sdfr    int first_call = 0x80;
323178825Sdfr
324178825Sdfr    if (apeer->target_name == NULL)
325178825Sdfr	errx(1, "apeer %s have no target name", apeer->name);
326178825Sdfr
327178825Sdfr    krb5_data_zero(&itoken);
328178825Sdfr
329178825Sdfr    while (!iDone || !aDone) {
330233294Sstas
331178825Sdfr	if (iDone) {
332178825Sdfr	    warnx("iPeer already done, aPeer want extra rtt");
333178825Sdfr	    val = GSMERR_ERROR;
334178825Sdfr	    goto out;
335178825Sdfr	}
336178825Sdfr
337178825Sdfr	val = init_sec_context(ipeer, &ic, &hCred, flags|first_call,
338178825Sdfr			       apeer->target_name, &itoken, &otoken);
339178825Sdfr	step++;
340178825Sdfr	switch(val) {
341178825Sdfr	case GSMERR_OK:
342178825Sdfr	    iDone = 1;
343178825Sdfr	    if (aDone)
344178825Sdfr		continue;
345178825Sdfr	    break;
346178825Sdfr	case GSMERR_CONTINUE_NEEDED:
347178825Sdfr	    break;
348178825Sdfr	default:
349233294Sstas	    warnx("iPeer %s failed with %d (step %d)",
350178825Sdfr		  ipeer->name, (int)val, step);
351178825Sdfr	    goto out;
352178825Sdfr	}
353178825Sdfr
354178825Sdfr	if (aDone) {
355178825Sdfr	    warnx("aPeer already done, iPeer want extra rtt");
356178825Sdfr	    val = GSMERR_ERROR;
357178825Sdfr	    goto out;
358178825Sdfr	}
359178825Sdfr
360178825Sdfr	val = accept_sec_context(apeer, &ac, flags|first_call,
361178825Sdfr				 &otoken, &itoken, &deleg);
362178825Sdfr	step++;
363178825Sdfr	switch(val) {
364178825Sdfr	case GSMERR_OK:
365178825Sdfr	    aDone = 1;
366178825Sdfr	    if (iDone)
367178825Sdfr		continue;
368178825Sdfr	    break;
369178825Sdfr	case GSMERR_CONTINUE_NEEDED:
370178825Sdfr	    break;
371178825Sdfr	default:
372178825Sdfr	    warnx("aPeer %s failed with %d (step %d)",
373178825Sdfr		 apeer->name, (int)val, step);
374178825Sdfr	    val = GSMERR_ERROR;
375178825Sdfr	    goto out;
376178825Sdfr	}
377178825Sdfr	first_call = 0;
378178825Sdfr	val = GSMERR_OK;
379178825Sdfr    }
380178825Sdfr
381178825Sdfr    if (iContext == NULL || val != GSMERR_OK) {
382178825Sdfr	if (ic)
383178825Sdfr	    toast_resource(ipeer, ic);
384178825Sdfr	if (iContext)
385178825Sdfr	    *iContext = 0;
386178825Sdfr    } else
387178825Sdfr	*iContext = ic;
388178825Sdfr
389178825Sdfr    if (aContext == NULL || val != GSMERR_OK) {
390178825Sdfr	if (ac)
391178825Sdfr	    toast_resource(apeer, ac);
392178825Sdfr	if (aContext)
393178825Sdfr	    *aContext = 0;
394178825Sdfr    } else
395178825Sdfr	*aContext = ac;
396178825Sdfr
397178825Sdfr    if (hDelegCred == NULL || val != GSMERR_OK) {
398178825Sdfr	if (deleg)
399178825Sdfr	    toast_resource(apeer, deleg);
400178825Sdfr	if (hDelegCred)
401178825Sdfr	    *hDelegCred = 0;
402178825Sdfr    } else
403178825Sdfr	*hDelegCred = deleg;
404178825Sdfr
405178825Sdfrout:
406178825Sdfr    return val;
407178825Sdfr}
408233294Sstas
409178825Sdfrstatic void
410178825Sdfrtest_mic(struct client *c1, int32_t hc1, struct client *c2, int32_t hc2)
411178825Sdfr{
412178825Sdfr    krb5_data msg, mic;
413178825Sdfr    int32_t val;
414233294Sstas
415178825Sdfr    msg.data = "foo";
416178825Sdfr    msg.length = 3;
417178825Sdfr
418178825Sdfr    krb5_data_zero(&mic);
419178825Sdfr
420178825Sdfr    val = get_mic(c1, hc1, &msg, &mic);
421178825Sdfr    if (val)
422178825Sdfr	errx(1, "get_mic failed to host: %s", c1->moniker);
423178825Sdfr    val = verify_mic(c2, hc2, &msg, &mic);
424178825Sdfr    if (val)
425178825Sdfr	errx(1, "verify_mic failed to host: %s", c2->moniker);
426178825Sdfr
427178825Sdfr    krb5_data_free(&mic);
428178825Sdfr}
429178825Sdfr
430178825Sdfrstatic int32_t
431233294Sstastest_wrap(struct client *c1, int32_t hc1, struct client *c2, int32_t hc2,
432178825Sdfr	  int conf)
433178825Sdfr{
434178825Sdfr    krb5_data msg, wrapped, out;
435178825Sdfr    int32_t val;
436233294Sstas
437178825Sdfr    msg.data = "foo";
438178825Sdfr    msg.length = 3;
439178825Sdfr
440178825Sdfr    krb5_data_zero(&wrapped);
441178825Sdfr    krb5_data_zero(&out);
442178825Sdfr
443178825Sdfr    val = encrypt_token(c1, hc1, conf, &msg, &wrapped);
444178825Sdfr    if (val) {
445178825Sdfr	warnx("encrypt_token failed to host: %s", c1->moniker);
446178825Sdfr	return val;
447178825Sdfr    }
448178825Sdfr    val = decrypt_token(c2, hc2, conf, &wrapped, &out);
449178825Sdfr    if (val) {
450178825Sdfr	krb5_data_free(&wrapped);
451178825Sdfr	warnx("decrypt_token failed to host: %s", c2->moniker);
452178825Sdfr	return val;
453178825Sdfr    }
454178825Sdfr
455178825Sdfr    if (msg.length != out.length) {
456178825Sdfr	warnx("decrypted'ed token have wrong length (%lu != %lu)",
457178825Sdfr	      (unsigned long)msg.length, (unsigned long)out.length);
458178825Sdfr	val = GSMERR_ERROR;
459178825Sdfr    } else if (memcmp(msg.data, out.data, msg.length) != 0) {
460178825Sdfr	warnx("decryptd'ed token have wrong data");
461178825Sdfr	val = GSMERR_ERROR;
462178825Sdfr    }
463178825Sdfr
464178825Sdfr    krb5_data_free(&wrapped);
465178825Sdfr    krb5_data_free(&out);
466178825Sdfr    return val;
467178825Sdfr}
468178825Sdfr
469178825Sdfrstatic int32_t
470233294Sstastest_wrap_ext(struct client *c1, int32_t hc1, struct client *c2, int32_t hc2,
471233294Sstas	      int conf, int bflags)
472178825Sdfr{
473233294Sstas    krb5_data header, msg, trailer, wrapped, out;
474178825Sdfr    int32_t val;
475233294Sstas
476233294Sstas    header.data = "header";
477233294Sstas    header.length = 6;
478233294Sstas
479233294Sstas    msg.data = "0123456789abcdef"; /* padded for most enctypes */
480233294Sstas    msg.length = 32;
481233294Sstas
482233294Sstas    trailer.data = "trailer";
483233294Sstas    trailer.length = 7;
484233294Sstas
485233294Sstas    krb5_data_zero(&wrapped);
486233294Sstas    krb5_data_zero(&out);
487233294Sstas
488233294Sstas    val = wrap_token_ext(c1, hc1, conf, bflags, &header, &msg, &trailer, &wrapped);
489233294Sstas    if (val) {
490233294Sstas	warnx("encrypt_token failed to host: %s", c1->moniker);
491233294Sstas	return val;
492233294Sstas    }
493233294Sstas    val = unwrap_token_ext(c2, hc2, conf, bflags, &header, &wrapped, &trailer, &out);
494233294Sstas    if (val) {
495233294Sstas	krb5_data_free(&wrapped);
496233294Sstas	warnx("decrypt_token failed to host: %s", c2->moniker);
497233294Sstas	return val;
498233294Sstas    }
499233294Sstas
500233294Sstas    if (msg.length != out.length) {
501233294Sstas	warnx("decrypted'ed token have wrong length (%lu != %lu)",
502233294Sstas	      (unsigned long)msg.length, (unsigned long)out.length);
503233294Sstas	val = GSMERR_ERROR;
504233294Sstas    } else if (memcmp(msg.data, out.data, msg.length) != 0) {
505233294Sstas	warnx("decryptd'ed token have wrong data");
506233294Sstas	val = GSMERR_ERROR;
507233294Sstas    }
508233294Sstas
509233294Sstas    krb5_data_free(&wrapped);
510233294Sstas    krb5_data_free(&out);
511233294Sstas    return val;
512233294Sstas}
513233294Sstas
514233294Sstas
515233294Sstasstatic int32_t
516233294Sstastest_token(struct client *c1, int32_t hc1, struct client *c2, int32_t hc2, int wrap_ext)
517233294Sstas{
518233294Sstas    int32_t val;
519178825Sdfr    int i;
520178825Sdfr
521178825Sdfr    for (i = 0; i < 10; i++) {
522233294Sstas	/* mic */
523178825Sdfr	test_mic(c1, hc1, c2, hc2);
524178825Sdfr	test_mic(c2, hc2, c1, hc1);
525233294Sstas
526233294Sstas	/* wrap */
527178825Sdfr	val = test_wrap(c1, hc1, c2, hc2, 0);
528178825Sdfr	if (val) return val;
529178825Sdfr	val = test_wrap(c2, hc2, c1, hc1, 0);
530178825Sdfr	if (val) return val;
531233294Sstas
532178825Sdfr	val = test_wrap(c1, hc1, c2, hc2, 1);
533178825Sdfr	if (val) return val;
534178825Sdfr	val = test_wrap(c2, hc2, c1, hc1, 1);
535178825Sdfr	if (val) return val;
536233294Sstas
537233294Sstas	if (wrap_ext) {
538233294Sstas	    /* wrap ext */
539233294Sstas	    val = test_wrap_ext(c1, hc1, c2, hc2, 1, 0);
540233294Sstas	    if (val) return val;
541233294Sstas	    val = test_wrap_ext(c2, hc2, c1, hc1, 1, 0);
542233294Sstas	    if (val) return val;
543233294Sstas
544233294Sstas	    val = test_wrap_ext(c1, hc1, c2, hc2, 1, 1);
545233294Sstas	    if (val) return val;
546233294Sstas	    val = test_wrap_ext(c2, hc2, c1, hc1, 1, 1);
547233294Sstas	    if (val) return val;
548233294Sstas
549233294Sstas	    val = test_wrap_ext(c1, hc1, c2, hc2, 0, 0);
550233294Sstas	    if (val) return val;
551233294Sstas	    val = test_wrap_ext(c2, hc2, c1, hc1, 0, 0);
552233294Sstas	    if (val) return val;
553233294Sstas
554233294Sstas	    val = test_wrap_ext(c1, hc1, c2, hc2, 0, 1);
555233294Sstas	    if (val) return val;
556233294Sstas	    val = test_wrap_ext(c2, hc2, c1, hc1, 0, 1);
557233294Sstas	    if (val) return val;
558233294Sstas	}
559178825Sdfr    }
560178825Sdfr    return GSMERR_OK;
561178825Sdfr}
562178825Sdfr
563178825Sdfrstatic int
564178825Sdfrlog_function(void *ptr)
565178825Sdfr{
566178825Sdfr    struct client *c = ptr;
567178825Sdfr    int32_t cmd, line;
568178825Sdfr    char *file, *string;
569178825Sdfr
570178825Sdfr    while (1) {
571178825Sdfr        if (krb5_ret_int32(c->logsock, &cmd))
572178825Sdfr	    goto out;
573178825Sdfr
574178825Sdfr	switch (cmd) {
575178825Sdfr	case eLogSetMoniker:
576178825Sdfr	    if (krb5_ret_string(c->logsock, &file))
577178825Sdfr		goto out;
578178825Sdfr	    free(file);
579178825Sdfr	    break;
580178825Sdfr	case eLogInfo:
581178825Sdfr	case eLogFailure:
582178825Sdfr	    if (krb5_ret_string(c->logsock, &file))
583178825Sdfr		goto out;
584178825Sdfr	    if (krb5_ret_int32(c->logsock, &line))
585178825Sdfr		goto out;
586178825Sdfr	    if (krb5_ret_string(c->logsock, &string))
587178825Sdfr		goto out;
588233294Sstas	    printf("%s:%lu: %s\n",
589178825Sdfr		   file, (unsigned long)line, string);
590233294Sstas	    fprintf(logfile, "%s:%lu: %s\n",
591178825Sdfr		    file, (unsigned long)line, string);
592178825Sdfr	    fflush(logfile);
593178825Sdfr	    free(file);
594178825Sdfr	    free(string);
595178825Sdfr	    if (krb5_store_int32(c->logsock, 0))
596178825Sdfr		goto out;
597178825Sdfr	    break;
598178825Sdfr	default:
599178825Sdfr	    errx(1, "client send bad log command: %d", (int)cmd);
600178825Sdfr	}
601178825Sdfr    }
602178825Sdfrout:
603178825Sdfr
604178825Sdfr    return 0;
605178825Sdfr}
606178825Sdfr
607178825Sdfrstatic void
608178825Sdfrconnect_client(const char *slave)
609178825Sdfr{
610178825Sdfr    char *name, *port;
611178825Sdfr    struct client *c = ecalloc(1, sizeof(*c));
612178825Sdfr    struct addrinfo hints, *res0, *res;
613178825Sdfr    int ret, fd;
614178825Sdfr
615178825Sdfr    name = estrdup(slave);
616178825Sdfr    port = strchr(name, ':');
617178825Sdfr    if (port == NULL)
618178825Sdfr	errx(1, "port missing from %s", name);
619178825Sdfr    *port++ = 0;
620178825Sdfr
621178825Sdfr    c->name = estrdup(slave);
622233294Sstas
623178825Sdfr    memset(&hints, 0, sizeof(hints));
624178825Sdfr    hints.ai_family = PF_UNSPEC;
625178825Sdfr    hints.ai_socktype = SOCK_STREAM;
626178825Sdfr
627178825Sdfr    ret = getaddrinfo(name, port, &hints, &res0);
628178825Sdfr    if (ret)
629178825Sdfr	errx(1, "error resolving %s", name);
630178825Sdfr
631178825Sdfr    for (res = res0, fd = -1; res; res = res->ai_next) {
632178825Sdfr	fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
633178825Sdfr	if (fd < 0)
634178825Sdfr	    continue;
635178825Sdfr	if (connect(fd, res->ai_addr, res->ai_addrlen) < 0) {
636178825Sdfr	    close(fd);
637178825Sdfr	    fd = -1;
638178825Sdfr	    continue;
639178825Sdfr	}
640178825Sdfr	c->sa = ecalloc(1, res->ai_addrlen);
641178825Sdfr	memcpy(c->sa, res->ai_addr, res->ai_addrlen);
642178825Sdfr	c->salen = res->ai_addrlen;
643178825Sdfr	break;  /* okay we got one */
644178825Sdfr    }
645178825Sdfr    if (fd < 0)
646178825Sdfr	err(1, "connect to host: %s", name);
647178825Sdfr    freeaddrinfo(res);
648178825Sdfr
649178825Sdfr    c->sock = krb5_storage_from_fd(fd);
650178825Sdfr    close(fd);
651178825Sdfr    if (c->sock == NULL)
652178825Sdfr	errx(1, "krb5_storage_from_fd");
653178825Sdfr
654178825Sdfr    {
655178825Sdfr	int32_t version;
656178825Sdfr	char *str = NULL;
657178825Sdfr	get_version_capa(c, &version, &c->capabilities, &str);
658178825Sdfr	if (str) {
659178825Sdfr	    free(str);
660178825Sdfr	}
661178825Sdfr	if (c->capabilities & HAS_MONIKER)
662178825Sdfr	    get_moniker(c, &c->moniker);
663178825Sdfr	else
664178825Sdfr	    c->moniker = c->name;
665178825Sdfr	if (c->capabilities & ISSERVER)
666178825Sdfr	    get_targetname(c, &c->target_name);
667178825Sdfr    }
668178825Sdfr
669178825Sdfr    if (logfile) {
670178825Sdfr	int fd;
671178825Sdfr
672178825Sdfr	printf("starting log socket to client %s\n", c->moniker);
673178825Sdfr
674178825Sdfr	fd = wait_log(c);
675178825Sdfr
676178825Sdfr	c->logsock = krb5_storage_from_fd(fd);
677178825Sdfr	close(fd);
678178825Sdfr	if (c->logsock == NULL)
679178825Sdfr	    errx(1, "failed to create log krb5_storage");
680178825Sdfr#ifdef ENABLE_PTHREAD_SUPPORT
681178825Sdfr	pthread_create(&c->thr, NULL, log_function, c);
682178825Sdfr#else
683178825Sdfr	c->child = fork();
684178825Sdfr	if (c->child == -1)
685178825Sdfr	    errx(1, "failed to fork");
686178825Sdfr	else if (c->child == 0) {
687178825Sdfr	    log_function(c);
688178825Sdfr	    fclose(logfile);
689178825Sdfr	    exit(0);
690178825Sdfr	}
691178825Sdfr#endif
692178825Sdfr   }
693178825Sdfr
694178825Sdfr
695178825Sdfr    clients = erealloc(clients, (num_clients + 1) * sizeof(*clients));
696233294Sstas
697178825Sdfr    clients[num_clients] = c;
698178825Sdfr    num_clients++;
699178825Sdfr
700178825Sdfr    free(name);
701178825Sdfr}
702178825Sdfr
703178825Sdfrstatic struct client *
704178825Sdfrget_client(const char *slave)
705178825Sdfr{
706178825Sdfr    size_t i;
707178825Sdfr    for (i = 0; i < num_clients; i++)
708178825Sdfr	if (strcmp(slave, clients[i]->name) == 0)
709178825Sdfr	    return clients[i];
710178825Sdfr    errx(1, "failed to find client %s", slave);
711178825Sdfr}
712178825Sdfr
713178825Sdfr/*
714178825Sdfr *
715178825Sdfr */
716178825Sdfr
717178825Sdfrstatic int version_flag;
718178825Sdfrstatic int help_flag;
719233294Sstasstatic int wrap_ext = 0;
720178825Sdfrstatic char *logfile_str;
721178825Sdfrstatic getarg_strings principals;
722178825Sdfrstatic getarg_strings slaves;
723178825Sdfr
724178825Sdfrstruct getargs args[] = {
725178825Sdfr    { "principals", 0,  arg_strings,	&principals,	"Test principal",
726178825Sdfr      NULL },
727178825Sdfr    { "slaves", 0,  arg_strings,	&slaves,	"Slaves",
728178825Sdfr      NULL },
729178825Sdfr    { "log-file", 0, arg_string,	&logfile_str,	"Logfile",
730178825Sdfr      NULL },
731233294Sstas    { "wrap-ext", 0,  arg_flag,		&wrap_ext,	"test wrap extended",
732233294Sstas      NULL },
733178825Sdfr    { "version", 0,  arg_flag,		&version_flag,	"Print version",
734178825Sdfr      NULL },
735178825Sdfr    { "help",	 0,  arg_flag,		&help_flag,	NULL,
736178825Sdfr      NULL }
737178825Sdfr};
738178825Sdfr
739178825Sdfrstatic void
740178825Sdfrusage(int ret)
741178825Sdfr{
742178825Sdfr    arg_printusage (args,
743178825Sdfr		    sizeof(args) / sizeof(args[0]),
744178825Sdfr		    NULL,
745178825Sdfr		    "");
746178825Sdfr    exit (ret);
747178825Sdfr}
748178825Sdfr
749178825Sdfrint
750178825Sdfrmain(int argc, char **argv)
751178825Sdfr{
752178825Sdfr    int optidx= 0;
753178825Sdfr    char *user;
754178825Sdfr    char *password;
755178825Sdfr    char ***list, **p;
756178825Sdfr    size_t num_list, i, j, k;
757178825Sdfr    int failed = 0;
758178825Sdfr
759178825Sdfr    setprogname (argv[0]);
760178825Sdfr
761178825Sdfr    if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx))
762178825Sdfr	usage (1);
763178825Sdfr
764178825Sdfr    if (help_flag)
765178825Sdfr	usage (0);
766178825Sdfr
767178825Sdfr    if (version_flag) {
768178825Sdfr	print_version (NULL);
769178825Sdfr	return 0;
770178825Sdfr    }
771178825Sdfr
772178825Sdfr    if (optidx != argc)
773178825Sdfr	usage (1);
774178825Sdfr
775178825Sdfr    if (principals.num_strings == 0)
776178825Sdfr	errx(1, "no principals");
777178825Sdfr
778178825Sdfr    user = estrdup(principals.strings[0]);
779178825Sdfr    password = strchr(user, ':');
780178825Sdfr    if (password == NULL)
781178825Sdfr	errx(1, "password missing from %s", user);
782178825Sdfr    *password++ = 0;
783233294Sstas
784178825Sdfr    if (slaves.num_strings == 0)
785178825Sdfr	errx(1, "no principals");
786178825Sdfr
787178825Sdfr    if (logfile_str) {
788178825Sdfr	printf("open logfile %s\n", logfile_str);
789178825Sdfr	logfile = fopen(logfile_str, "w+");
790178825Sdfr	if (logfile == NULL)
791178825Sdfr	    err(1, "failed to open: %s", logfile_str);
792178825Sdfr    }
793178825Sdfr
794178825Sdfr    /*
795178825Sdfr     *
796178825Sdfr     */
797178825Sdfr
798178825Sdfr    list = permutate_all(&slaves, &num_list);
799178825Sdfr
800178825Sdfr    /*
801178825Sdfr     * Set up connection to all clients
802178825Sdfr     */
803178825Sdfr
804178825Sdfr    printf("Connecting to slaves\n");
805178825Sdfr    for (i = 0; i < slaves.num_strings; i++)
806178825Sdfr	connect_client(slaves.strings[i]);
807178825Sdfr
808178825Sdfr    /*
809178825Sdfr     * Test acquire credentials
810178825Sdfr     */
811178825Sdfr
812178825Sdfr    printf("Test acquire credentials\n");
813178825Sdfr    for (i = 0; i < slaves.num_strings; i++) {
814178825Sdfr	int32_t hCred, val;
815178825Sdfr
816178825Sdfr	val = acquire_cred(clients[i], user, password, 1, &hCred);
817178825Sdfr	if (val != GSMERR_OK) {
818233294Sstas	    warnx("Failed to acquire_cred on host %s: %d",
819178825Sdfr		 clients[i]->moniker, (int)val);
820178825Sdfr	    failed = 1;
821178825Sdfr	} else
822178825Sdfr	    toast_resource(clients[i], hCred);
823178825Sdfr    }
824178825Sdfr
825178825Sdfr    if (failed)
826178825Sdfr	goto out;
827178825Sdfr
828233294Sstas    /*
829178825Sdfr     * First test if all slaves can build context to them-self.
830178825Sdfr     */
831178825Sdfr
832178825Sdfr    printf("Self context tests\n");
833178825Sdfr    for (i = 0; i < num_clients; i++) {
834178825Sdfr	int32_t hCred, val, delegCred;
835178825Sdfr	int32_t clientC, serverC;
836178825Sdfr	struct client *c = clients[i];
837233294Sstas
838178825Sdfr	if (c->target_name == NULL)
839178825Sdfr	    continue;
840178825Sdfr
841178825Sdfr	printf("%s connects to self using %s\n",
842178825Sdfr	       c->moniker, c->target_name);
843178825Sdfr
844178825Sdfr	val = acquire_cred(c, user, password, 1, &hCred);
845178825Sdfr	if (val != GSMERR_OK)
846178825Sdfr	    errx(1, "failed to acquire_cred: %d", (int)val);
847233294Sstas
848233294Sstas	val = build_context(c, c,
849178825Sdfr			    GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG|
850178825Sdfr			    GSS_C_INTEG_FLAG|GSS_C_CONF_FLAG|
851178825Sdfr			    GSS_C_DELEG_FLAG|GSS_C_MUTUAL_FLAG,
852178825Sdfr			    hCred, &clientC, &serverC, &delegCred);
853178825Sdfr	if (val == GSMERR_OK) {
854233294Sstas	    test_token(c, clientC, c, serverC, wrap_ext);
855178825Sdfr	    toast_resource(c, clientC);
856178825Sdfr	    toast_resource(c, serverC);
857178825Sdfr	    if (delegCred)
858178825Sdfr		toast_resource(c, delegCred);
859178825Sdfr	} else {
860178825Sdfr	    warnx("build_context failed: %d", (int)val);
861178825Sdfr	}
862178825Sdfr	/*
863178825Sdfr	 *
864178825Sdfr	 */
865178825Sdfr
866178825Sdfr	val = build_context(c, c,
867178825Sdfr			    GSS_C_INTEG_FLAG|GSS_C_CONF_FLAG,
868178825Sdfr			    hCred, &clientC, &serverC, &delegCred);
869178825Sdfr	if (val == GSMERR_OK) {
870233294Sstas	    test_token(c, clientC, c, serverC, wrap_ext);
871178825Sdfr	    toast_resource(c, clientC);
872178825Sdfr	    toast_resource(c, serverC);
873178825Sdfr	    if (delegCred)
874178825Sdfr		toast_resource(c, delegCred);
875178825Sdfr	} else {
876178825Sdfr	    warnx("build_context failed: %d", (int)val);
877178825Sdfr	}
878178825Sdfr
879178825Sdfr	toast_resource(c, hCred);
880178825Sdfr    }
881178825Sdfr    /*
882178825Sdfr     * Build contexts though all entries in each lists, including the
883178825Sdfr     * step from the last entry to the first, ie treat the list as a
884178825Sdfr     * circle.
885178825Sdfr     *
886178825Sdfr     * Only follow the delegated credential, but test "all"
887178825Sdfr     * flags. (XXX only do deleg|mutual right now.
888178825Sdfr     */
889178825Sdfr
890178825Sdfr    printf("\"All\" permutation tests\n");
891178825Sdfr
892178825Sdfr    for (i = 0; i < num_list; i++) {
893178825Sdfr	int32_t hCred, val, delegCred = 0;
894178825Sdfr	int32_t clientC = 0, serverC = 0;
895178825Sdfr	struct client *client, *server;
896233294Sstas
897178825Sdfr	p = list[i];
898233294Sstas
899178825Sdfr	client = get_client(p[0]);
900233294Sstas
901178825Sdfr	val = acquire_cred(client, user, password, 1, &hCred);
902178825Sdfr	if (val != GSMERR_OK)
903178825Sdfr	    errx(1, "failed to acquire_cred: %d", (int)val);
904178825Sdfr
905178825Sdfr	for (j = 1; j < num_clients + 1; j++) {
906178825Sdfr	    server = get_client(p[j % num_clients]);
907233294Sstas
908178825Sdfr	    if (server->target_name == NULL)
909178825Sdfr		break;
910178825Sdfr
911178825Sdfr	    for (k = 1; k < j; k++)
912178825Sdfr		printf("\t");
913178825Sdfr	    printf("%s -> %s\n", client->moniker, server->moniker);
914178825Sdfr
915178825Sdfr	    val = build_context(client, server,
916178825Sdfr				GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG|
917178825Sdfr				GSS_C_INTEG_FLAG|GSS_C_CONF_FLAG|
918178825Sdfr				GSS_C_DELEG_FLAG|GSS_C_MUTUAL_FLAG,
919178825Sdfr				hCred, &clientC, &serverC, &delegCred);
920178825Sdfr	    if (val != GSMERR_OK) {
921178825Sdfr		warnx("build_context failed: %d", (int)val);
922178825Sdfr		break;
923178825Sdfr	    }
924233294Sstas
925233294Sstas	    val = test_token(client, clientC, server, serverC, wrap_ext);
926178825Sdfr	    if (val)
927178825Sdfr		break;
928233294Sstas
929178825Sdfr	    toast_resource(client, clientC);
930178825Sdfr	    toast_resource(server, serverC);
931178825Sdfr	    if (!delegCred) {
932178825Sdfr		warnx("no delegated cred on %s", server->moniker);
933178825Sdfr		break;
934178825Sdfr	    }
935178825Sdfr	    toast_resource(client, hCred);
936178825Sdfr	    hCred = delegCred;
937178825Sdfr	    client = server;
938178825Sdfr	}
939178825Sdfr	if (hCred)
940178825Sdfr	    toast_resource(client, hCred);
941178825Sdfr    }
942233294Sstas
943178825Sdfr    /*
944178825Sdfr     * Close all connections to clients
945178825Sdfr     */
946233294Sstas
947178825Sdfrout:
948178825Sdfr    printf("sending goodbye and waiting for log sockets\n");
949178825Sdfr    for (i = 0; i < num_clients; i++) {
950178825Sdfr	goodbye(clients[i]);
951178825Sdfr	if (clients[i]->logsock) {
952178825Sdfr#ifdef ENABLE_PTHREAD_SUPPORT
953178825Sdfr	    pthread_join(&clients[i]->thr, NULL);
954178825Sdfr#else
955178825Sdfr	    waitpid(clients[i]->child, NULL, 0);
956178825Sdfr#endif
957178825Sdfr	}
958178825Sdfr    }
959178825Sdfr
960178825Sdfr    printf("done\n");
961178825Sdfr
962178825Sdfr    return 0;
963178825Sdfr}
964