gssmaestro.c revision 178825
1178825Sdfr/* 2178825Sdfr * Copyright (c) 2006 Kungliga Tekniska H�gskolan 3178825Sdfr * (Royal Institute of Technology, Stockholm, Sweden). 4178825Sdfr * All rights reserved. 5178825Sdfr * 6178825Sdfr * Redistribution and use in source and binary forms, with or without 7178825Sdfr * modification, are permitted provided that the following conditions 8178825Sdfr * are met: 9178825Sdfr * 10178825Sdfr * 1. Redistributions of source code must retain the above copyright 11178825Sdfr * notice, this list of conditions and the following disclaimer. 12178825Sdfr * 13178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright 14178825Sdfr * notice, this list of conditions and the following disclaimer in the 15178825Sdfr * 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> 35178825SdfrRCSID("$Id: gssmaestro.c 21605 2007-07-17 06:51:57Z lha $"); 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 64178825Sdfrinit_sec_context(struct client *client, 65178825Sdfr int32_t *hContext, int32_t *hCred, 66178825Sdfr 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 85178825Sdfraccept_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 106178825Sdfracquire_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 123178825Sdfrtoast_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 141178825Sdfrget_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 165178825Sdfrdecrypt_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 180178825Sdfrget_mic(struct client *client, int32_t hContext, 181178825Sdfr krb5_data *in, krb5_data *mic) 182178825Sdfr{ 183178825Sdfr int32_t val; 184178825Sdfr put32(client, eSign); 185178825Sdfr put32(client, hContext); 186178825Sdfr put32(client, 0); 187178825Sdfr put32(client, 0); 188178825Sdfr putdata(client, *in); 189178825Sdfr ret32(client, val); 190178825Sdfr retdata(client, *mic); 191178825Sdfr return val; 192178825Sdfr} 193178825Sdfr 194178825Sdfrstatic int32_t 195178825Sdfrverify_mic(struct client *client, int32_t hContext, 196178825Sdfr krb5_data *in, krb5_data *mic) 197178825Sdfr{ 198178825Sdfr int32_t val; 199178825Sdfr put32(client, eVerify); 200178825Sdfr put32(client, hContext); 201178825Sdfr put32(client, 0); 202178825Sdfr put32(client, 0); 203178825Sdfr putdata(client, *in); 204178825Sdfr putdata(client, *mic); 205178825Sdfr ret32(client, val); 206178825Sdfr return val; 207178825Sdfr} 208178825Sdfr 209178825Sdfr 210178825Sdfrstatic int32_t 211178825Sdfrget_version_capa(struct client *client, 212178825Sdfr int32_t *version, int32_t *capa, 213178825Sdfr char **version_str) 214178825Sdfr{ 215178825Sdfr put32(client, eGetVersionAndCapabilities); 216178825Sdfr ret32(client, *version); 217178825Sdfr ret32(client, *capa); 218178825Sdfr retstring(client, *version_str); 219178825Sdfr return GSMERR_OK; 220178825Sdfr} 221178825Sdfr 222178825Sdfrstatic int32_t 223178825Sdfrget_moniker(struct client *client, 224178825Sdfr char **moniker) 225178825Sdfr{ 226178825Sdfr put32(client, eGetMoniker); 227178825Sdfr retstring(client, *moniker); 228178825Sdfr return GSMERR_OK; 229178825Sdfr} 230178825Sdfr 231178825Sdfrstatic int 232178825Sdfrwait_log(struct client *c) 233178825Sdfr{ 234178825Sdfr int32_t port; 235178825Sdfr struct sockaddr_storage sast; 236178825Sdfr socklen_t salen = sizeof(sast); 237178825Sdfr int fd, fd2, ret; 238178825Sdfr 239178825Sdfr memset(&sast, 0, sizeof(sast)); 240178825Sdfr 241178825Sdfr assert(sizeof(sast) >= c->salen); 242178825Sdfr 243178825Sdfr fd = socket(c->sa->sa_family, SOCK_STREAM, 0); 244178825Sdfr if (fd < 0) 245178825Sdfr err(1, "failed to build socket for %s's logging port", c->moniker); 246178825Sdfr 247178825Sdfr ((struct sockaddr *)&sast)->sa_family = c->sa->sa_family; 248178825Sdfr ret = bind(fd, (struct sockaddr *)&sast, c->salen); 249178825Sdfr if (ret < 0) 250178825Sdfr err(1, "failed to bind %s's logging port", c->moniker); 251178825Sdfr 252178825Sdfr if (listen(fd, SOMAXCONN) < 0) 253178825Sdfr err(1, "failed to listen %s's logging port", c->moniker); 254178825Sdfr 255178825Sdfr salen = sizeof(sast); 256178825Sdfr ret = getsockname(fd, (struct sockaddr *)&sast, &salen); 257178825Sdfr if (ret < 0) 258178825Sdfr err(1, "failed to get address of local socket for %s", c->moniker); 259178825Sdfr 260178825Sdfr port = socket_get_port((struct sockaddr *)&sast); 261178825Sdfr 262178825Sdfr put32(c, eSetLoggingSocket); 263178825Sdfr put32(c, ntohs(port)); 264178825Sdfr 265178825Sdfr salen = sizeof(sast); 266178825Sdfr fd2 = accept(fd, (struct sockaddr *)&sast, &salen); 267178825Sdfr if (fd2 < 0) 268178825Sdfr err(1, "failed to accept local socket for %s", c->moniker); 269178825Sdfr close(fd); 270178825Sdfr 271178825Sdfr return fd2; 272178825Sdfr} 273178825Sdfr 274178825Sdfr 275178825Sdfr 276178825Sdfr 277178825Sdfrstatic int 278178825Sdfrbuild_context(struct client *ipeer, struct client *apeer, 279178825Sdfr int32_t flags, int32_t hCred, 280178825Sdfr int32_t *iContext, int32_t *aContext, int32_t *hDelegCred) 281178825Sdfr{ 282178825Sdfr int32_t val = GSMERR_ERROR, ic = 0, ac = 0, deleg = 0; 283178825Sdfr krb5_data itoken, otoken; 284178825Sdfr int iDone = 0, aDone = 0; 285178825Sdfr int step = 0; 286178825Sdfr int first_call = 0x80; 287178825Sdfr 288178825Sdfr if (apeer->target_name == NULL) 289178825Sdfr errx(1, "apeer %s have no target name", apeer->name); 290178825Sdfr 291178825Sdfr krb5_data_zero(&itoken); 292178825Sdfr 293178825Sdfr while (!iDone || !aDone) { 294178825Sdfr 295178825Sdfr if (iDone) { 296178825Sdfr warnx("iPeer already done, aPeer want extra rtt"); 297178825Sdfr val = GSMERR_ERROR; 298178825Sdfr goto out; 299178825Sdfr } 300178825Sdfr 301178825Sdfr val = init_sec_context(ipeer, &ic, &hCred, flags|first_call, 302178825Sdfr apeer->target_name, &itoken, &otoken); 303178825Sdfr step++; 304178825Sdfr switch(val) { 305178825Sdfr case GSMERR_OK: 306178825Sdfr iDone = 1; 307178825Sdfr if (aDone) 308178825Sdfr continue; 309178825Sdfr break; 310178825Sdfr case GSMERR_CONTINUE_NEEDED: 311178825Sdfr break; 312178825Sdfr default: 313178825Sdfr warnx("iPeer %s failed with %d (step %d)", 314178825Sdfr ipeer->name, (int)val, step); 315178825Sdfr goto out; 316178825Sdfr } 317178825Sdfr 318178825Sdfr if (aDone) { 319178825Sdfr warnx("aPeer already done, iPeer want extra rtt"); 320178825Sdfr val = GSMERR_ERROR; 321178825Sdfr goto out; 322178825Sdfr } 323178825Sdfr 324178825Sdfr val = accept_sec_context(apeer, &ac, flags|first_call, 325178825Sdfr &otoken, &itoken, &deleg); 326178825Sdfr step++; 327178825Sdfr switch(val) { 328178825Sdfr case GSMERR_OK: 329178825Sdfr aDone = 1; 330178825Sdfr if (iDone) 331178825Sdfr continue; 332178825Sdfr break; 333178825Sdfr case GSMERR_CONTINUE_NEEDED: 334178825Sdfr break; 335178825Sdfr default: 336178825Sdfr warnx("aPeer %s failed with %d (step %d)", 337178825Sdfr apeer->name, (int)val, step); 338178825Sdfr val = GSMERR_ERROR; 339178825Sdfr goto out; 340178825Sdfr } 341178825Sdfr first_call = 0; 342178825Sdfr val = GSMERR_OK; 343178825Sdfr } 344178825Sdfr 345178825Sdfr if (iContext == NULL || val != GSMERR_OK) { 346178825Sdfr if (ic) 347178825Sdfr toast_resource(ipeer, ic); 348178825Sdfr if (iContext) 349178825Sdfr *iContext = 0; 350178825Sdfr } else 351178825Sdfr *iContext = ic; 352178825Sdfr 353178825Sdfr if (aContext == NULL || val != GSMERR_OK) { 354178825Sdfr if (ac) 355178825Sdfr toast_resource(apeer, ac); 356178825Sdfr if (aContext) 357178825Sdfr *aContext = 0; 358178825Sdfr } else 359178825Sdfr *aContext = ac; 360178825Sdfr 361178825Sdfr if (hDelegCred == NULL || val != GSMERR_OK) { 362178825Sdfr if (deleg) 363178825Sdfr toast_resource(apeer, deleg); 364178825Sdfr if (hDelegCred) 365178825Sdfr *hDelegCred = 0; 366178825Sdfr } else 367178825Sdfr *hDelegCred = deleg; 368178825Sdfr 369178825Sdfrout: 370178825Sdfr return val; 371178825Sdfr} 372178825Sdfr 373178825Sdfrstatic void 374178825Sdfrtest_mic(struct client *c1, int32_t hc1, struct client *c2, int32_t hc2) 375178825Sdfr{ 376178825Sdfr krb5_data msg, mic; 377178825Sdfr int32_t val; 378178825Sdfr 379178825Sdfr msg.data = "foo"; 380178825Sdfr msg.length = 3; 381178825Sdfr 382178825Sdfr krb5_data_zero(&mic); 383178825Sdfr 384178825Sdfr val = get_mic(c1, hc1, &msg, &mic); 385178825Sdfr if (val) 386178825Sdfr errx(1, "get_mic failed to host: %s", c1->moniker); 387178825Sdfr val = verify_mic(c2, hc2, &msg, &mic); 388178825Sdfr if (val) 389178825Sdfr errx(1, "verify_mic failed to host: %s", c2->moniker); 390178825Sdfr 391178825Sdfr krb5_data_free(&mic); 392178825Sdfr} 393178825Sdfr 394178825Sdfrstatic int32_t 395178825Sdfrtest_wrap(struct client *c1, int32_t hc1, struct client *c2, int32_t hc2, 396178825Sdfr int conf) 397178825Sdfr{ 398178825Sdfr krb5_data msg, wrapped, out; 399178825Sdfr int32_t val; 400178825Sdfr 401178825Sdfr msg.data = "foo"; 402178825Sdfr msg.length = 3; 403178825Sdfr 404178825Sdfr krb5_data_zero(&wrapped); 405178825Sdfr krb5_data_zero(&out); 406178825Sdfr 407178825Sdfr val = encrypt_token(c1, hc1, conf, &msg, &wrapped); 408178825Sdfr if (val) { 409178825Sdfr warnx("encrypt_token failed to host: %s", c1->moniker); 410178825Sdfr return val; 411178825Sdfr } 412178825Sdfr val = decrypt_token(c2, hc2, conf, &wrapped, &out); 413178825Sdfr if (val) { 414178825Sdfr krb5_data_free(&wrapped); 415178825Sdfr warnx("decrypt_token failed to host: %s", c2->moniker); 416178825Sdfr return val; 417178825Sdfr } 418178825Sdfr 419178825Sdfr if (msg.length != out.length) { 420178825Sdfr warnx("decrypted'ed token have wrong length (%lu != %lu)", 421178825Sdfr (unsigned long)msg.length, (unsigned long)out.length); 422178825Sdfr val = GSMERR_ERROR; 423178825Sdfr } else if (memcmp(msg.data, out.data, msg.length) != 0) { 424178825Sdfr warnx("decryptd'ed token have wrong data"); 425178825Sdfr val = GSMERR_ERROR; 426178825Sdfr } 427178825Sdfr 428178825Sdfr krb5_data_free(&wrapped); 429178825Sdfr krb5_data_free(&out); 430178825Sdfr return val; 431178825Sdfr} 432178825Sdfr 433178825Sdfrstatic int32_t 434178825Sdfrtest_token(struct client *c1, int32_t hc1, struct client *c2, int32_t hc2) 435178825Sdfr{ 436178825Sdfr int32_t val; 437178825Sdfr int i; 438178825Sdfr 439178825Sdfr for (i = 0; i < 10; i++) { 440178825Sdfr test_mic(c1, hc1, c2, hc2); 441178825Sdfr test_mic(c2, hc2, c1, hc1); 442178825Sdfr val = test_wrap(c1, hc1, c2, hc2, 0); 443178825Sdfr if (val) return val; 444178825Sdfr val = test_wrap(c2, hc2, c1, hc1, 0); 445178825Sdfr if (val) return val; 446178825Sdfr val = test_wrap(c1, hc1, c2, hc2, 1); 447178825Sdfr if (val) return val; 448178825Sdfr val = test_wrap(c2, hc2, c1, hc1, 1); 449178825Sdfr if (val) return val; 450178825Sdfr } 451178825Sdfr return GSMERR_OK; 452178825Sdfr} 453178825Sdfr 454178825Sdfrstatic int 455178825Sdfrlog_function(void *ptr) 456178825Sdfr{ 457178825Sdfr struct client *c = ptr; 458178825Sdfr int32_t cmd, line; 459178825Sdfr char *file, *string; 460178825Sdfr 461178825Sdfr while (1) { 462178825Sdfr if (krb5_ret_int32(c->logsock, &cmd)) 463178825Sdfr goto out; 464178825Sdfr 465178825Sdfr switch (cmd) { 466178825Sdfr case eLogSetMoniker: 467178825Sdfr if (krb5_ret_string(c->logsock, &file)) 468178825Sdfr goto out; 469178825Sdfr free(file); 470178825Sdfr break; 471178825Sdfr case eLogInfo: 472178825Sdfr case eLogFailure: 473178825Sdfr if (krb5_ret_string(c->logsock, &file)) 474178825Sdfr goto out; 475178825Sdfr if (krb5_ret_int32(c->logsock, &line)) 476178825Sdfr goto out; 477178825Sdfr if (krb5_ret_string(c->logsock, &string)) 478178825Sdfr goto out; 479178825Sdfr printf("%s:%lu: %s\n", 480178825Sdfr file, (unsigned long)line, string); 481178825Sdfr fprintf(logfile, "%s:%lu: %s\n", 482178825Sdfr file, (unsigned long)line, string); 483178825Sdfr fflush(logfile); 484178825Sdfr free(file); 485178825Sdfr free(string); 486178825Sdfr if (krb5_store_int32(c->logsock, 0)) 487178825Sdfr goto out; 488178825Sdfr break; 489178825Sdfr default: 490178825Sdfr errx(1, "client send bad log command: %d", (int)cmd); 491178825Sdfr } 492178825Sdfr } 493178825Sdfrout: 494178825Sdfr 495178825Sdfr return 0; 496178825Sdfr} 497178825Sdfr 498178825Sdfrstatic void 499178825Sdfrconnect_client(const char *slave) 500178825Sdfr{ 501178825Sdfr char *name, *port; 502178825Sdfr struct client *c = ecalloc(1, sizeof(*c)); 503178825Sdfr struct addrinfo hints, *res0, *res; 504178825Sdfr int ret, fd; 505178825Sdfr 506178825Sdfr name = estrdup(slave); 507178825Sdfr port = strchr(name, ':'); 508178825Sdfr if (port == NULL) 509178825Sdfr errx(1, "port missing from %s", name); 510178825Sdfr *port++ = 0; 511178825Sdfr 512178825Sdfr c->name = estrdup(slave); 513178825Sdfr 514178825Sdfr memset(&hints, 0, sizeof(hints)); 515178825Sdfr hints.ai_family = PF_UNSPEC; 516178825Sdfr hints.ai_socktype = SOCK_STREAM; 517178825Sdfr 518178825Sdfr ret = getaddrinfo(name, port, &hints, &res0); 519178825Sdfr if (ret) 520178825Sdfr errx(1, "error resolving %s", name); 521178825Sdfr 522178825Sdfr for (res = res0, fd = -1; res; res = res->ai_next) { 523178825Sdfr fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 524178825Sdfr if (fd < 0) 525178825Sdfr continue; 526178825Sdfr if (connect(fd, res->ai_addr, res->ai_addrlen) < 0) { 527178825Sdfr close(fd); 528178825Sdfr fd = -1; 529178825Sdfr continue; 530178825Sdfr } 531178825Sdfr c->sa = ecalloc(1, res->ai_addrlen); 532178825Sdfr memcpy(c->sa, res->ai_addr, res->ai_addrlen); 533178825Sdfr c->salen = res->ai_addrlen; 534178825Sdfr break; /* okay we got one */ 535178825Sdfr } 536178825Sdfr if (fd < 0) 537178825Sdfr err(1, "connect to host: %s", name); 538178825Sdfr freeaddrinfo(res); 539178825Sdfr 540178825Sdfr c->sock = krb5_storage_from_fd(fd); 541178825Sdfr close(fd); 542178825Sdfr if (c->sock == NULL) 543178825Sdfr errx(1, "krb5_storage_from_fd"); 544178825Sdfr 545178825Sdfr { 546178825Sdfr int32_t version; 547178825Sdfr char *str = NULL; 548178825Sdfr get_version_capa(c, &version, &c->capabilities, &str); 549178825Sdfr if (str) { 550178825Sdfr free(str); 551178825Sdfr } 552178825Sdfr if (c->capabilities & HAS_MONIKER) 553178825Sdfr get_moniker(c, &c->moniker); 554178825Sdfr else 555178825Sdfr c->moniker = c->name; 556178825Sdfr if (c->capabilities & ISSERVER) 557178825Sdfr get_targetname(c, &c->target_name); 558178825Sdfr } 559178825Sdfr 560178825Sdfr if (logfile) { 561178825Sdfr int fd; 562178825Sdfr 563178825Sdfr printf("starting log socket to client %s\n", c->moniker); 564178825Sdfr 565178825Sdfr fd = wait_log(c); 566178825Sdfr 567178825Sdfr c->logsock = krb5_storage_from_fd(fd); 568178825Sdfr close(fd); 569178825Sdfr if (c->logsock == NULL) 570178825Sdfr errx(1, "failed to create log krb5_storage"); 571178825Sdfr#ifdef ENABLE_PTHREAD_SUPPORT 572178825Sdfr pthread_create(&c->thr, NULL, log_function, c); 573178825Sdfr#else 574178825Sdfr c->child = fork(); 575178825Sdfr if (c->child == -1) 576178825Sdfr errx(1, "failed to fork"); 577178825Sdfr else if (c->child == 0) { 578178825Sdfr log_function(c); 579178825Sdfr fclose(logfile); 580178825Sdfr exit(0); 581178825Sdfr } 582178825Sdfr#endif 583178825Sdfr } 584178825Sdfr 585178825Sdfr 586178825Sdfr clients = erealloc(clients, (num_clients + 1) * sizeof(*clients)); 587178825Sdfr 588178825Sdfr clients[num_clients] = c; 589178825Sdfr num_clients++; 590178825Sdfr 591178825Sdfr free(name); 592178825Sdfr} 593178825Sdfr 594178825Sdfrstatic struct client * 595178825Sdfrget_client(const char *slave) 596178825Sdfr{ 597178825Sdfr size_t i; 598178825Sdfr for (i = 0; i < num_clients; i++) 599178825Sdfr if (strcmp(slave, clients[i]->name) == 0) 600178825Sdfr return clients[i]; 601178825Sdfr errx(1, "failed to find client %s", slave); 602178825Sdfr} 603178825Sdfr 604178825Sdfr/* 605178825Sdfr * 606178825Sdfr */ 607178825Sdfr 608178825Sdfrstatic int version_flag; 609178825Sdfrstatic int help_flag; 610178825Sdfrstatic char *logfile_str; 611178825Sdfrstatic getarg_strings principals; 612178825Sdfrstatic getarg_strings slaves; 613178825Sdfr 614178825Sdfrstruct getargs args[] = { 615178825Sdfr { "principals", 0, arg_strings, &principals, "Test principal", 616178825Sdfr NULL }, 617178825Sdfr { "slaves", 0, arg_strings, &slaves, "Slaves", 618178825Sdfr NULL }, 619178825Sdfr { "log-file", 0, arg_string, &logfile_str, "Logfile", 620178825Sdfr NULL }, 621178825Sdfr { "version", 0, arg_flag, &version_flag, "Print version", 622178825Sdfr NULL }, 623178825Sdfr { "help", 0, arg_flag, &help_flag, NULL, 624178825Sdfr NULL } 625178825Sdfr}; 626178825Sdfr 627178825Sdfrstatic void 628178825Sdfrusage(int ret) 629178825Sdfr{ 630178825Sdfr arg_printusage (args, 631178825Sdfr sizeof(args) / sizeof(args[0]), 632178825Sdfr NULL, 633178825Sdfr ""); 634178825Sdfr exit (ret); 635178825Sdfr} 636178825Sdfr 637178825Sdfrint 638178825Sdfrmain(int argc, char **argv) 639178825Sdfr{ 640178825Sdfr int optidx= 0; 641178825Sdfr char *user; 642178825Sdfr char *password; 643178825Sdfr char ***list, **p; 644178825Sdfr size_t num_list, i, j, k; 645178825Sdfr int failed = 0; 646178825Sdfr 647178825Sdfr setprogname (argv[0]); 648178825Sdfr 649178825Sdfr if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) 650178825Sdfr usage (1); 651178825Sdfr 652178825Sdfr if (help_flag) 653178825Sdfr usage (0); 654178825Sdfr 655178825Sdfr if (version_flag) { 656178825Sdfr print_version (NULL); 657178825Sdfr return 0; 658178825Sdfr } 659178825Sdfr 660178825Sdfr if (optidx != argc) 661178825Sdfr usage (1); 662178825Sdfr 663178825Sdfr if (principals.num_strings == 0) 664178825Sdfr errx(1, "no principals"); 665178825Sdfr 666178825Sdfr user = estrdup(principals.strings[0]); 667178825Sdfr password = strchr(user, ':'); 668178825Sdfr if (password == NULL) 669178825Sdfr errx(1, "password missing from %s", user); 670178825Sdfr *password++ = 0; 671178825Sdfr 672178825Sdfr if (slaves.num_strings == 0) 673178825Sdfr errx(1, "no principals"); 674178825Sdfr 675178825Sdfr if (logfile_str) { 676178825Sdfr printf("open logfile %s\n", logfile_str); 677178825Sdfr logfile = fopen(logfile_str, "w+"); 678178825Sdfr if (logfile == NULL) 679178825Sdfr err(1, "failed to open: %s", logfile_str); 680178825Sdfr } 681178825Sdfr 682178825Sdfr /* 683178825Sdfr * 684178825Sdfr */ 685178825Sdfr 686178825Sdfr list = permutate_all(&slaves, &num_list); 687178825Sdfr 688178825Sdfr /* 689178825Sdfr * Set up connection to all clients 690178825Sdfr */ 691178825Sdfr 692178825Sdfr printf("Connecting to slaves\n"); 693178825Sdfr for (i = 0; i < slaves.num_strings; i++) 694178825Sdfr connect_client(slaves.strings[i]); 695178825Sdfr 696178825Sdfr /* 697178825Sdfr * Test acquire credentials 698178825Sdfr */ 699178825Sdfr 700178825Sdfr printf("Test acquire credentials\n"); 701178825Sdfr for (i = 0; i < slaves.num_strings; i++) { 702178825Sdfr int32_t hCred, val; 703178825Sdfr 704178825Sdfr val = acquire_cred(clients[i], user, password, 1, &hCred); 705178825Sdfr if (val != GSMERR_OK) { 706178825Sdfr warnx("Failed to acquire_cred on host %s: %d", 707178825Sdfr clients[i]->moniker, (int)val); 708178825Sdfr failed = 1; 709178825Sdfr } else 710178825Sdfr toast_resource(clients[i], hCred); 711178825Sdfr } 712178825Sdfr 713178825Sdfr if (failed) 714178825Sdfr goto out; 715178825Sdfr 716178825Sdfr /* 717178825Sdfr * First test if all slaves can build context to them-self. 718178825Sdfr */ 719178825Sdfr 720178825Sdfr printf("Self context tests\n"); 721178825Sdfr for (i = 0; i < num_clients; i++) { 722178825Sdfr int32_t hCred, val, delegCred; 723178825Sdfr int32_t clientC, serverC; 724178825Sdfr struct client *c = clients[i]; 725178825Sdfr 726178825Sdfr if (c->target_name == NULL) 727178825Sdfr continue; 728178825Sdfr 729178825Sdfr printf("%s connects to self using %s\n", 730178825Sdfr c->moniker, c->target_name); 731178825Sdfr 732178825Sdfr val = acquire_cred(c, user, password, 1, &hCred); 733178825Sdfr if (val != GSMERR_OK) 734178825Sdfr errx(1, "failed to acquire_cred: %d", (int)val); 735178825Sdfr 736178825Sdfr val = build_context(c, c, 737178825Sdfr GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG| 738178825Sdfr GSS_C_INTEG_FLAG|GSS_C_CONF_FLAG| 739178825Sdfr GSS_C_DELEG_FLAG|GSS_C_MUTUAL_FLAG, 740178825Sdfr hCred, &clientC, &serverC, &delegCred); 741178825Sdfr if (val == GSMERR_OK) { 742178825Sdfr test_token(c, clientC, c, serverC); 743178825Sdfr toast_resource(c, clientC); 744178825Sdfr toast_resource(c, serverC); 745178825Sdfr if (delegCred) 746178825Sdfr toast_resource(c, delegCred); 747178825Sdfr } else { 748178825Sdfr warnx("build_context failed: %d", (int)val); 749178825Sdfr } 750178825Sdfr /* 751178825Sdfr * 752178825Sdfr */ 753178825Sdfr 754178825Sdfr val = build_context(c, c, 755178825Sdfr GSS_C_INTEG_FLAG|GSS_C_CONF_FLAG, 756178825Sdfr hCred, &clientC, &serverC, &delegCred); 757178825Sdfr if (val == GSMERR_OK) { 758178825Sdfr test_token(c, clientC, c, serverC); 759178825Sdfr toast_resource(c, clientC); 760178825Sdfr toast_resource(c, serverC); 761178825Sdfr if (delegCred) 762178825Sdfr toast_resource(c, delegCred); 763178825Sdfr } else { 764178825Sdfr warnx("build_context failed: %d", (int)val); 765178825Sdfr } 766178825Sdfr 767178825Sdfr toast_resource(c, hCred); 768178825Sdfr } 769178825Sdfr /* 770178825Sdfr * Build contexts though all entries in each lists, including the 771178825Sdfr * step from the last entry to the first, ie treat the list as a 772178825Sdfr * circle. 773178825Sdfr * 774178825Sdfr * Only follow the delegated credential, but test "all" 775178825Sdfr * flags. (XXX only do deleg|mutual right now. 776178825Sdfr */ 777178825Sdfr 778178825Sdfr printf("\"All\" permutation tests\n"); 779178825Sdfr 780178825Sdfr for (i = 0; i < num_list; i++) { 781178825Sdfr int32_t hCred, val, delegCred = 0; 782178825Sdfr int32_t clientC = 0, serverC = 0; 783178825Sdfr struct client *client, *server; 784178825Sdfr 785178825Sdfr p = list[i]; 786178825Sdfr 787178825Sdfr client = get_client(p[0]); 788178825Sdfr 789178825Sdfr val = acquire_cred(client, user, password, 1, &hCred); 790178825Sdfr if (val != GSMERR_OK) 791178825Sdfr errx(1, "failed to acquire_cred: %d", (int)val); 792178825Sdfr 793178825Sdfr for (j = 1; j < num_clients + 1; j++) { 794178825Sdfr server = get_client(p[j % num_clients]); 795178825Sdfr 796178825Sdfr if (server->target_name == NULL) 797178825Sdfr break; 798178825Sdfr 799178825Sdfr for (k = 1; k < j; k++) 800178825Sdfr printf("\t"); 801178825Sdfr printf("%s -> %s\n", client->moniker, server->moniker); 802178825Sdfr 803178825Sdfr val = build_context(client, server, 804178825Sdfr GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG| 805178825Sdfr GSS_C_INTEG_FLAG|GSS_C_CONF_FLAG| 806178825Sdfr GSS_C_DELEG_FLAG|GSS_C_MUTUAL_FLAG, 807178825Sdfr hCred, &clientC, &serverC, &delegCred); 808178825Sdfr if (val != GSMERR_OK) { 809178825Sdfr warnx("build_context failed: %d", (int)val); 810178825Sdfr break; 811178825Sdfr } 812178825Sdfr 813178825Sdfr val = test_token(client, clientC, server, serverC); 814178825Sdfr if (val) 815178825Sdfr break; 816178825Sdfr 817178825Sdfr toast_resource(client, clientC); 818178825Sdfr toast_resource(server, serverC); 819178825Sdfr if (!delegCred) { 820178825Sdfr warnx("no delegated cred on %s", server->moniker); 821178825Sdfr break; 822178825Sdfr } 823178825Sdfr toast_resource(client, hCred); 824178825Sdfr hCred = delegCred; 825178825Sdfr client = server; 826178825Sdfr } 827178825Sdfr if (hCred) 828178825Sdfr toast_resource(client, hCred); 829178825Sdfr } 830178825Sdfr 831178825Sdfr /* 832178825Sdfr * Close all connections to clients 833178825Sdfr */ 834178825Sdfr 835178825Sdfrout: 836178825Sdfr printf("sending goodbye and waiting for log sockets\n"); 837178825Sdfr for (i = 0; i < num_clients; i++) { 838178825Sdfr goodbye(clients[i]); 839178825Sdfr if (clients[i]->logsock) { 840178825Sdfr#ifdef ENABLE_PTHREAD_SUPPORT 841178825Sdfr pthread_join(&clients[i]->thr, NULL); 842178825Sdfr#else 843178825Sdfr waitpid(clients[i]->child, NULL, 0); 844178825Sdfr#endif 845178825Sdfr } 846178825Sdfr } 847178825Sdfr 848178825Sdfr printf("done\n"); 849178825Sdfr 850178825Sdfr return 0; 851178825Sdfr} 852