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