Path: blob/main/crypto/krb5/src/windows/leashdll/krb5routines.c
34914 views
// Module name: krb5routines.c12#include <windows.h>3#define SECURITY_WIN324#include <security.h>56/* _WIN32_WINNT must be 0x0501 or greater to pull in definition of7* all required LSA data types when the Vista SDK NtSecAPI.h is used.8*/9#ifndef _WIN32_WINNT10#define _WIN32_WINNT 0x050111#else12#if _WIN32_WINNT < 0x050113#undef _WIN32_WINNT14#define _WIN32_WINNT 0x050115#endif16#endif17#include <ntsecapi.h>18#include <stdio.h>19#include <string.h>20#include <time.h>21#include <assert.h>2223#include <winsock2.h>2425/* Private Include files */26#include "leashdll.h"27#include <leashwin.h>28#include "leash-int.h"2930#define KRB5_DEFAULT_LIFE 60*60*10 /* 10 hours */3132char *GetTicketFlag(krb5_creds *cred)33{34static char buf[32];35int i = 0;3637buf[i++] = ' ';38buf[i++] = '(';3940if (cred->ticket_flags & TKT_FLG_FORWARDABLE)41buf[i++] = 'F';4243if (cred->ticket_flags & TKT_FLG_FORWARDED)44buf[i++] = 'f';4546if (cred->ticket_flags & TKT_FLG_PROXIABLE)47buf[i++] = 'P';4849if (cred->ticket_flags & TKT_FLG_PROXY)50buf[i++] = 'p';5152if (cred->ticket_flags & TKT_FLG_MAY_POSTDATE)53buf[i++] = 'D';5455if (cred->ticket_flags & TKT_FLG_POSTDATED)56buf[i++] = 'd';5758if (cred->ticket_flags & TKT_FLG_INVALID)59buf[i++] = 'i';6061if (cred->ticket_flags & TKT_FLG_RENEWABLE)62buf[i++] = 'R';6364if (cred->ticket_flags & TKT_FLG_INITIAL)65buf[i++] = 'I';6667if (cred->ticket_flags & TKT_FLG_HW_AUTH)68buf[i++] = 'H';6970if (cred->ticket_flags & TKT_FLG_PRE_AUTH)71buf[i++] = 'A';7273buf[i++] = ')';74buf[i] = '\0';7576if (i <= 3)77buf[0] = '\0';7879return buf;80}8182int83LeashKRB5_renew(void)84{85krb5_error_code code = 0;86krb5_context ctx = 0;87krb5_ccache cc = 0;88krb5_principal me = 0;89krb5_principal server = 0;90krb5_creds my_creds;91krb5_data *realm = 0;9293if ( !pkrb5_init_context )94goto cleanup;9596memset(&my_creds, 0, sizeof(krb5_creds));9798code = pkrb5_init_context(&ctx);99if (code) goto cleanup;100101code = pkrb5_cc_default(ctx, &cc);102if (code) goto cleanup;103104code = pkrb5_cc_get_principal(ctx, cc, &me);105if (code) goto cleanup;106107realm = krb5_princ_realm(ctx, me);108109code = pkrb5_build_principal_ext(ctx, &server,110realm->length,realm->data,111KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,112realm->length,realm->data,1130);114if ( code ) goto cleanup;115116my_creds.client = me;117my_creds.server = server;118119pkrb5_cc_set_flags(ctx, cc, 0);120code = pkrb5_get_renewed_creds(ctx, &my_creds, me, cc, NULL);121pkrb5_cc_set_flags(ctx, cc, KRB5_TC_NOTICKET);122if (code) {123if (code != KRB5KDC_ERR_ETYPE_NOSUPP && code != KRB5_KDC_UNREACH &&124code != KRB5_CC_NOTFOUND)125Leash_krb5_error(code, "krb5_get_renewed_creds()", 0, &ctx, &cc);126goto cleanup;127}128129code = pkrb5_cc_initialize(ctx, cc, me);130if (code) goto cleanup;131132code = pkrb5_cc_store_cred(ctx, cc, &my_creds);133if (code) goto cleanup;134135cleanup:136if (my_creds.client == me)137my_creds.client = 0;138if (my_creds.server == server)139my_creds.server = 0;140pkrb5_free_cred_contents(ctx, &my_creds);141if (me)142pkrb5_free_principal(ctx, me);143if (server)144pkrb5_free_principal(ctx, server);145if (cc)146pkrb5_cc_close(ctx, cc);147if (ctx)148pkrb5_free_context(ctx);149return(code);150}151152static krb5_error_code KRB5_CALLCONV153leash_krb5_prompter( krb5_context context,154void *data,155const char *name,156const char *banner,157int num_prompts,158krb5_prompt prompts[]);159160int161Leash_krb5_kinit(162krb5_context alt_ctx,163HWND hParent,164char *principal_name,165char *password,166krb5_deltat lifetime,167DWORD forwardable,168DWORD proxiable,169krb5_deltat renew_life,170DWORD addressless,171DWORD publicIP172)173{174krb5_error_code code = 0;175krb5_context ctx = 0;176krb5_ccache cc = 0, defcache = 0;177krb5_principal me = 0;178char* name = 0;179krb5_creds my_creds;180krb5_get_init_creds_opt * options = NULL;181krb5_address ** addrs = NULL;182size_t i = 0, addr_count = 0;183int cc_new = 0;184const char * deftype = NULL;185186if (!pkrb5_init_context)187return 0;188189memset(&my_creds, 0, sizeof(my_creds));190191if (alt_ctx)192{193ctx = alt_ctx;194}195else196{197code = pkrb5_init_context(&ctx);198if (code) goto cleanup;199}200201code = pkrb5_get_init_creds_opt_alloc(ctx, &options);202if (code) goto cleanup;203204code = pkrb5_cc_default(ctx, &defcache);205if (code) goto cleanup;206207code = pkrb5_parse_name(ctx, principal_name, &me);208if (code) goto cleanup;209210deftype = pkrb5_cc_get_type(ctx, defcache);211if (me != NULL && pkrb5_cc_support_switch(ctx, deftype)) {212/* Use an existing cache for the specified principal if we can. */213code = pkrb5_cc_cache_match(ctx, me, &cc);214if (code != 0 && code != KRB5_CC_NOTFOUND)215goto cleanup;216if (code == KRB5_CC_NOTFOUND) {217code = pkrb5_cc_new_unique(ctx, deftype, NULL, &cc);218if (code)219goto cleanup;220cc_new = 1;221}222pkrb5_cc_close(ctx, defcache);223} else {224cc = defcache;225}226227code = pkrb5_unparse_name(ctx, me, &name);228if (code) goto cleanup;229230if (lifetime == 0)231lifetime = Leash_get_default_lifetime();232else233lifetime *= 5*60;234235if (renew_life > 0)236renew_life *= 5*60;237238if (lifetime)239pkrb5_get_init_creds_opt_set_tkt_life(options, lifetime);240pkrb5_get_init_creds_opt_set_forwardable(options,241forwardable ? 1 : 0);242pkrb5_get_init_creds_opt_set_proxiable(options,243proxiable ? 1 : 0);244pkrb5_get_init_creds_opt_set_renew_life(options,245renew_life);246if (addressless)247pkrb5_get_init_creds_opt_set_address_list(options,NULL);248else {249if (publicIP)250{251// we are going to add the public IP address specified by the user252// to the list provided by the operating system253krb5_address ** local_addrs=NULL;254DWORD netIPAddr;255256pkrb5_os_localaddr(ctx, &local_addrs);257while ( local_addrs[i++] );258addr_count = i + 1;259260addrs = (krb5_address **) malloc((addr_count+1) * sizeof(krb5_address *));261if ( !addrs ) {262pkrb5_free_addresses(ctx, local_addrs);263assert(0);264}265memset(addrs, 0, sizeof(krb5_address *) * (addr_count+1));266i = 0;267while ( local_addrs[i] ) {268addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));269if (addrs[i] == NULL) {270pkrb5_free_addresses(ctx, local_addrs);271assert(0);272}273274addrs[i]->magic = local_addrs[i]->magic;275addrs[i]->addrtype = local_addrs[i]->addrtype;276addrs[i]->length = local_addrs[i]->length;277addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);278if (!addrs[i]->contents) {279pkrb5_free_addresses(ctx, local_addrs);280assert(0);281}282283memcpy(addrs[i]->contents,local_addrs[i]->contents,284local_addrs[i]->length); /* safe */285i++;286}287pkrb5_free_addresses(ctx, local_addrs);288289addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));290if (addrs[i] == NULL)291assert(0);292293addrs[i]->magic = KV5M_ADDRESS;294addrs[i]->addrtype = AF_INET;295addrs[i]->length = 4;296addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);297if (!addrs[i]->contents)298assert(0);299300netIPAddr = htonl(publicIP);301memcpy(addrs[i]->contents,&netIPAddr,4);302303pkrb5_get_init_creds_opt_set_address_list(options,addrs);304305}306}307308code = pkrb5_get_init_creds_opt_set_out_ccache(ctx, options, cc);309if (code)310goto cleanup;311312code = pkrb5_get_init_creds_password(ctx,313&my_creds,314me,315password, // password316leash_krb5_prompter, // prompter317hParent, // prompter data3180, // start time3190, // service name320options);321// @TODO: make this an option322if ((!code) && (cc != defcache)) {323code = pkrb5_cc_switch(ctx, cc);324if (!code) {325const char *cctype = pkrb5_cc_get_type(ctx, cc);326if (cctype != NULL) {327char defname[20];328sprintf_s(defname, sizeof(defname), "%s:", cctype);329pkrb5int_cc_user_set_default_name(ctx, defname);330}331}332}333cleanup:334if (code && cc_new) {335// don't leave newly-generated empty ccache lying around on failure336pkrb5_cc_destroy(ctx, cc);337cc = NULL;338}339if ( addrs ) {340for ( i=0;i<addr_count;i++ ) {341if ( addrs[i] ) {342if ( addrs[i]->contents )343free(addrs[i]->contents);344free(addrs[i]);345}346}347}348if (my_creds.client == me)349my_creds.client = 0;350pkrb5_free_cred_contents(ctx, &my_creds);351if (name)352pkrb5_free_unparsed_name(ctx, name);353if (me)354pkrb5_free_principal(ctx, me);355if (cc)356pkrb5_cc_close(ctx, cc);357if (options)358pkrb5_get_init_creds_opt_free(ctx, options);359if (ctx && (ctx != alt_ctx))360pkrb5_free_context(ctx);361return(code);362}363364365/**************************************/366/* LeashKRB5destroyTicket(): */367/**************************************/368int369Leash_krb5_kdestroy(370void371)372{373krb5_context ctx;374krb5_ccache cache;375krb5_error_code rc;376377ctx = NULL;378cache = NULL;379rc = Leash_krb5_initialize(&ctx);380if (rc)381return(rc);382383if (rc = pkrb5_cc_default(ctx, &cache))384return(rc);385386rc = pkrb5_cc_destroy(ctx, cache);387388if (ctx != NULL)389pkrb5_free_context(ctx);390391return(rc);392393}394395krb5_error_code396Leash_krb5_cc_default(krb5_context *ctx, krb5_ccache *cache)397{398krb5_error_code rc;399krb5_flags flags;400401char *functionName = NULL;402if (*cache == 0) {403rc = pkrb5_cc_default(*ctx, cache);404if (rc) {405functionName = "krb5_cc_default()";406goto on_error;407}408}409flags = KRB5_TC_NOTICKET;410rc = pkrb5_cc_set_flags(*ctx, *cache, flags);411if (rc) {412if (rc == KRB5_FCC_NOFILE || rc == KRB5_CC_NOTFOUND) {413if (*cache != NULL && *ctx != NULL)414pkrb5_cc_close(*ctx, *cache);415} else {416functionName = "krb5_cc_set_flags()";417goto on_error;418}419}420on_error:421if (rc && functionName) {422Leash_krb5_error(rc, functionName, 0, ctx, cache);423}424return rc;425}426427/**************************************/428/* Leash_krb5_initialize(): */429/**************************************/430int Leash_krb5_initialize(krb5_context *ctx)431{432LPCSTR functionName = NULL;433krb5_error_code rc;434435if (pkrb5_init_context == NULL)436return 1;437438if (*ctx == 0) {439if (rc = (*pkrb5_init_context)(ctx)) {440functionName = "krb5_init_context()";441return Leash_krb5_error(rc, functionName, 0, ctx, NULL);442}443}444return 0;445}446447448/**************************************/449/* Leash_krb5_error(): */450/**************************************/451int452Leash_krb5_error(krb5_error_code rc, LPCSTR FailedFunctionName,453int FreeContextFlag, krb5_context * ctx,454krb5_ccache * cache)455{456#ifdef USE_MESSAGE_BOX457char message[256];458const char *errText;459460errText = perror_message(rc);461_snprintf(message, sizeof(message),462"%s\n(Kerberos error %ld)\n\n%s failed",463errText,464rc,465FailedFunctionName);466message[sizeof(message)-1] = 0;467468MessageBox(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR |469MB_TASKMODAL |470MB_SETFOREGROUND);471#endif /* USE_MESSAGE_BOX */472473if (ctx != NULL && *ctx != NULL) {474if (cache != NULL && *cache != NULL) {475pkrb5_cc_close(*ctx, *cache);476*cache = NULL;477}478479if (FreeContextFlag) {480pkrb5_free_context(*ctx);481*ctx = NULL;482}483}484485return rc;486}487488489/* User Query data structures and functions */490491struct textField {492char * buf; /* Destination buffer address */493int len; /* Destination buffer length */494char * label; /* Label for this field */495char * def; /* Default response for this field */496int echo; /* 0 = no, 1 = yes, 2 = asterisks */497};498499static int mid_cnt = 0;500static struct textField * mid_tb = NULL;501502#define ID_TEXT 150503#define ID_MID_TEXT 300504505static BOOL CALLBACK506MultiInputDialogProc( HWND hDialog, UINT message, WPARAM wParam, LPARAM lParam)507{508int i;509510switch ( message ) {511case WM_INITDIALOG:512if ( GetDlgCtrlID((HWND) wParam) != ID_MID_TEXT )513{514SetFocus(GetDlgItem( hDialog, ID_MID_TEXT));515return FALSE;516}517for ( i=0; i < mid_cnt ; i++ ) {518if (mid_tb[i].echo == 0)519SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, 32, 0);520else if (mid_tb[i].echo == 2)521SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, '*', 0);522}523return TRUE;524525case WM_COMMAND:526switch ( LOWORD(wParam) ) {527case IDOK:528for ( i=0; i < mid_cnt ; i++ ) {529if ( !GetDlgItemText(hDialog, ID_MID_TEXT+i, mid_tb[i].buf, mid_tb[i].len) )530*mid_tb[i].buf = '\0';531}532/* fallthrough */533case IDCANCEL:534EndDialog(hDialog, LOWORD(wParam));535return TRUE;536}537}538return FALSE;539}540541static LPWORD542lpwAlign( LPWORD lpIn )543{544ULONG ul;545546ul = (ULONG) lpIn;547ul += 3;548ul >>=2;549ul <<=2;550return (LPWORD) ul;;551}552553/*554* dialog widths are measured in 1/4 character widths555* dialog height are measured in 1/8 character heights556*/557558static LRESULT559MultiInputDialog( HINSTANCE hinst, HWND hwndOwner,560char * ptext[], int numlines, int width,561int tb_cnt, struct textField * tb)562{563HGLOBAL hgbl;564LPDLGTEMPLATE lpdt;565LPDLGITEMTEMPLATE lpdit;566LPWORD lpw;567LPWSTR lpwsz;568LRESULT ret;569int nchar, i;570size_t pwid;571572hgbl = GlobalAlloc(GMEM_ZEROINIT, 4096);573if (!hgbl)574return -1;575576mid_cnt = tb_cnt;577mid_tb = tb;578579lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);580581// Define a dialog box.582583lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU584| DS_MODALFRAME | WS_CAPTION | DS_CENTER585| DS_SETFOREGROUND | DS_3DLOOK586| DS_SHELLFONT | DS_NOFAILCREATE;587lpdt->cdit = numlines + (2 * tb_cnt) + 2; // number of controls588lpdt->x = 10;589lpdt->y = 10;590lpdt->cx = 20 + width * 4;591lpdt->cy = 20 + (numlines + tb_cnt + 4) * 14;592593lpw = (LPWORD) (lpdt + 1);594*lpw++ = 0; // no menu595*lpw++ = 0; // predefined dialog box class (by default)596597lpwsz = (LPWSTR) lpw;598nchar = MultiByteToWideChar (CP_ACP, 0, "", -1, lpwsz, 128);599lpw += nchar;600*lpw++ = 8; // font size (points)601lpwsz = (LPWSTR) lpw;602nchar = MultiByteToWideChar (CP_ACP, 0, "MS Shell Dlg",603-1, lpwsz, 128);604lpw += nchar;605606//-----------------------607// Define an OK button.608//-----------------------609lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary610lpdit = (LPDLGITEMTEMPLATE) lpw;611lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_BORDER;612lpdit->dwExtendedStyle = 0;613lpdit->x = (lpdt->cx - 14)/4 - 20;614lpdit->y = 10 + (numlines + tb_cnt + 2) * 14;615lpdit->cx = 40;616lpdit->cy = 14;617lpdit->id = IDOK; // OK button identifier618619lpw = (LPWORD) (lpdit + 1);620*lpw++ = 0xFFFF;621*lpw++ = 0x0080; // button class622623lpwsz = (LPWSTR) lpw;624nchar = MultiByteToWideChar (CP_ACP, 0, "OK", -1, lpwsz, 50);625lpw += nchar;626*lpw++ = 0; // no creation data627628//-----------------------629// Define an Cancel button.630//-----------------------631lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary632lpdit = (LPDLGITEMTEMPLATE) lpw;633lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP | WS_BORDER;634lpdit->dwExtendedStyle = 0;635lpdit->x = (lpdt->cx - 14)*3/4 - 20;636lpdit->y = 10 + (numlines + tb_cnt + 2) * 14;637lpdit->cx = 40;638lpdit->cy = 14;639lpdit->id = IDCANCEL; // CANCEL button identifier640641lpw = (LPWORD) (lpdit + 1);642*lpw++ = 0xFFFF;643*lpw++ = 0x0080; // button class644645lpwsz = (LPWSTR) lpw;646nchar = MultiByteToWideChar (CP_ACP, 0, "Cancel", -1, lpwsz, 50);647lpw += nchar;648*lpw++ = 0; // no creation data649650/* Add controls for preface data */651for ( i=0; i<numlines; i++) {652/*-----------------------653* Define a static text control.654*-----------------------*/655lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */656lpdit = (LPDLGITEMTEMPLATE) lpw;657lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;658lpdit->dwExtendedStyle = 0;659lpdit->x = 10;660lpdit->y = 10 + i * 14;661lpdit->cx = strlen(ptext[i]) * 4 + 10;662lpdit->cy = 14;663lpdit->id = ID_TEXT + i; // text identifier664665lpw = (LPWORD) (lpdit + 1);666*lpw++ = 0xFFFF;667*lpw++ = 0x0082; // static class668669lpwsz = (LPWSTR) lpw;670nchar = MultiByteToWideChar (CP_ACP, 0, ptext[i],671-1, lpwsz, 2*width);672lpw += nchar;673*lpw++ = 0; // no creation data674}675676for ( i=0, pwid = 0; i<tb_cnt; i++) {677if ( pwid < strlen(tb[i].label) )678pwid = strlen(tb[i].label);679}680681for ( i=0; i<tb_cnt; i++) {682/* Prompt */683/*-----------------------684* Define a static text control.685*-----------------------*/686lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */687lpdit = (LPDLGITEMTEMPLATE) lpw;688lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;689lpdit->dwExtendedStyle = 0;690lpdit->x = 10;691lpdit->y = 10 + (numlines + i + 1) * 14;692lpdit->cx = pwid * 4;693lpdit->cy = 14;694lpdit->id = ID_TEXT + numlines + i; // text identifier695696lpw = (LPWORD) (lpdit + 1);697*lpw++ = 0xFFFF;698*lpw++ = 0x0082; // static class699700lpwsz = (LPWSTR) lpw;701nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].label ? tb[i].label : "",702-1, lpwsz, 128);703lpw += nchar;704*lpw++ = 0; // no creation data705706/*-----------------------707* Define an edit control.708*-----------------------*/709lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */710lpdit = (LPDLGITEMTEMPLATE) lpw;711lpdit->style = WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP | WS_BORDER | (tb[i].echo == 1 ? 0L : ES_PASSWORD);712lpdit->dwExtendedStyle = 0;713lpdit->x = 10 + (pwid + 1) * 4;714lpdit->y = 10 + (numlines + i + 1) * 14;715lpdit->cx = (width - (pwid + 1)) * 4;716lpdit->cy = 14;717lpdit->id = ID_MID_TEXT + i; // identifier718719lpw = (LPWORD) (lpdit + 1);720*lpw++ = 0xFFFF;721*lpw++ = 0x0081; // edit class722723lpwsz = (LPWSTR) lpw;724nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].def ? tb[i].def : "",725-1, lpwsz, 128);726lpw += nchar;727*lpw++ = 0; // no creation data728}729730GlobalUnlock(hgbl);731ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl,732hwndOwner, (DLGPROC) MultiInputDialogProc);733GlobalFree(hgbl);734735switch ( ret ) {736case 0: /* Timeout */737return -1;738case IDOK:739return 1;740case IDCANCEL:741return 0;742default: {743char buf[256];744sprintf(buf,"DialogBoxIndirect() failed: %d",GetLastError());745MessageBox(hwndOwner,746buf,747"GetLastError()",748MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);749return -1;750}751}752}753754static int755multi_field_dialog(HWND hParent, char * preface, int n, struct textField tb[])756{757extern HINSTANCE hLeashInst;758size_t maxwidth = 0;759int numlines = 0;760size_t len;761char * plines[16], *p = preface ? preface : "";762int i;763764for ( i=0; i<16; i++ )765plines[i] = NULL;766767while (*p && numlines < 16) {768plines[numlines++] = p;769for ( ;*p && *p != '\r' && *p != '\n'; p++ );770if ( *p == '\r' && *(p+1) == '\n' ) {771*p++ = '\0';772p++;773} else if ( *p == '\n' ) {774*p++ = '\0';775}776if ( strlen(plines[numlines-1]) > maxwidth )777maxwidth = strlen(plines[numlines-1]);778}779780for ( i=0;i<n;i++ ) {781len = strlen(tb[i].label) + 1 + (tb[i].len > 40 ? 40 : tb[i].len);782if ( maxwidth < len )783maxwidth = len;784}785786return(MultiInputDialog(hLeashInst, hParent, plines, numlines, maxwidth, n, tb));787}788789static krb5_error_code KRB5_CALLCONV790leash_krb5_prompter( krb5_context context,791void *data,792const char *name,793const char *banner,794int num_prompts,795krb5_prompt prompts[])796{797krb5_error_code errcode = 0;798int i;799struct textField * tb = NULL;800int len = 0, blen=0, nlen=0;801HWND hParent = (HWND)data;802803if (name)804nlen = strlen(name)+2;805806if (banner)807blen = strlen(banner)+2;808809tb = (struct textField *) malloc(sizeof(struct textField) * num_prompts);810if ( tb != NULL ) {811int ok;812memset(tb,0,sizeof(struct textField) * num_prompts);813for ( i=0; i < num_prompts; i++ ) {814tb[i].buf = prompts[i].reply->data;815tb[i].len = prompts[i].reply->length;816tb[i].label = prompts[i].prompt;817tb[i].def = NULL;818tb[i].echo = (prompts[i].hidden ? 2 : 1);819}820821ok = multi_field_dialog(hParent,(char *)banner,num_prompts,tb);822if ( ok ) {823for ( i=0; i < num_prompts; i++ )824prompts[i].reply->length = strlen(prompts[i].reply->data);825} else826errcode = -2;827}828829if ( tb )830free(tb);831if (errcode) {832for (i = 0; i < num_prompts; i++) {833memset(prompts[i].reply->data, 0, prompts[i].reply->length);834}835}836return errcode;837}838839840