Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/windows/leashdll/krb5routines.c
34914 views
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
840