1 // Module name: krb5routines.c 2 3 #include <windows.h> 4 #define SECURITY_WIN32 5 #include <security.h> 6 7 /* _WIN32_WINNT must be 0x0501 or greater to pull in definition of 8 * all required LSA data types when the Vista SDK NtSecAPI.h is used. 9 */ 10 #ifndef _WIN32_WINNT 11 #define _WIN32_WINNT 0x0501 12 #else 13 #if _WIN32_WINNT < 0x0501 14 #undef _WIN32_WINNT 15 #define _WIN32_WINNT 0x0501 16 #endif 17 #endif 18 #include <ntsecapi.h> 19 #include <stdio.h> 20 #include <string.h> 21 #include <time.h> 22 #include <assert.h> 23 24 #include <winsock2.h> 25 26 /* Private Include files */ 27 #include "leashdll.h" 28 #include <leashwin.h> 29 #include "leash-int.h" 30 31 #define KRB5_DEFAULT_LIFE 60*60*10 /* 10 hours */ 32 33 char *GetTicketFlag(krb5_creds *cred) 34 { 35 static char buf[32]; 36 int i = 0; 37 38 buf[i++] = ' '; 39 buf[i++] = '('; 40 41 if (cred->ticket_flags & TKT_FLG_FORWARDABLE) 42 buf[i++] = 'F'; 43 44 if (cred->ticket_flags & TKT_FLG_FORWARDED) 45 buf[i++] = 'f'; 46 47 if (cred->ticket_flags & TKT_FLG_PROXIABLE) 48 buf[i++] = 'P'; 49 50 if (cred->ticket_flags & TKT_FLG_PROXY) 51 buf[i++] = 'p'; 52 53 if (cred->ticket_flags & TKT_FLG_MAY_POSTDATE) 54 buf[i++] = 'D'; 55 56 if (cred->ticket_flags & TKT_FLG_POSTDATED) 57 buf[i++] = 'd'; 58 59 if (cred->ticket_flags & TKT_FLG_INVALID) 60 buf[i++] = 'i'; 61 62 if (cred->ticket_flags & TKT_FLG_RENEWABLE) 63 buf[i++] = 'R'; 64 65 if (cred->ticket_flags & TKT_FLG_INITIAL) 66 buf[i++] = 'I'; 67 68 if (cred->ticket_flags & TKT_FLG_HW_AUTH) 69 buf[i++] = 'H'; 70 71 if (cred->ticket_flags & TKT_FLG_PRE_AUTH) 72 buf[i++] = 'A'; 73 74 buf[i++] = ')'; 75 buf[i] = '\0'; 76 77 if (i <= 3) 78 buf[0] = '\0'; 79 80 return buf; 81 } 82 83 int 84 LeashKRB5_renew(void) 85 { 86 krb5_error_code code = 0; 87 krb5_context ctx = 0; 88 krb5_ccache cc = 0; 89 krb5_principal me = 0; 90 krb5_principal server = 0; 91 krb5_creds my_creds; 92 krb5_data *realm = 0; 93 94 if ( !pkrb5_init_context ) 95 goto cleanup; 96 97 memset(&my_creds, 0, sizeof(krb5_creds)); 98 99 code = pkrb5_init_context(&ctx); 100 if (code) goto cleanup; 101 102 code = pkrb5_cc_default(ctx, &cc); 103 if (code) goto cleanup; 104 105 code = pkrb5_cc_get_principal(ctx, cc, &me); 106 if (code) goto cleanup; 107 108 realm = krb5_princ_realm(ctx, me); 109 110 code = pkrb5_build_principal_ext(ctx, &server, 111 realm->length,realm->data, 112 KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME, 113 realm->length,realm->data, 114 0); 115 if ( code ) goto cleanup; 116 117 my_creds.client = me; 118 my_creds.server = server; 119 120 pkrb5_cc_set_flags(ctx, cc, 0); 121 code = pkrb5_get_renewed_creds(ctx, &my_creds, me, cc, NULL); 122 pkrb5_cc_set_flags(ctx, cc, KRB5_TC_NOTICKET); 123 if (code) { 124 if (code != KRB5KDC_ERR_ETYPE_NOSUPP && code != KRB5_KDC_UNREACH && 125 code != KRB5_CC_NOTFOUND) 126 Leash_krb5_error(code, "krb5_get_renewed_creds()", 0, &ctx, &cc); 127 goto cleanup; 128 } 129 130 code = pkrb5_cc_initialize(ctx, cc, me); 131 if (code) goto cleanup; 132 133 code = pkrb5_cc_store_cred(ctx, cc, &my_creds); 134 if (code) goto cleanup; 135 136 cleanup: 137 if (my_creds.client == me) 138 my_creds.client = 0; 139 if (my_creds.server == server) 140 my_creds.server = 0; 141 pkrb5_free_cred_contents(ctx, &my_creds); 142 if (me) 143 pkrb5_free_principal(ctx, me); 144 if (server) 145 pkrb5_free_principal(ctx, server); 146 if (cc) 147 pkrb5_cc_close(ctx, cc); 148 if (ctx) 149 pkrb5_free_context(ctx); 150 return(code); 151 } 152 153 static krb5_error_code KRB5_CALLCONV 154 leash_krb5_prompter( krb5_context context, 155 void *data, 156 const char *name, 157 const char *banner, 158 int num_prompts, 159 krb5_prompt prompts[]); 160 161 int 162 Leash_krb5_kinit( 163 krb5_context alt_ctx, 164 HWND hParent, 165 char *principal_name, 166 char *password, 167 krb5_deltat lifetime, 168 DWORD forwardable, 169 DWORD proxiable, 170 krb5_deltat renew_life, 171 DWORD addressless, 172 DWORD publicIP 173 ) 174 { 175 krb5_error_code code = 0; 176 krb5_context ctx = 0; 177 krb5_ccache cc = 0, defcache = 0; 178 krb5_principal me = 0; 179 char* name = 0; 180 krb5_creds my_creds; 181 krb5_get_init_creds_opt * options = NULL; 182 krb5_address ** addrs = NULL; 183 size_t i = 0, addr_count = 0; 184 int cc_new = 0; 185 const char * deftype = NULL; 186 187 if (!pkrb5_init_context) 188 return 0; 189 190 memset(&my_creds, 0, sizeof(my_creds)); 191 192 if (alt_ctx) 193 { 194 ctx = alt_ctx; 195 } 196 else 197 { 198 code = pkrb5_init_context(&ctx); 199 if (code) goto cleanup; 200 } 201 202 code = pkrb5_get_init_creds_opt_alloc(ctx, &options); 203 if (code) goto cleanup; 204 205 code = pkrb5_cc_default(ctx, &defcache); 206 if (code) goto cleanup; 207 208 code = pkrb5_parse_name(ctx, principal_name, &me); 209 if (code) goto cleanup; 210 211 deftype = pkrb5_cc_get_type(ctx, defcache); 212 if (me != NULL && pkrb5_cc_support_switch(ctx, deftype)) { 213 /* Use an existing cache for the specified principal if we can. */ 214 code = pkrb5_cc_cache_match(ctx, me, &cc); 215 if (code != 0 && code != KRB5_CC_NOTFOUND) 216 goto cleanup; 217 if (code == KRB5_CC_NOTFOUND) { 218 code = pkrb5_cc_new_unique(ctx, deftype, NULL, &cc); 219 if (code) 220 goto cleanup; 221 cc_new = 1; 222 } 223 pkrb5_cc_close(ctx, defcache); 224 } else { 225 cc = defcache; 226 } 227 228 code = pkrb5_unparse_name(ctx, me, &name); 229 if (code) goto cleanup; 230 231 if (lifetime == 0) 232 lifetime = Leash_get_default_lifetime(); 233 else 234 lifetime *= 5*60; 235 236 if (renew_life > 0) 237 renew_life *= 5*60; 238 239 if (lifetime) 240 pkrb5_get_init_creds_opt_set_tkt_life(options, lifetime); 241 pkrb5_get_init_creds_opt_set_forwardable(options, 242 forwardable ? 1 : 0); 243 pkrb5_get_init_creds_opt_set_proxiable(options, 244 proxiable ? 1 : 0); 245 pkrb5_get_init_creds_opt_set_renew_life(options, 246 renew_life); 247 if (addressless) 248 pkrb5_get_init_creds_opt_set_address_list(options,NULL); 249 else { 250 if (publicIP) 251 { 252 // we are going to add the public IP address specified by the user 253 // to the list provided by the operating system 254 krb5_address ** local_addrs=NULL; 255 DWORD netIPAddr; 256 257 pkrb5_os_localaddr(ctx, &local_addrs); 258 while ( local_addrs[i++] ); 259 addr_count = i + 1; 260 261 addrs = (krb5_address **) malloc((addr_count+1) * sizeof(krb5_address *)); 262 if ( !addrs ) { 263 pkrb5_free_addresses(ctx, local_addrs); 264 assert(0); 265 } 266 memset(addrs, 0, sizeof(krb5_address *) * (addr_count+1)); 267 i = 0; 268 while ( local_addrs[i] ) { 269 addrs[i] = (krb5_address *)malloc(sizeof(krb5_address)); 270 if (addrs[i] == NULL) { 271 pkrb5_free_addresses(ctx, local_addrs); 272 assert(0); 273 } 274 275 addrs[i]->magic = local_addrs[i]->magic; 276 addrs[i]->addrtype = local_addrs[i]->addrtype; 277 addrs[i]->length = local_addrs[i]->length; 278 addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length); 279 if (!addrs[i]->contents) { 280 pkrb5_free_addresses(ctx, local_addrs); 281 assert(0); 282 } 283 284 memcpy(addrs[i]->contents,local_addrs[i]->contents, 285 local_addrs[i]->length); /* safe */ 286 i++; 287 } 288 pkrb5_free_addresses(ctx, local_addrs); 289 290 addrs[i] = (krb5_address *)malloc(sizeof(krb5_address)); 291 if (addrs[i] == NULL) 292 assert(0); 293 294 addrs[i]->magic = KV5M_ADDRESS; 295 addrs[i]->addrtype = AF_INET; 296 addrs[i]->length = 4; 297 addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length); 298 if (!addrs[i]->contents) 299 assert(0); 300 301 netIPAddr = htonl(publicIP); 302 memcpy(addrs[i]->contents,&netIPAddr,4); 303 304 pkrb5_get_init_creds_opt_set_address_list(options,addrs); 305 306 } 307 } 308 309 code = pkrb5_get_init_creds_opt_set_out_ccache(ctx, options, cc); 310 if (code) 311 goto cleanup; 312 313 code = pkrb5_get_init_creds_password(ctx, 314 &my_creds, 315 me, 316 password, // password 317 leash_krb5_prompter, // prompter 318 hParent, // prompter data 319 0, // start time 320 0, // service name 321 options); 322 // @TODO: make this an option 323 if ((!code) && (cc != defcache)) { 324 code = pkrb5_cc_switch(ctx, cc); 325 if (!code) { 326 const char *cctype = pkrb5_cc_get_type(ctx, cc); 327 if (cctype != NULL) { 328 char defname[20]; 329 sprintf_s(defname, sizeof(defname), "%s:", cctype); 330 pkrb5int_cc_user_set_default_name(ctx, defname); 331 } 332 } 333 } 334 cleanup: 335 if (code && cc_new) { 336 // don't leave newly-generated empty ccache lying around on failure 337 pkrb5_cc_destroy(ctx, cc); 338 cc = NULL; 339 } 340 if ( addrs ) { 341 for ( i=0;i<addr_count;i++ ) { 342 if ( addrs[i] ) { 343 if ( addrs[i]->contents ) 344 free(addrs[i]->contents); 345 free(addrs[i]); 346 } 347 } 348 } 349 if (my_creds.client == me) 350 my_creds.client = 0; 351 pkrb5_free_cred_contents(ctx, &my_creds); 352 if (name) 353 pkrb5_free_unparsed_name(ctx, name); 354 if (me) 355 pkrb5_free_principal(ctx, me); 356 if (cc) 357 pkrb5_cc_close(ctx, cc); 358 if (options) 359 pkrb5_get_init_creds_opt_free(ctx, options); 360 if (ctx && (ctx != alt_ctx)) 361 pkrb5_free_context(ctx); 362 return(code); 363 } 364 365 366 /**************************************/ 367 /* LeashKRB5destroyTicket(): */ 368 /**************************************/ 369 int 370 Leash_krb5_kdestroy( 371 void 372 ) 373 { 374 krb5_context ctx; 375 krb5_ccache cache; 376 krb5_error_code rc; 377 378 ctx = NULL; 379 cache = NULL; 380 rc = Leash_krb5_initialize(&ctx); 381 if (rc) 382 return(rc); 383 384 if (rc = pkrb5_cc_default(ctx, &cache)) 385 return(rc); 386 387 rc = pkrb5_cc_destroy(ctx, cache); 388 389 if (ctx != NULL) 390 pkrb5_free_context(ctx); 391 392 return(rc); 393 394 } 395 396 krb5_error_code 397 Leash_krb5_cc_default(krb5_context *ctx, krb5_ccache *cache) 398 { 399 krb5_error_code rc; 400 krb5_flags flags; 401 402 char *functionName = NULL; 403 if (*cache == 0) { 404 rc = pkrb5_cc_default(*ctx, cache); 405 if (rc) { 406 functionName = "krb5_cc_default()"; 407 goto on_error; 408 } 409 } 410 flags = KRB5_TC_NOTICKET; 411 rc = pkrb5_cc_set_flags(*ctx, *cache, flags); 412 if (rc) { 413 if (rc == KRB5_FCC_NOFILE || rc == KRB5_CC_NOTFOUND) { 414 if (*cache != NULL && *ctx != NULL) 415 pkrb5_cc_close(*ctx, *cache); 416 } else { 417 functionName = "krb5_cc_set_flags()"; 418 goto on_error; 419 } 420 } 421 on_error: 422 if (rc && functionName) { 423 Leash_krb5_error(rc, functionName, 0, ctx, cache); 424 } 425 return rc; 426 } 427 428 /**************************************/ 429 /* Leash_krb5_initialize(): */ 430 /**************************************/ 431 int Leash_krb5_initialize(krb5_context *ctx) 432 { 433 LPCSTR functionName = NULL; 434 krb5_error_code rc; 435 436 if (pkrb5_init_context == NULL) 437 return 1; 438 439 if (*ctx == 0) { 440 if (rc = (*pkrb5_init_context)(ctx)) { 441 functionName = "krb5_init_context()"; 442 return Leash_krb5_error(rc, functionName, 0, ctx, NULL); 443 } 444 } 445 return 0; 446 } 447 448 449 /**************************************/ 450 /* Leash_krb5_error(): */ 451 /**************************************/ 452 int 453 Leash_krb5_error(krb5_error_code rc, LPCSTR FailedFunctionName, 454 int FreeContextFlag, krb5_context * ctx, 455 krb5_ccache * cache) 456 { 457 #ifdef USE_MESSAGE_BOX 458 char message[256]; 459 const char *errText; 460 461 errText = perror_message(rc); 462 _snprintf(message, sizeof(message), 463 "%s\n(Kerberos error %ld)\n\n%s failed", 464 errText, 465 rc, 466 FailedFunctionName); 467 message[sizeof(message)-1] = 0; 468 469 MessageBox(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR | 470 MB_TASKMODAL | 471 MB_SETFOREGROUND); 472 #endif /* USE_MESSAGE_BOX */ 473 474 if (ctx != NULL && *ctx != NULL) { 475 if (cache != NULL && *cache != NULL) { 476 pkrb5_cc_close(*ctx, *cache); 477 *cache = NULL; 478 } 479 480 if (FreeContextFlag) { 481 pkrb5_free_context(*ctx); 482 *ctx = NULL; 483 } 484 } 485 486 return rc; 487 } 488 489 490 /* User Query data structures and functions */ 491 492 struct textField { 493 char * buf; /* Destination buffer address */ 494 int len; /* Destination buffer length */ 495 char * label; /* Label for this field */ 496 char * def; /* Default response for this field */ 497 int echo; /* 0 = no, 1 = yes, 2 = asterisks */ 498 }; 499 500 static int mid_cnt = 0; 501 static struct textField * mid_tb = NULL; 502 503 #define ID_TEXT 150 504 #define ID_MID_TEXT 300 505 506 static BOOL CALLBACK 507 MultiInputDialogProc( HWND hDialog, UINT message, WPARAM wParam, LPARAM lParam) 508 { 509 int i; 510 511 switch ( message ) { 512 case WM_INITDIALOG: 513 if ( GetDlgCtrlID((HWND) wParam) != ID_MID_TEXT ) 514 { 515 SetFocus(GetDlgItem( hDialog, ID_MID_TEXT)); 516 return FALSE; 517 } 518 for ( i=0; i < mid_cnt ; i++ ) { 519 if (mid_tb[i].echo == 0) 520 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, 32, 0); 521 else if (mid_tb[i].echo == 2) 522 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, '*', 0); 523 } 524 return TRUE; 525 526 case WM_COMMAND: 527 switch ( LOWORD(wParam) ) { 528 case IDOK: 529 for ( i=0; i < mid_cnt ; i++ ) { 530 if ( !GetDlgItemText(hDialog, ID_MID_TEXT+i, mid_tb[i].buf, mid_tb[i].len) ) 531 *mid_tb[i].buf = '\0'; 532 } 533 /* fallthrough */ 534 case IDCANCEL: 535 EndDialog(hDialog, LOWORD(wParam)); 536 return TRUE; 537 } 538 } 539 return FALSE; 540 } 541 542 static LPWORD 543 lpwAlign( LPWORD lpIn ) 544 { 545 ULONG ul; 546 547 ul = (ULONG) lpIn; 548 ul += 3; 549 ul >>=2; 550 ul <<=2; 551 return (LPWORD) ul;; 552 } 553 554 /* 555 * dialog widths are measured in 1/4 character widths 556 * dialog height are measured in 1/8 character heights 557 */ 558 559 static LRESULT 560 MultiInputDialog( HINSTANCE hinst, HWND hwndOwner, 561 char * ptext[], int numlines, int width, 562 int tb_cnt, struct textField * tb) 563 { 564 HGLOBAL hgbl; 565 LPDLGTEMPLATE lpdt; 566 LPDLGITEMTEMPLATE lpdit; 567 LPWORD lpw; 568 LPWSTR lpwsz; 569 LRESULT ret; 570 int nchar, i; 571 size_t pwid; 572 573 hgbl = GlobalAlloc(GMEM_ZEROINIT, 4096); 574 if (!hgbl) 575 return -1; 576 577 mid_cnt = tb_cnt; 578 mid_tb = tb; 579 580 lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl); 581 582 // Define a dialog box. 583 584 lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU 585 | DS_MODALFRAME | WS_CAPTION | DS_CENTER 586 | DS_SETFOREGROUND | DS_3DLOOK 587 | DS_SHELLFONT | DS_NOFAILCREATE; 588 lpdt->cdit = numlines + (2 * tb_cnt) + 2; // number of controls 589 lpdt->x = 10; 590 lpdt->y = 10; 591 lpdt->cx = 20 + width * 4; 592 lpdt->cy = 20 + (numlines + tb_cnt + 4) * 14; 593 594 lpw = (LPWORD) (lpdt + 1); 595 *lpw++ = 0; // no menu 596 *lpw++ = 0; // predefined dialog box class (by default) 597 598 lpwsz = (LPWSTR) lpw; 599 nchar = MultiByteToWideChar (CP_ACP, 0, "", -1, lpwsz, 128); 600 lpw += nchar; 601 *lpw++ = 8; // font size (points) 602 lpwsz = (LPWSTR) lpw; 603 nchar = MultiByteToWideChar (CP_ACP, 0, "MS Shell Dlg", 604 -1, lpwsz, 128); 605 lpw += nchar; 606 607 //----------------------- 608 // Define an OK button. 609 //----------------------- 610 lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary 611 lpdit = (LPDLGITEMTEMPLATE) lpw; 612 lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_BORDER; 613 lpdit->dwExtendedStyle = 0; 614 lpdit->x = (lpdt->cx - 14)/4 - 20; 615 lpdit->y = 10 + (numlines + tb_cnt + 2) * 14; 616 lpdit->cx = 40; 617 lpdit->cy = 14; 618 lpdit->id = IDOK; // OK button identifier 619 620 lpw = (LPWORD) (lpdit + 1); 621 *lpw++ = 0xFFFF; 622 *lpw++ = 0x0080; // button class 623 624 lpwsz = (LPWSTR) lpw; 625 nchar = MultiByteToWideChar (CP_ACP, 0, "OK", -1, lpwsz, 50); 626 lpw += nchar; 627 *lpw++ = 0; // no creation data 628 629 //----------------------- 630 // Define an Cancel button. 631 //----------------------- 632 lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary 633 lpdit = (LPDLGITEMTEMPLATE) lpw; 634 lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP | WS_BORDER; 635 lpdit->dwExtendedStyle = 0; 636 lpdit->x = (lpdt->cx - 14)*3/4 - 20; 637 lpdit->y = 10 + (numlines + tb_cnt + 2) * 14; 638 lpdit->cx = 40; 639 lpdit->cy = 14; 640 lpdit->id = IDCANCEL; // CANCEL button identifier 641 642 lpw = (LPWORD) (lpdit + 1); 643 *lpw++ = 0xFFFF; 644 *lpw++ = 0x0080; // button class 645 646 lpwsz = (LPWSTR) lpw; 647 nchar = MultiByteToWideChar (CP_ACP, 0, "Cancel", -1, lpwsz, 50); 648 lpw += nchar; 649 *lpw++ = 0; // no creation data 650 651 /* Add controls for preface data */ 652 for ( i=0; i<numlines; i++) { 653 /*----------------------- 654 * Define a static text control. 655 *-----------------------*/ 656 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */ 657 lpdit = (LPDLGITEMTEMPLATE) lpw; 658 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT; 659 lpdit->dwExtendedStyle = 0; 660 lpdit->x = 10; 661 lpdit->y = 10 + i * 14; 662 lpdit->cx = strlen(ptext[i]) * 4 + 10; 663 lpdit->cy = 14; 664 lpdit->id = ID_TEXT + i; // text identifier 665 666 lpw = (LPWORD) (lpdit + 1); 667 *lpw++ = 0xFFFF; 668 *lpw++ = 0x0082; // static class 669 670 lpwsz = (LPWSTR) lpw; 671 nchar = MultiByteToWideChar (CP_ACP, 0, ptext[i], 672 -1, lpwsz, 2*width); 673 lpw += nchar; 674 *lpw++ = 0; // no creation data 675 } 676 677 for ( i=0, pwid = 0; i<tb_cnt; i++) { 678 if ( pwid < strlen(tb[i].label) ) 679 pwid = strlen(tb[i].label); 680 } 681 682 for ( i=0; i<tb_cnt; i++) { 683 /* Prompt */ 684 /*----------------------- 685 * Define a static text control. 686 *-----------------------*/ 687 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */ 688 lpdit = (LPDLGITEMTEMPLATE) lpw; 689 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT; 690 lpdit->dwExtendedStyle = 0; 691 lpdit->x = 10; 692 lpdit->y = 10 + (numlines + i + 1) * 14; 693 lpdit->cx = pwid * 4; 694 lpdit->cy = 14; 695 lpdit->id = ID_TEXT + numlines + i; // text identifier 696 697 lpw = (LPWORD) (lpdit + 1); 698 *lpw++ = 0xFFFF; 699 *lpw++ = 0x0082; // static class 700 701 lpwsz = (LPWSTR) lpw; 702 nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].label ? tb[i].label : "", 703 -1, lpwsz, 128); 704 lpw += nchar; 705 *lpw++ = 0; // no creation data 706 707 /*----------------------- 708 * Define an edit control. 709 *-----------------------*/ 710 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */ 711 lpdit = (LPDLGITEMTEMPLATE) lpw; 712 lpdit->style = WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP | WS_BORDER | (tb[i].echo == 1 ? 0L : ES_PASSWORD); 713 lpdit->dwExtendedStyle = 0; 714 lpdit->x = 10 + (pwid + 1) * 4; 715 lpdit->y = 10 + (numlines + i + 1) * 14; 716 lpdit->cx = (width - (pwid + 1)) * 4; 717 lpdit->cy = 14; 718 lpdit->id = ID_MID_TEXT + i; // identifier 719 720 lpw = (LPWORD) (lpdit + 1); 721 *lpw++ = 0xFFFF; 722 *lpw++ = 0x0081; // edit class 723 724 lpwsz = (LPWSTR) lpw; 725 nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].def ? tb[i].def : "", 726 -1, lpwsz, 128); 727 lpw += nchar; 728 *lpw++ = 0; // no creation data 729 } 730 731 GlobalUnlock(hgbl); 732 ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl, 733 hwndOwner, (DLGPROC) MultiInputDialogProc); 734 GlobalFree(hgbl); 735 736 switch ( ret ) { 737 case 0: /* Timeout */ 738 return -1; 739 case IDOK: 740 return 1; 741 case IDCANCEL: 742 return 0; 743 default: { 744 char buf[256]; 745 sprintf(buf,"DialogBoxIndirect() failed: %d",GetLastError()); 746 MessageBox(hwndOwner, 747 buf, 748 "GetLastError()", 749 MB_OK | MB_ICONINFORMATION | MB_TASKMODAL); 750 return -1; 751 } 752 } 753 } 754 755 static int 756 multi_field_dialog(HWND hParent, char * preface, int n, struct textField tb[]) 757 { 758 extern HINSTANCE hLeashInst; 759 size_t maxwidth = 0; 760 int numlines = 0; 761 size_t len; 762 char * plines[16], *p = preface ? preface : ""; 763 int i; 764 765 for ( i=0; i<16; i++ ) 766 plines[i] = NULL; 767 768 while (*p && numlines < 16) { 769 plines[numlines++] = p; 770 for ( ;*p && *p != '\r' && *p != '\n'; p++ ); 771 if ( *p == '\r' && *(p+1) == '\n' ) { 772 *p++ = '\0'; 773 p++; 774 } else if ( *p == '\n' ) { 775 *p++ = '\0'; 776 } 777 if ( strlen(plines[numlines-1]) > maxwidth ) 778 maxwidth = strlen(plines[numlines-1]); 779 } 780 781 for ( i=0;i<n;i++ ) { 782 len = strlen(tb[i].label) + 1 + (tb[i].len > 40 ? 40 : tb[i].len); 783 if ( maxwidth < len ) 784 maxwidth = len; 785 } 786 787 return(MultiInputDialog(hLeashInst, hParent, plines, numlines, maxwidth, n, tb)); 788 } 789 790 static krb5_error_code KRB5_CALLCONV 791 leash_krb5_prompter( krb5_context context, 792 void *data, 793 const char *name, 794 const char *banner, 795 int num_prompts, 796 krb5_prompt prompts[]) 797 { 798 krb5_error_code errcode = 0; 799 int i; 800 struct textField * tb = NULL; 801 int len = 0, blen=0, nlen=0; 802 HWND hParent = (HWND)data; 803 804 if (name) 805 nlen = strlen(name)+2; 806 807 if (banner) 808 blen = strlen(banner)+2; 809 810 tb = (struct textField *) malloc(sizeof(struct textField) * num_prompts); 811 if ( tb != NULL ) { 812 int ok; 813 memset(tb,0,sizeof(struct textField) * num_prompts); 814 for ( i=0; i < num_prompts; i++ ) { 815 tb[i].buf = prompts[i].reply->data; 816 tb[i].len = prompts[i].reply->length; 817 tb[i].label = prompts[i].prompt; 818 tb[i].def = NULL; 819 tb[i].echo = (prompts[i].hidden ? 2 : 1); 820 } 821 822 ok = multi_field_dialog(hParent,(char *)banner,num_prompts,tb); 823 if ( ok ) { 824 for ( i=0; i < num_prompts; i++ ) 825 prompts[i].reply->length = strlen(prompts[i].reply->data); 826 } else 827 errcode = -2; 828 } 829 830 if ( tb ) 831 free(tb); 832 if (errcode) { 833 for (i = 0; i < num_prompts; i++) { 834 memset(prompts[i].reply->data, 0, prompts[i].reply->length); 835 } 836 } 837 return errcode; 838 } 839