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 37178825Sdfr/* 38178825Sdfr * 39178825Sdfr */ 40178825Sdfr 41178825Sdfrenum handle_type { handle_context, handle_cred }; 42178825Sdfr 43178825Sdfrstruct handle { 44178825Sdfr int32_t idx; 45178825Sdfr enum handle_type type; 46178825Sdfr void *ptr; 47178825Sdfr struct handle *next; 48178825Sdfr}; 49178825Sdfr 50178825Sdfrstruct client { 51178825Sdfr krb5_storage *sock; 52178825Sdfr krb5_storage *logging; 53178825Sdfr char *moniker; 54178825Sdfr int32_t nHandle; 55178825Sdfr struct handle *handles; 56178825Sdfr struct sockaddr_storage sa; 57178825Sdfr socklen_t salen; 58178825Sdfr char servername[MAXHOSTNAMELEN]; 59178825Sdfr}; 60178825Sdfr 61178825SdfrFILE *logfile; 62178825Sdfrstatic char *targetname; 63178825Sdfrkrb5_context context; 64178825Sdfr 65178825Sdfr/* 66178825Sdfr * 67178825Sdfr */ 68178825Sdfr 69178825Sdfrstatic void 70178825Sdfrlogmessage(struct client *c, const char *file, unsigned int lineno, 71178825Sdfr int level, const char *fmt, ...) 72178825Sdfr{ 73178825Sdfr char *message; 74178825Sdfr va_list ap; 75178825Sdfr int32_t ackid; 76178825Sdfr 77178825Sdfr va_start(ap, fmt); 78178825Sdfr vasprintf(&message, fmt, ap); 79178825Sdfr va_end(ap); 80178825Sdfr 81178825Sdfr if (logfile) 82178825Sdfr fprintf(logfile, "%s:%u: %d %s\n", file, lineno, level, message); 83178825Sdfr 84178825Sdfr if (c->logging) { 85178825Sdfr if (krb5_store_int32(c->logging, eLogInfo) != 0) 86178825Sdfr errx(1, "krb5_store_int32: log level"); 87178825Sdfr if (krb5_store_string(c->logging, file) != 0) 88178825Sdfr errx(1, "krb5_store_string: filename"); 89178825Sdfr if (krb5_store_int32(c->logging, lineno) != 0) 90178825Sdfr errx(1, "krb5_store_string: filename"); 91178825Sdfr if (krb5_store_string(c->logging, message) != 0) 92178825Sdfr errx(1, "krb5_store_string: message"); 93178825Sdfr if (krb5_ret_int32(c->logging, &ackid) != 0) 94178825Sdfr errx(1, "krb5_ret_int32: ackid"); 95178825Sdfr } 96178825Sdfr free(message); 97178825Sdfr} 98178825Sdfr 99178825Sdfr/* 100178825Sdfr * 101178825Sdfr */ 102178825Sdfr 103178825Sdfrstatic int32_t 104178825Sdfradd_handle(struct client *c, enum handle_type type, void *data) 105178825Sdfr{ 106178825Sdfr struct handle *h; 107178825Sdfr 108178825Sdfr h = ecalloc(1, sizeof(*h)); 109178825Sdfr 110178825Sdfr h->idx = ++c->nHandle; 111178825Sdfr h->type = type; 112178825Sdfr h->ptr = data; 113178825Sdfr h->next = c->handles; 114178825Sdfr c->handles = h; 115178825Sdfr 116178825Sdfr return h->idx; 117178825Sdfr} 118178825Sdfr 119178825Sdfrstatic void 120178825Sdfrdel_handle(struct handle **h, int32_t idx) 121178825Sdfr{ 122178825Sdfr OM_uint32 min_stat; 123178825Sdfr 124178825Sdfr if (idx == 0) 125178825Sdfr return; 126178825Sdfr 127178825Sdfr while (*h) { 128178825Sdfr if ((*h)->idx == idx) { 129178825Sdfr struct handle *p = *h; 130178825Sdfr *h = (*h)->next; 131178825Sdfr switch(p->type) { 132178825Sdfr case handle_context: { 133178825Sdfr gss_ctx_id_t c = p->ptr; 134178825Sdfr gss_delete_sec_context(&min_stat, &c, NULL); 135178825Sdfr break; } 136178825Sdfr case handle_cred: { 137178825Sdfr gss_cred_id_t c = p->ptr; 138178825Sdfr gss_release_cred(&min_stat, &c); 139178825Sdfr break; } 140178825Sdfr } 141178825Sdfr free(p); 142178825Sdfr return; 143178825Sdfr } 144178825Sdfr h = &((*h)->next); 145178825Sdfr } 146178825Sdfr errx(1, "tried to delete an unexisting handle"); 147178825Sdfr} 148178825Sdfr 149178825Sdfrstatic void * 150178825Sdfrfind_handle(struct handle *h, int32_t idx, enum handle_type type) 151178825Sdfr{ 152178825Sdfr if (idx == 0) 153178825Sdfr return NULL; 154233294Sstas 155178825Sdfr while (h) { 156178825Sdfr if (h->idx == idx) { 157178825Sdfr if (type == h->type) 158178825Sdfr return h->ptr; 159178825Sdfr errx(1, "monger switched type on handle!"); 160178825Sdfr } 161178825Sdfr h = h->next; 162178825Sdfr } 163233294Sstas return NULL; 164178825Sdfr} 165178825Sdfr 166178825Sdfr 167178825Sdfrstatic int32_t 168178825Sdfrconvert_gss_to_gsm(OM_uint32 maj_stat) 169178825Sdfr{ 170178825Sdfr switch(maj_stat) { 171178825Sdfr case 0: 172178825Sdfr return GSMERR_OK; 173178825Sdfr case GSS_S_CONTINUE_NEEDED: 174178825Sdfr return GSMERR_CONTINUE_NEEDED; 175178825Sdfr case GSS_S_DEFECTIVE_TOKEN: 176178825Sdfr return GSMERR_INVALID_TOKEN; 177178825Sdfr case GSS_S_BAD_MIC: 178178825Sdfr return GSMERR_AP_MODIFIED; 179178825Sdfr default: 180178825Sdfr return GSMERR_ERROR; 181178825Sdfr } 182178825Sdfr} 183178825Sdfr 184178825Sdfrstatic int32_t 185178825Sdfrconvert_krb5_to_gsm(krb5_error_code ret) 186178825Sdfr{ 187178825Sdfr switch(ret) { 188178825Sdfr case 0: 189178825Sdfr return GSMERR_OK; 190178825Sdfr default: 191178825Sdfr return GSMERR_ERROR; 192178825Sdfr } 193178825Sdfr} 194178825Sdfr 195178825Sdfr/* 196178825Sdfr * 197178825Sdfr */ 198178825Sdfr 199178825Sdfrstatic int32_t 200178825Sdfracquire_cred(struct client *c, 201178825Sdfr krb5_principal principal, 202178825Sdfr krb5_get_init_creds_opt *opt, 203178825Sdfr int32_t *handle) 204178825Sdfr{ 205178825Sdfr krb5_error_code ret; 206178825Sdfr krb5_creds cred; 207178825Sdfr krb5_ccache id; 208178825Sdfr gss_cred_id_t gcred; 209178825Sdfr OM_uint32 maj_stat, min_stat; 210178825Sdfr 211178825Sdfr *handle = 0; 212178825Sdfr 213178825Sdfr krb5_get_init_creds_opt_set_forwardable (opt, 1); 214178825Sdfr krb5_get_init_creds_opt_set_renew_life (opt, 3600 * 24 * 30); 215178825Sdfr 216178825Sdfr memset(&cred, 0, sizeof(cred)); 217178825Sdfr 218178825Sdfr ret = krb5_get_init_creds_password (context, 219178825Sdfr &cred, 220178825Sdfr principal, 221178825Sdfr NULL, 222178825Sdfr NULL, 223178825Sdfr NULL, 224178825Sdfr 0, 225178825Sdfr NULL, 226178825Sdfr opt); 227178825Sdfr if (ret) { 228178825Sdfr logmessage(c, __FILE__, __LINE__, 0, 229178825Sdfr "krb5_get_init_creds failed: %d", ret); 230178825Sdfr return convert_krb5_to_gsm(ret); 231178825Sdfr } 232233294Sstas 233178825Sdfr ret = krb5_cc_new_unique(context, "MEMORY", NULL, &id); 234178825Sdfr if (ret) 235178825Sdfr krb5_err (context, 1, ret, "krb5_cc_initialize"); 236178825Sdfr 237178825Sdfr ret = krb5_cc_initialize (context, id, cred.client); 238178825Sdfr if (ret) 239178825Sdfr krb5_err (context, 1, ret, "krb5_cc_initialize"); 240233294Sstas 241178825Sdfr ret = krb5_cc_store_cred (context, id, &cred); 242178825Sdfr if (ret) 243178825Sdfr krb5_err (context, 1, ret, "krb5_cc_store_cred"); 244178825Sdfr 245178825Sdfr krb5_free_cred_contents (context, &cred); 246178825Sdfr 247178825Sdfr maj_stat = gss_krb5_import_cred(&min_stat, 248178825Sdfr id, 249178825Sdfr NULL, 250178825Sdfr NULL, 251178825Sdfr &gcred); 252178825Sdfr krb5_cc_close(context, id); 253178825Sdfr if (maj_stat) { 254178825Sdfr logmessage(c, __FILE__, __LINE__, 0, 255178825Sdfr "krb5 import creds failed with: %d", maj_stat); 256178825Sdfr return convert_gss_to_gsm(maj_stat); 257178825Sdfr } 258178825Sdfr 259178825Sdfr *handle = add_handle(c, handle_cred, gcred); 260178825Sdfr 261178825Sdfr return 0; 262178825Sdfr} 263178825Sdfr 264178825Sdfr 265178825Sdfr/* 266178825Sdfr * 267178825Sdfr */ 268178825Sdfr 269178825Sdfr#define HandleOP(h) \ 270178825Sdfrhandle##h(enum gssMaggotOp op, struct client *c) 271178825Sdfr 272178825Sdfr/* 273178825Sdfr * 274178825Sdfr */ 275178825Sdfr 276178825Sdfrstatic int 277178825SdfrHandleOP(GetVersionInfo) 278178825Sdfr{ 279178825Sdfr put32(c, GSSMAGGOTPROTOCOL); 280178825Sdfr errx(1, "GetVersionInfo"); 281178825Sdfr} 282178825Sdfr 283178825Sdfrstatic int 284178825SdfrHandleOP(GoodBye) 285178825Sdfr{ 286178825Sdfr struct handle *h = c->handles; 287233294Sstas unsigned int i = 0; 288178825Sdfr 289178825Sdfr while (h) { 290178825Sdfr h = h->next; 291178825Sdfr i++; 292178825Sdfr } 293178825Sdfr 294233294Sstas if (i) 295178825Sdfr logmessage(c, __FILE__, __LINE__, 0, 296178825Sdfr "Did not toast all resources: %d", i); 297178825Sdfr return 1; 298178825Sdfr} 299178825Sdfr 300178825Sdfrstatic int 301178825SdfrHandleOP(InitContext) 302178825Sdfr{ 303178825Sdfr OM_uint32 maj_stat, min_stat, ret_flags; 304178825Sdfr int32_t hContext, hCred, flags; 305178825Sdfr krb5_data target_name, in_token; 306178825Sdfr int32_t new_context_id = 0, gsm_error = 0; 307178825Sdfr krb5_data out_token = { 0 , NULL }; 308178825Sdfr 309178825Sdfr gss_ctx_id_t ctx; 310178825Sdfr gss_cred_id_t creds; 311178825Sdfr gss_name_t gss_target_name; 312178825Sdfr gss_buffer_desc input_token, output_token; 313178825Sdfr gss_OID oid = GSS_C_NO_OID; 314178825Sdfr gss_buffer_t input_token_ptr = GSS_C_NO_BUFFER; 315178825Sdfr 316178825Sdfr ret32(c, hContext); 317178825Sdfr ret32(c, hCred); 318178825Sdfr ret32(c, flags); 319178825Sdfr retdata(c, target_name); 320178825Sdfr retdata(c, in_token); 321178825Sdfr 322178825Sdfr logmessage(c, __FILE__, __LINE__, 0, 323178825Sdfr "targetname: <%.*s>", (int)target_name.length, 324178825Sdfr (char *)target_name.data); 325178825Sdfr 326178825Sdfr ctx = find_handle(c->handles, hContext, handle_context); 327178825Sdfr if (ctx == NULL) 328178825Sdfr hContext = 0; 329178825Sdfr creds = find_handle(c->handles, hCred, handle_cred); 330178825Sdfr if (creds == NULL) 331178825Sdfr abort(); 332178825Sdfr 333178825Sdfr input_token.length = target_name.length; 334178825Sdfr input_token.value = target_name.data; 335178825Sdfr 336178825Sdfr maj_stat = gss_import_name(&min_stat, 337178825Sdfr &input_token, 338178825Sdfr GSS_KRB5_NT_PRINCIPAL_NAME, 339178825Sdfr &gss_target_name); 340178825Sdfr if (GSS_ERROR(maj_stat)) { 341178825Sdfr logmessage(c, __FILE__, __LINE__, 0, 342178825Sdfr "import name creds failed with: %d", maj_stat); 343178825Sdfr gsm_error = convert_gss_to_gsm(maj_stat); 344178825Sdfr goto out; 345178825Sdfr } 346178825Sdfr 347178825Sdfr /* oid from flags */ 348178825Sdfr 349178825Sdfr if (in_token.length) { 350178825Sdfr input_token.length = in_token.length; 351178825Sdfr input_token.value = in_token.data; 352178825Sdfr input_token_ptr = &input_token; 353178825Sdfr if (ctx == NULL) 354178825Sdfr krb5_errx(context, 1, "initcreds, context NULL, but not first req"); 355178825Sdfr } else { 356178825Sdfr input_token.length = 0; 357178825Sdfr input_token.value = NULL; 358178825Sdfr if (ctx) 359178825Sdfr krb5_errx(context, 1, "initcreds, context not NULL, but first req"); 360178825Sdfr } 361233294Sstas 362178825Sdfr if ((flags & GSS_C_DELEG_FLAG) != 0) 363178825Sdfr logmessage(c, __FILE__, __LINE__, 0, "init_sec_context delegating"); 364178825Sdfr if ((flags & GSS_C_DCE_STYLE) != 0) 365178825Sdfr logmessage(c, __FILE__, __LINE__, 0, "init_sec_context dce-style"); 366178825Sdfr 367178825Sdfr maj_stat = gss_init_sec_context(&min_stat, 368178825Sdfr creds, 369178825Sdfr &ctx, 370178825Sdfr gss_target_name, 371178825Sdfr oid, 372178825Sdfr flags & 0x7f, 373233294Sstas 0, 374178825Sdfr NULL, 375178825Sdfr input_token_ptr, 376178825Sdfr NULL, 377178825Sdfr &output_token, 378178825Sdfr &ret_flags, 379178825Sdfr NULL); 380178825Sdfr if (GSS_ERROR(maj_stat)) { 381178825Sdfr if (hContext != 0) 382178825Sdfr del_handle(&c->handles, hContext); 383178825Sdfr new_context_id = 0; 384178825Sdfr logmessage(c, __FILE__, __LINE__, 0, 385233294Sstas "gss_init_sec_context returns code: %d/%d", 386178825Sdfr maj_stat, min_stat); 387178825Sdfr } else { 388178825Sdfr if (input_token.length == 0) 389178825Sdfr new_context_id = add_handle(c, handle_context, ctx); 390178825Sdfr else 391178825Sdfr new_context_id = hContext; 392178825Sdfr } 393178825Sdfr 394178825Sdfr gsm_error = convert_gss_to_gsm(maj_stat); 395178825Sdfr 396178825Sdfr if (output_token.length) { 397178825Sdfr out_token.data = output_token.value; 398178825Sdfr out_token.length = output_token.length; 399178825Sdfr } 400178825Sdfr 401178825Sdfrout: 402178825Sdfr logmessage(c, __FILE__, __LINE__, 0, 403178825Sdfr "InitContext return code: %d", gsm_error); 404178825Sdfr 405178825Sdfr put32(c, new_context_id); 406178825Sdfr put32(c, gsm_error); 407178825Sdfr putdata(c, out_token); 408178825Sdfr 409178825Sdfr gss_release_name(&min_stat, &gss_target_name); 410178825Sdfr if (output_token.length) 411178825Sdfr gss_release_buffer(&min_stat, &output_token); 412178825Sdfr krb5_data_free(&in_token); 413178825Sdfr krb5_data_free(&target_name); 414178825Sdfr 415178825Sdfr return 0; 416178825Sdfr} 417178825Sdfr 418178825Sdfrstatic int 419178825SdfrHandleOP(AcceptContext) 420178825Sdfr{ 421178825Sdfr OM_uint32 maj_stat, min_stat, ret_flags; 422178825Sdfr int32_t hContext, deleg_hcred, flags; 423178825Sdfr krb5_data in_token; 424178825Sdfr int32_t new_context_id = 0, gsm_error = 0; 425178825Sdfr krb5_data out_token = { 0 , NULL }; 426178825Sdfr 427178825Sdfr gss_ctx_id_t ctx; 428178825Sdfr gss_cred_id_t deleg_cred = GSS_C_NO_CREDENTIAL; 429178825Sdfr gss_buffer_desc input_token, output_token; 430178825Sdfr gss_buffer_t input_token_ptr = GSS_C_NO_BUFFER; 431178825Sdfr 432178825Sdfr ret32(c, hContext); 433178825Sdfr ret32(c, flags); 434178825Sdfr retdata(c, in_token); 435178825Sdfr 436178825Sdfr ctx = find_handle(c->handles, hContext, handle_context); 437178825Sdfr if (ctx == NULL) 438178825Sdfr hContext = 0; 439178825Sdfr 440178825Sdfr if (in_token.length) { 441178825Sdfr input_token.length = in_token.length; 442178825Sdfr input_token.value = in_token.data; 443178825Sdfr input_token_ptr = &input_token; 444178825Sdfr } else { 445178825Sdfr input_token.length = 0; 446178825Sdfr input_token.value = NULL; 447178825Sdfr } 448178825Sdfr 449178825Sdfr maj_stat = gss_accept_sec_context(&min_stat, 450178825Sdfr &ctx, 451178825Sdfr GSS_C_NO_CREDENTIAL, 452178825Sdfr &input_token, 453178825Sdfr GSS_C_NO_CHANNEL_BINDINGS, 454178825Sdfr NULL, 455178825Sdfr NULL, 456178825Sdfr &output_token, 457178825Sdfr &ret_flags, 458178825Sdfr NULL, 459178825Sdfr &deleg_cred); 460178825Sdfr if (GSS_ERROR(maj_stat)) { 461178825Sdfr if (hContext != 0) 462178825Sdfr del_handle(&c->handles, hContext); 463178825Sdfr logmessage(c, __FILE__, __LINE__, 0, 464233294Sstas "gss_accept_sec_context returns code: %d/%d", 465178825Sdfr maj_stat, min_stat); 466178825Sdfr new_context_id = 0; 467178825Sdfr } else { 468178825Sdfr if (hContext == 0) 469178825Sdfr new_context_id = add_handle(c, handle_context, ctx); 470178825Sdfr else 471178825Sdfr new_context_id = hContext; 472178825Sdfr } 473178825Sdfr if (output_token.length) { 474178825Sdfr out_token.data = output_token.value; 475178825Sdfr out_token.length = output_token.length; 476178825Sdfr } 477178825Sdfr if ((ret_flags & GSS_C_DCE_STYLE) != 0) 478178825Sdfr logmessage(c, __FILE__, __LINE__, 0, "accept_sec_context dce-style"); 479178825Sdfr if ((ret_flags & GSS_C_DELEG_FLAG) != 0) { 480178825Sdfr deleg_hcred = add_handle(c, handle_cred, deleg_cred); 481178825Sdfr logmessage(c, __FILE__, __LINE__, 0, 482178825Sdfr "accept_context delegated handle: %d", deleg_hcred); 483178825Sdfr } else { 484178825Sdfr gss_release_cred(&min_stat, &deleg_cred); 485178825Sdfr deleg_hcred = 0; 486178825Sdfr } 487233294Sstas 488233294Sstas 489178825Sdfr gsm_error = convert_gss_to_gsm(maj_stat); 490178825Sdfr 491178825Sdfr put32(c, new_context_id); 492178825Sdfr put32(c, gsm_error); 493178825Sdfr putdata(c, out_token); 494178825Sdfr put32(c, deleg_hcred); 495178825Sdfr 496178825Sdfr if (output_token.length) 497178825Sdfr gss_release_buffer(&min_stat, &output_token); 498178825Sdfr krb5_data_free(&in_token); 499178825Sdfr 500178825Sdfr return 0; 501178825Sdfr} 502178825Sdfr 503178825Sdfrstatic int 504178825SdfrHandleOP(ToastResource) 505178825Sdfr{ 506178825Sdfr int32_t handle; 507178825Sdfr 508178825Sdfr ret32(c, handle); 509178825Sdfr logmessage(c, __FILE__, __LINE__, 0, "toasting %d", handle); 510178825Sdfr del_handle(&c->handles, handle); 511178825Sdfr put32(c, GSMERR_OK); 512178825Sdfr 513178825Sdfr return 0; 514178825Sdfr} 515178825Sdfr 516178825Sdfrstatic int 517178825SdfrHandleOP(AcquireCreds) 518178825Sdfr{ 519178825Sdfr char *name, *password; 520178825Sdfr int32_t gsm_error, flags, handle = 0; 521178825Sdfr krb5_principal principal = NULL; 522178825Sdfr krb5_get_init_creds_opt *opt = NULL; 523178825Sdfr krb5_error_code ret; 524178825Sdfr 525178825Sdfr retstring(c, name); 526178825Sdfr retstring(c, password); 527178825Sdfr ret32(c, flags); 528178825Sdfr 529178825Sdfr logmessage(c, __FILE__, __LINE__, 0, 530178825Sdfr "username: %s password: %s", name, password); 531178825Sdfr 532178825Sdfr ret = krb5_parse_name(context, name, &principal); 533178825Sdfr if (ret) { 534178825Sdfr gsm_error = convert_krb5_to_gsm(ret); 535178825Sdfr goto out; 536178825Sdfr } 537233294Sstas 538178825Sdfr ret = krb5_get_init_creds_opt_alloc (context, &opt); 539178825Sdfr if (ret) 540178825Sdfr krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc"); 541233294Sstas 542178825Sdfr krb5_get_init_creds_opt_set_pa_password(context, opt, password, NULL); 543178825Sdfr 544178825Sdfr gsm_error = acquire_cred(c, principal, opt, &handle); 545178825Sdfr 546178825Sdfrout: 547178825Sdfr logmessage(c, __FILE__, __LINE__, 0, 548178825Sdfr "AcquireCreds handle: %d return code: %d", handle, gsm_error); 549178825Sdfr 550178825Sdfr if (opt) 551178825Sdfr krb5_get_init_creds_opt_free (context, opt); 552178825Sdfr if (principal) 553178825Sdfr krb5_free_principal(context, principal); 554178825Sdfr free(name); 555178825Sdfr free(password); 556178825Sdfr 557178825Sdfr put32(c, gsm_error); 558178825Sdfr put32(c, handle); 559178825Sdfr 560178825Sdfr return 0; 561178825Sdfr} 562178825Sdfr 563178825Sdfrstatic int 564178825SdfrHandleOP(Sign) 565178825Sdfr{ 566178825Sdfr OM_uint32 maj_stat, min_stat; 567178825Sdfr int32_t hContext, flags, seqno; 568178825Sdfr krb5_data token; 569178825Sdfr gss_ctx_id_t ctx; 570178825Sdfr gss_buffer_desc input_token, output_token; 571178825Sdfr 572178825Sdfr ret32(c, hContext); 573178825Sdfr ret32(c, flags); 574178825Sdfr ret32(c, seqno); 575178825Sdfr retdata(c, token); 576178825Sdfr 577178825Sdfr ctx = find_handle(c->handles, hContext, handle_context); 578178825Sdfr if (ctx == NULL) 579178825Sdfr errx(1, "sign: reference to unknown context"); 580178825Sdfr 581178825Sdfr input_token.length = token.length; 582178825Sdfr input_token.value = token.data; 583233294Sstas 584178825Sdfr maj_stat = gss_get_mic(&min_stat, ctx, 0, &input_token, 585178825Sdfr &output_token); 586178825Sdfr if (maj_stat != GSS_S_COMPLETE) 587178825Sdfr errx(1, "gss_get_mic failed"); 588233294Sstas 589178825Sdfr krb5_data_free(&token); 590233294Sstas 591178825Sdfr token.data = output_token.value; 592178825Sdfr token.length = output_token.length; 593233294Sstas 594178825Sdfr put32(c, 0); /* XXX fix gsm_error */ 595178825Sdfr putdata(c, token); 596233294Sstas 597178825Sdfr gss_release_buffer(&min_stat, &output_token); 598233294Sstas 599178825Sdfr return 0; 600178825Sdfr} 601178825Sdfr 602178825Sdfrstatic int 603178825SdfrHandleOP(Verify) 604178825Sdfr{ 605178825Sdfr OM_uint32 maj_stat, min_stat; 606178825Sdfr int32_t hContext, flags, seqno; 607178825Sdfr krb5_data msg, mic; 608178825Sdfr gss_ctx_id_t ctx; 609178825Sdfr gss_buffer_desc msg_token, mic_token; 610178825Sdfr gss_qop_t qop; 611178825Sdfr 612178825Sdfr ret32(c, hContext); 613178825Sdfr 614178825Sdfr ctx = find_handle(c->handles, hContext, handle_context); 615178825Sdfr if (ctx == NULL) 616178825Sdfr errx(1, "verify: reference to unknown context"); 617178825Sdfr 618178825Sdfr ret32(c, flags); 619178825Sdfr ret32(c, seqno); 620178825Sdfr retdata(c, msg); 621178825Sdfr 622178825Sdfr msg_token.length = msg.length; 623178825Sdfr msg_token.value = msg.data; 624233294Sstas 625178825Sdfr retdata(c, mic); 626178825Sdfr 627178825Sdfr mic_token.length = mic.length; 628178825Sdfr mic_token.value = mic.data; 629178825Sdfr 630178825Sdfr maj_stat = gss_verify_mic(&min_stat, ctx, &msg_token, 631178825Sdfr &mic_token, &qop); 632178825Sdfr if (maj_stat != GSS_S_COMPLETE) 633178825Sdfr errx(1, "gss_verify_mic failed"); 634233294Sstas 635178825Sdfr krb5_data_free(&mic); 636178825Sdfr krb5_data_free(&msg); 637233294Sstas 638178825Sdfr put32(c, 0); /* XXX fix gsm_error */ 639233294Sstas 640178825Sdfr return 0; 641178825Sdfr} 642178825Sdfr 643178825Sdfrstatic int 644178825SdfrHandleOP(GetVersionAndCapabilities) 645178825Sdfr{ 646178825Sdfr int32_t cap = HAS_MONIKER; 647178825Sdfr char name[256] = "unknown", *str; 648178825Sdfr 649178825Sdfr if (targetname) 650178825Sdfr cap |= ISSERVER; /* is server */ 651178825Sdfr 652178825Sdfr#ifdef HAVE_UNAME 653178825Sdfr { 654178825Sdfr struct utsname ut; 655178825Sdfr if (uname(&ut) == 0) { 656233294Sstas snprintf(name, sizeof(name), "%s-%s-%s", 657178825Sdfr ut.sysname, ut.version, ut.machine); 658178825Sdfr } 659178825Sdfr } 660178825Sdfr#endif 661178825Sdfr 662178825Sdfr asprintf(&str, "gssmask %s %s", PACKAGE_STRING, name); 663178825Sdfr 664178825Sdfr put32(c, GSSMAGGOTPROTOCOL); 665178825Sdfr put32(c, cap); 666233294Sstas putstring(c, str); 667178825Sdfr free(str); 668178825Sdfr 669178825Sdfr return 0; 670178825Sdfr} 671178825Sdfr 672178825Sdfrstatic int 673178825SdfrHandleOP(GetTargetName) 674178825Sdfr{ 675178825Sdfr if (targetname) 676178825Sdfr putstring(c, targetname); 677178825Sdfr else 678178825Sdfr putstring(c, ""); 679178825Sdfr return 0; 680178825Sdfr} 681178825Sdfr 682178825Sdfrstatic int 683178825SdfrHandleOP(SetLoggingSocket) 684178825Sdfr{ 685178825Sdfr int32_t portnum; 686178825Sdfr int fd, ret; 687178825Sdfr 688178825Sdfr ret32(c, portnum); 689178825Sdfr 690178825Sdfr logmessage(c, __FILE__, __LINE__, 0, 691178825Sdfr "logging port on peer is: %d", (int)portnum); 692178825Sdfr 693178825Sdfr socket_set_port((struct sockaddr *)(&c->sa), htons(portnum)); 694178825Sdfr 695178825Sdfr fd = socket(((struct sockaddr *)&c->sa)->sa_family, SOCK_STREAM, 0); 696178825Sdfr if (fd < 0) 697178825Sdfr return 0; 698178825Sdfr 699178825Sdfr ret = connect(fd, (struct sockaddr *)&c->sa, c->salen); 700178825Sdfr if (ret < 0) { 701178825Sdfr logmessage(c, __FILE__, __LINE__, 0, "failed connect to log port: %s", 702178825Sdfr strerror(errno)); 703178825Sdfr close(fd); 704178825Sdfr return 0; 705178825Sdfr } 706178825Sdfr 707178825Sdfr if (c->logging) 708178825Sdfr krb5_storage_free(c->logging); 709178825Sdfr c->logging = krb5_storage_from_fd(fd); 710178825Sdfr close(fd); 711178825Sdfr 712178825Sdfr krb5_store_int32(c->logging, eLogSetMoniker); 713178825Sdfr store_string(c->logging, c->moniker); 714233294Sstas 715178825Sdfr logmessage(c, __FILE__, __LINE__, 0, "logging turned on"); 716178825Sdfr 717178825Sdfr return 0; 718178825Sdfr} 719178825Sdfr 720233294Sstas 721178825Sdfrstatic int 722178825SdfrHandleOP(ChangePassword) 723178825Sdfr{ 724178825Sdfr errx(1, "ChangePassword"); 725178825Sdfr} 726178825Sdfr 727178825Sdfrstatic int 728178825SdfrHandleOP(SetPasswordSelf) 729178825Sdfr{ 730178825Sdfr errx(1, "SetPasswordSelf"); 731178825Sdfr} 732178825Sdfr 733178825Sdfrstatic int 734178825SdfrHandleOP(Wrap) 735178825Sdfr{ 736178825Sdfr OM_uint32 maj_stat, min_stat; 737178825Sdfr int32_t hContext, flags, seqno; 738178825Sdfr krb5_data token; 739178825Sdfr gss_ctx_id_t ctx; 740178825Sdfr gss_buffer_desc input_token, output_token; 741178825Sdfr int conf_state; 742178825Sdfr 743178825Sdfr ret32(c, hContext); 744178825Sdfr ret32(c, flags); 745178825Sdfr ret32(c, seqno); 746178825Sdfr retdata(c, token); 747178825Sdfr 748178825Sdfr ctx = find_handle(c->handles, hContext, handle_context); 749178825Sdfr if (ctx == NULL) 750178825Sdfr errx(1, "wrap: reference to unknown context"); 751178825Sdfr 752178825Sdfr input_token.length = token.length; 753178825Sdfr input_token.value = token.data; 754233294Sstas 755178825Sdfr maj_stat = gss_wrap(&min_stat, ctx, flags, 0, &input_token, 756178825Sdfr &conf_state, &output_token); 757178825Sdfr if (maj_stat != GSS_S_COMPLETE) 758178825Sdfr errx(1, "gss_wrap failed"); 759233294Sstas 760178825Sdfr krb5_data_free(&token); 761233294Sstas 762178825Sdfr token.data = output_token.value; 763178825Sdfr token.length = output_token.length; 764233294Sstas 765178825Sdfr put32(c, 0); /* XXX fix gsm_error */ 766178825Sdfr putdata(c, token); 767233294Sstas 768178825Sdfr gss_release_buffer(&min_stat, &output_token); 769233294Sstas 770178825Sdfr return 0; 771178825Sdfr} 772178825Sdfr 773178825Sdfr 774178825Sdfrstatic int 775178825SdfrHandleOP(Unwrap) 776178825Sdfr{ 777178825Sdfr OM_uint32 maj_stat, min_stat; 778178825Sdfr int32_t hContext, flags, seqno; 779178825Sdfr krb5_data token; 780178825Sdfr gss_ctx_id_t ctx; 781178825Sdfr gss_buffer_desc input_token, output_token; 782178825Sdfr int conf_state; 783178825Sdfr gss_qop_t qop_state; 784178825Sdfr 785178825Sdfr ret32(c, hContext); 786178825Sdfr ret32(c, flags); 787178825Sdfr ret32(c, seqno); 788178825Sdfr retdata(c, token); 789178825Sdfr 790178825Sdfr ctx = find_handle(c->handles, hContext, handle_context); 791178825Sdfr if (ctx == NULL) 792178825Sdfr errx(1, "unwrap: reference to unknown context"); 793178825Sdfr 794178825Sdfr input_token.length = token.length; 795178825Sdfr input_token.value = token.data; 796233294Sstas 797178825Sdfr maj_stat = gss_unwrap(&min_stat, ctx, &input_token, 798178825Sdfr &output_token, &conf_state, &qop_state); 799233294Sstas 800178825Sdfr if (maj_stat != GSS_S_COMPLETE) 801178825Sdfr errx(1, "gss_unwrap failed: %d/%d", maj_stat, min_stat); 802233294Sstas 803178825Sdfr krb5_data_free(&token); 804178825Sdfr if (maj_stat == GSS_S_COMPLETE) { 805178825Sdfr token.data = output_token.value; 806178825Sdfr token.length = output_token.length; 807178825Sdfr } else { 808178825Sdfr token.data = NULL; 809178825Sdfr token.length = 0; 810178825Sdfr } 811178825Sdfr put32(c, 0); /* XXX fix gsm_error */ 812178825Sdfr putdata(c, token); 813178825Sdfr 814178825Sdfr if (maj_stat == GSS_S_COMPLETE) 815178825Sdfr gss_release_buffer(&min_stat, &output_token); 816178825Sdfr 817178825Sdfr return 0; 818178825Sdfr} 819178825Sdfr 820178825Sdfrstatic int 821178825SdfrHandleOP(Encrypt) 822178825Sdfr{ 823178825Sdfr return handleWrap(op, c); 824178825Sdfr} 825178825Sdfr 826178825Sdfrstatic int 827178825SdfrHandleOP(Decrypt) 828178825Sdfr{ 829178825Sdfr return handleUnwrap(op, c); 830178825Sdfr} 831178825Sdfr 832178825Sdfrstatic int 833178825SdfrHandleOP(ConnectLoggingService2) 834178825Sdfr{ 835178825Sdfr errx(1, "ConnectLoggingService2"); 836178825Sdfr} 837178825Sdfr 838178825Sdfrstatic int 839178825SdfrHandleOP(GetMoniker) 840178825Sdfr{ 841178825Sdfr putstring(c, c->moniker); 842178825Sdfr return 0; 843178825Sdfr} 844178825Sdfr 845178825Sdfrstatic int 846178825SdfrHandleOP(CallExtension) 847178825Sdfr{ 848178825Sdfr errx(1, "CallExtension"); 849178825Sdfr} 850178825Sdfr 851178825Sdfrstatic int 852178825SdfrHandleOP(AcquirePKInitCreds) 853178825Sdfr{ 854178825Sdfr int32_t flags; 855178825Sdfr krb5_data pfxdata; 856233294Sstas char fn[] = "FILE:/tmp/pkcs12-creds-XXXXXXX"; 857233294Sstas krb5_principal principal = NULL; 858233294Sstas int fd; 859178825Sdfr 860178825Sdfr ret32(c, flags); 861178825Sdfr retdata(c, pfxdata); 862178825Sdfr 863233294Sstas fd = mkstemp(fn + 5); 864233294Sstas if (fd < 0) 865233294Sstas errx(1, "mkstemp"); 866178825Sdfr 867233294Sstas net_write(fd, pfxdata.data, pfxdata.length); 868178825Sdfr krb5_data_free(&pfxdata); 869233294Sstas close(fd); 870178825Sdfr 871233294Sstas if (principal) 872233294Sstas krb5_free_principal(context, principal); 873233294Sstas 874178825Sdfr put32(c, -1); /* hResource */ 875178825Sdfr put32(c, GSMERR_NOT_SUPPORTED); 876178825Sdfr return 0; 877178825Sdfr} 878178825Sdfr 879233294Sstasstatic int 880233294SstasHandleOP(WrapExt) 881233294Sstas{ 882233294Sstas OM_uint32 maj_stat, min_stat; 883233294Sstas int32_t hContext, flags, bflags; 884233294Sstas krb5_data token, header, trailer; 885233294Sstas gss_ctx_id_t ctx; 886233294Sstas unsigned char *p; 887233294Sstas int conf_state, iov_len; 888233294Sstas gss_iov_buffer_desc iov[6]; 889233294Sstas 890233294Sstas ret32(c, hContext); 891233294Sstas ret32(c, flags); 892233294Sstas ret32(c, bflags); 893233294Sstas retdata(c, header); 894233294Sstas retdata(c, token); 895233294Sstas retdata(c, trailer); 896233294Sstas 897233294Sstas ctx = find_handle(c->handles, hContext, handle_context); 898233294Sstas if (ctx == NULL) 899233294Sstas errx(1, "wrap: reference to unknown context"); 900233294Sstas 901233294Sstas memset(&iov, 0, sizeof(iov)); 902233294Sstas 903233294Sstas iov_len = sizeof(iov)/sizeof(iov[0]); 904233294Sstas 905233294Sstas if (bflags & WRAP_EXP_ONLY_HEADER) 906233294Sstas iov_len -= 2; /* skip trailer and padding, aka dce-style */ 907233294Sstas 908233294Sstas iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE; 909233294Sstas if (header.length != 0) { 910233294Sstas iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY; 911233294Sstas iov[1].buffer.length = header.length; 912233294Sstas iov[1].buffer.value = header.data; 913233294Sstas } else { 914233294Sstas iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY; 915233294Sstas } 916233294Sstas iov[2].type = GSS_IOV_BUFFER_TYPE_DATA; 917233294Sstas iov[2].buffer.length = token.length; 918233294Sstas iov[2].buffer.value = token.data; 919233294Sstas if (trailer.length != 0) { 920233294Sstas iov[3].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY; 921233294Sstas iov[3].buffer.length = trailer.length; 922233294Sstas iov[3].buffer.value = trailer.data; 923233294Sstas } else { 924233294Sstas iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY; 925233294Sstas } 926233294Sstas iov[4].type = GSS_IOV_BUFFER_TYPE_PADDING | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE; 927233294Sstas iov[5].type = GSS_IOV_BUFFER_TYPE_TRAILER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE; 928233294Sstas 929233294Sstas maj_stat = gss_wrap_iov_length(&min_stat, ctx, flags, 0, &conf_state, 930233294Sstas iov, iov_len); 931233294Sstas if (maj_stat != GSS_S_COMPLETE) 932233294Sstas errx(1, "gss_wrap_iov_length failed"); 933233294Sstas 934233294Sstas maj_stat = gss_wrap_iov(&min_stat, ctx, flags, 0, &conf_state, 935233294Sstas iov, iov_len); 936233294Sstas if (maj_stat != GSS_S_COMPLETE) 937233294Sstas errx(1, "gss_wrap_iov failed"); 938233294Sstas 939233294Sstas krb5_data_free(&token); 940233294Sstas 941233294Sstas token.length = iov[0].buffer.length + iov[2].buffer.length + iov[4].buffer.length + iov[5].buffer.length; 942233294Sstas token.data = malloc(token.length); 943233294Sstas 944233294Sstas p = token.data; 945233294Sstas memcpy(p, iov[0].buffer.value, iov[0].buffer.length); 946233294Sstas p += iov[0].buffer.length; 947233294Sstas memcpy(p, iov[2].buffer.value, iov[2].buffer.length); 948233294Sstas p += iov[2].buffer.length; 949233294Sstas memcpy(p, iov[4].buffer.value, iov[4].buffer.length); 950233294Sstas p += iov[4].buffer.length; 951233294Sstas memcpy(p, iov[5].buffer.value, iov[5].buffer.length); 952233294Sstas p += iov[5].buffer.length; 953233294Sstas 954233294Sstas gss_release_iov_buffer(NULL, iov, iov_len); 955233294Sstas 956233294Sstas put32(c, 0); /* XXX fix gsm_error */ 957233294Sstas putdata(c, token); 958233294Sstas 959233294Sstas free(token.data); 960233294Sstas 961233294Sstas return 0; 962233294Sstas} 963233294Sstas 964233294Sstas 965233294Sstasstatic int 966233294SstasHandleOP(UnwrapExt) 967233294Sstas{ 968233294Sstas OM_uint32 maj_stat, min_stat; 969233294Sstas int32_t hContext, flags, bflags; 970233294Sstas krb5_data token, header, trailer; 971233294Sstas gss_ctx_id_t ctx; 972233294Sstas gss_iov_buffer_desc iov[3]; 973233294Sstas int conf_state, iov_len; 974233294Sstas gss_qop_t qop_state; 975233294Sstas 976233294Sstas ret32(c, hContext); 977233294Sstas ret32(c, flags); 978233294Sstas ret32(c, bflags); 979233294Sstas retdata(c, header); 980233294Sstas retdata(c, token); 981233294Sstas retdata(c, trailer); 982233294Sstas 983233294Sstas iov_len = sizeof(iov)/sizeof(iov[0]); 984233294Sstas 985233294Sstas if (bflags & WRAP_EXP_ONLY_HEADER) 986233294Sstas iov_len -= 1; /* skip trailer and padding, aka dce-style */ 987233294Sstas 988233294Sstas ctx = find_handle(c->handles, hContext, handle_context); 989233294Sstas if (ctx == NULL) 990233294Sstas errx(1, "unwrap: reference to unknown context"); 991233294Sstas 992233294Sstas if (header.length != 0) { 993233294Sstas iov[0].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY; 994233294Sstas iov[0].buffer.length = header.length; 995233294Sstas iov[0].buffer.value = header.data; 996233294Sstas } else { 997233294Sstas iov[0].type = GSS_IOV_BUFFER_TYPE_EMPTY; 998233294Sstas } 999233294Sstas iov[1].type = GSS_IOV_BUFFER_TYPE_DATA; 1000233294Sstas iov[1].buffer.length = token.length; 1001233294Sstas iov[1].buffer.value = token.data; 1002233294Sstas 1003233294Sstas if (trailer.length != 0) { 1004233294Sstas iov[2].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY; 1005233294Sstas iov[2].buffer.length = trailer.length; 1006233294Sstas iov[2].buffer.value = trailer.data; 1007233294Sstas } else { 1008233294Sstas iov[2].type = GSS_IOV_BUFFER_TYPE_EMPTY; 1009233294Sstas } 1010233294Sstas 1011233294Sstas maj_stat = gss_unwrap_iov(&min_stat, ctx, &conf_state, &qop_state, 1012233294Sstas iov, iov_len); 1013233294Sstas 1014233294Sstas if (maj_stat != GSS_S_COMPLETE) 1015233294Sstas errx(1, "gss_unwrap failed: %d/%d", maj_stat, min_stat); 1016233294Sstas 1017233294Sstas if (maj_stat == GSS_S_COMPLETE) { 1018233294Sstas token.data = iov[1].buffer.value; 1019233294Sstas token.length = iov[1].buffer.length; 1020233294Sstas } else { 1021233294Sstas token.data = NULL; 1022233294Sstas token.length = 0; 1023233294Sstas } 1024233294Sstas put32(c, 0); /* XXX fix gsm_error */ 1025233294Sstas putdata(c, token); 1026233294Sstas 1027233294Sstas return 0; 1028233294Sstas} 1029233294Sstas 1030178825Sdfr/* 1031178825Sdfr * 1032178825Sdfr */ 1033178825Sdfr 1034178825Sdfrstruct handler { 1035178825Sdfr enum gssMaggotOp op; 1036178825Sdfr const char *name; 1037178825Sdfr int (*func)(enum gssMaggotOp, struct client *); 1038178825Sdfr}; 1039178825Sdfr 1040178825Sdfr#define S(a) { e##a, #a, handle##a } 1041178825Sdfr 1042178825Sdfrstruct handler handlers[] = { 1043178825Sdfr S(GetVersionInfo), 1044178825Sdfr S(GoodBye), 1045178825Sdfr S(InitContext), 1046178825Sdfr S(AcceptContext), 1047178825Sdfr S(ToastResource), 1048178825Sdfr S(AcquireCreds), 1049178825Sdfr S(Encrypt), 1050178825Sdfr S(Decrypt), 1051178825Sdfr S(Sign), 1052178825Sdfr S(Verify), 1053178825Sdfr S(GetVersionAndCapabilities), 1054178825Sdfr S(GetTargetName), 1055178825Sdfr S(SetLoggingSocket), 1056178825Sdfr S(ChangePassword), 1057178825Sdfr S(SetPasswordSelf), 1058178825Sdfr S(Wrap), 1059178825Sdfr S(Unwrap), 1060178825Sdfr S(ConnectLoggingService2), 1061178825Sdfr S(GetMoniker), 1062178825Sdfr S(CallExtension), 1063233294Sstas S(AcquirePKInitCreds), 1064233294Sstas S(WrapExt), 1065233294Sstas S(UnwrapExt), 1066178825Sdfr}; 1067178825Sdfr 1068178825Sdfr#undef S 1069178825Sdfr 1070178825Sdfr/* 1071178825Sdfr * 1072178825Sdfr */ 1073178825Sdfr 1074178825Sdfrstatic struct handler * 1075178825Sdfrfind_op(int32_t op) 1076178825Sdfr{ 1077178825Sdfr int i; 1078178825Sdfr 1079178825Sdfr for (i = 0; i < sizeof(handlers)/sizeof(handlers[0]); i++) 1080178825Sdfr if (handlers[i].op == op) 1081178825Sdfr return &handlers[i]; 1082178825Sdfr return NULL; 1083178825Sdfr} 1084178825Sdfr 1085178825Sdfrstatic struct client * 1086178825Sdfrcreate_client(int fd, int port, const char *moniker) 1087178825Sdfr{ 1088178825Sdfr struct client *c; 1089178825Sdfr 1090178825Sdfr c = ecalloc(1, sizeof(*c)); 1091178825Sdfr 1092178825Sdfr if (moniker) { 1093178825Sdfr c->moniker = estrdup(moniker); 1094178825Sdfr } else { 1095178825Sdfr char hostname[MAXHOSTNAMELEN]; 1096178825Sdfr gethostname(hostname, sizeof(hostname)); 1097178825Sdfr asprintf(&c->moniker, "gssmask: %s:%d", hostname, port); 1098178825Sdfr } 1099178825Sdfr 1100178825Sdfr { 1101178825Sdfr c->salen = sizeof(c->sa); 1102178825Sdfr getpeername(fd, (struct sockaddr *)&c->sa, &c->salen); 1103233294Sstas 1104233294Sstas getnameinfo((struct sockaddr *)&c->sa, c->salen, 1105233294Sstas c->servername, sizeof(c->servername), 1106178825Sdfr NULL, 0, NI_NUMERICHOST); 1107178825Sdfr } 1108178825Sdfr 1109178825Sdfr c->sock = krb5_storage_from_fd(fd); 1110178825Sdfr if (c->sock == NULL) 1111178825Sdfr errx(1, "krb5_storage_from_fd"); 1112233294Sstas 1113178825Sdfr close(fd); 1114178825Sdfr 1115178825Sdfr return c; 1116178825Sdfr} 1117178825Sdfr 1118178825Sdfrstatic void 1119178825Sdfrfree_client(struct client *c) 1120178825Sdfr{ 1121178825Sdfr while(c->handles) 1122178825Sdfr del_handle(&c->handles, c->handles->idx); 1123178825Sdfr 1124178825Sdfr free(c->moniker); 1125178825Sdfr krb5_storage_free(c->sock); 1126178825Sdfr if (c->logging) 1127178825Sdfr krb5_storage_free(c->logging); 1128178825Sdfr free(c); 1129178825Sdfr} 1130178825Sdfr 1131178825Sdfr 1132178825Sdfrstatic void * 1133178825SdfrhandleServer(void *ptr) 1134178825Sdfr{ 1135178825Sdfr struct handler *handler; 1136178825Sdfr struct client *c; 1137178825Sdfr int32_t op; 1138178825Sdfr 1139178825Sdfr c = (struct client *)ptr; 1140178825Sdfr 1141178825Sdfr 1142178825Sdfr while(1) { 1143178825Sdfr ret32(c, op); 1144178825Sdfr 1145178825Sdfr handler = find_op(op); 1146178825Sdfr if (handler == NULL) { 1147178825Sdfr logmessage(c, __FILE__, __LINE__, 0, 1148178825Sdfr "op %d not supported", (int)op); 1149178825Sdfr exit(1); 1150178825Sdfr } 1151178825Sdfr 1152178825Sdfr logmessage(c, __FILE__, __LINE__, 0, 1153233294Sstas "---> Got op %s from server %s", 1154178825Sdfr handler->name, c->servername); 1155178825Sdfr 1156178825Sdfr if ((handler->func)(handler->op, c)) 1157178825Sdfr break; 1158178825Sdfr } 1159178825Sdfr 1160178825Sdfr return NULL; 1161178825Sdfr} 1162178825Sdfr 1163178825Sdfr 1164178825Sdfrstatic char *port_str; 1165178825Sdfrstatic int version_flag; 1166178825Sdfrstatic int help_flag; 1167178825Sdfrstatic char *logfile_str; 1168178825Sdfrstatic char *moniker_str; 1169178825Sdfr 1170178825Sdfrstatic int port = 4711; 1171178825Sdfr 1172178825Sdfrstruct getargs args[] = { 1173178825Sdfr { "spn", 0, arg_string, &targetname, "This host's SPN", 1174178825Sdfr "service/host@REALM" }, 1175178825Sdfr { "port", 'p', arg_string, &port_str, "Use this port", 1176178825Sdfr "number-of-service" }, 1177178825Sdfr { "logfile", 0, arg_string, &logfile_str, "logfile", 1178178825Sdfr "number-of-service" }, 1179178825Sdfr { "moniker", 0, arg_string, &moniker_str, "nickname", 1180178825Sdfr "name" }, 1181178825Sdfr { "version", 0, arg_flag, &version_flag, "Print version", 1182178825Sdfr NULL }, 1183178825Sdfr { "help", 0, arg_flag, &help_flag, NULL, 1184178825Sdfr NULL } 1185178825Sdfr}; 1186178825Sdfr 1187178825Sdfrstatic void 1188178825Sdfrusage(int ret) 1189178825Sdfr{ 1190178825Sdfr arg_printusage (args, 1191178825Sdfr sizeof(args) / sizeof(args[0]), 1192178825Sdfr NULL, 1193178825Sdfr ""); 1194178825Sdfr exit (ret); 1195178825Sdfr} 1196178825Sdfr 1197178825Sdfrint 1198178825Sdfrmain(int argc, char **argv) 1199178825Sdfr{ 1200178825Sdfr int optidx = 0; 1201178825Sdfr 1202178825Sdfr setprogname (argv[0]); 1203178825Sdfr 1204178825Sdfr if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv, &optidx)) 1205178825Sdfr usage (1); 1206178825Sdfr 1207178825Sdfr if (help_flag) 1208178825Sdfr usage (0); 1209178825Sdfr 1210178825Sdfr if (version_flag) { 1211178825Sdfr print_version (NULL); 1212178825Sdfr return 0; 1213178825Sdfr } 1214178825Sdfr 1215178825Sdfr if (optidx != argc) 1216178825Sdfr usage (1); 1217178825Sdfr 1218178825Sdfr if (port_str) { 1219178825Sdfr char *ptr; 1220178825Sdfr 1221178825Sdfr port = strtol (port_str, &ptr, 10); 1222178825Sdfr if (port == 0 && ptr == port_str) 1223178825Sdfr errx (1, "Bad port `%s'", port_str); 1224178825Sdfr } 1225178825Sdfr 1226178825Sdfr krb5_init_context(&context); 1227178825Sdfr 1228178825Sdfr { 1229178825Sdfr const char *lf = logfile_str; 1230178825Sdfr if (lf == NULL) 1231178825Sdfr lf = "/dev/tty"; 1232178825Sdfr 1233178825Sdfr logfile = fopen(lf, "w"); 1234178825Sdfr if (logfile == NULL) 1235178825Sdfr err(1, "error opening %s", lf); 1236178825Sdfr } 1237178825Sdfr 1238233294Sstas mini_inetd(htons(port), NULL); 1239178825Sdfr fprintf(logfile, "connected\n"); 1240178825Sdfr 1241178825Sdfr { 1242233294Sstas struct client *c; 1243178825Sdfr 1244178825Sdfr c = create_client(0, port, moniker_str); 1245178825Sdfr /* close(0); */ 1246178825Sdfr 1247178825Sdfr handleServer(c); 1248178825Sdfr 1249178825Sdfr free_client(c); 1250178825Sdfr } 1251178825Sdfr 1252178825Sdfr krb5_free_context(context); 1253178825Sdfr 1254178825Sdfr return 0; 1255178825Sdfr} 1256