Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

790 lines
24 KiB

/*++
Copyright (c) 2000,2001 Microsoft Corporation
Module Name:
EDITDLG.CPP
Abstract:
Implementation of the properties dialog which allows the user to create
a new credential or edit an old one.
Author:
Environment:
WinXP
--*/
//////////////////////////////////////////////////////////////////////////////
//
// Include files
//
#include <stdlib.h>
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <winbase.h>
#include <tchar.h>
#include <windns.h>
#include <shellapi.h>
#include <wincrui.h>
#include <htmlhelp.h>
#include <wincred.h>
#include <credp.h>
#include <comctrlp.h>
#include <scuisupp.h>
#include <shfusion.h>
#include "switches.h"
#include "Dlg.h"
#include "Res.h"
#include "KRDlg.h"
#include "keymgr.h"
#include "testaudit.h"
// character length of buffer to contain localized description string for
// the credential being created/edited
#define DESCBUFFERLEN 500
BOOL g_fPswChanged; // password window touched by user
extern BOOL g_fReloadList;
/**********************************************************************
Return the help string associated with the UI element passed by ID
as input.
**********************************************************************/
UINT C_AddKeyDlg::MapID(UINT uiID)
{
switch(uiID)
{
case 1003:
return IDH_CUIUSER;
case 1005:
return IDH_CUIPSW;
case 1010:
return IDH_CUIVIEW;
case IDOK:
return IDH_CLOSE;
case IDCANCEL:
return IDH_DCANCEL;
case IDD_ADDCRED:
return IDH_ADDCRED;
case IDC_TARGET_NAME:
return IDH_TARGETNAME;
case IDC_OLD_PASSWORD:
return IDH_OLDPASSWORD;
case IDC_NEW_PASSWORD:
return IDH_NEWPASSWORD;
case IDC_CONFIRM_PASSWORD:
return IDH_CONFIRM;
case IDD_KEYRING:
return IDH_KEYRING;
case IDC_KEYLIST:
return IDH_KEYLIST;
case IDC_NEWKEY:
return IDH_NEW;
case IDC_EDITKEY:
return IDH_EDIT;
case IDC_DELETEKEY:
return IDH_DELETE;
case IDC_CHANGE_PASSWORD:
return IDH_CHANGEPASSWORD;
default:
return IDS_NOHELP;
}
}
//////////////////////////////////////////////////////////////////////////////
//
// C_AddKeyDlg
//
// Constructor.
//
// parameters:
// hwndParent parent window for the dialog (may be NULL)
// hInstance instance handle of the parent window (may be NULL)
// lIDD dialog template id
// pfnDlgProc pointer to the function that will process messages for
// the dialog. if it is NULL, the default dialog proc
// will be used.
//
// returns:
// Nothing.
//
//////////////////////////////////////////////////////////////////////////////
C_AddKeyDlg::C_AddKeyDlg(
HWND hwndParent,
HINSTANCE hInstance,
LONG lIDD,
DLGPROC pfnDlgProc // = NULL
)
: C_Dlg(hwndParent, hInstance, lIDD, pfnDlgProc)
{
m_hInst = hInstance;
} // C_AddKeyDlg::C_AddKeyDlg
/**********************************************************************
Fill properties dialog fields with values taken from the currently selected
credential.
**********************************************************************/
void
C_AddKeyDlg::EditFillDialog(void)
{
TCHAR szTitle[CRED_MAX_STRING_LENGTH + 1]; // buffer to hold window title string
ASSERT(g_pExistingCred);
if (NULL == g_pExistingCred) return;
// Set up persistence in the UI
g_dwPersist = g_pExistingCred->Persist;
g_dwType = g_pExistingCred->Type;
// Enable the change password stuff only on domain password creds
//
switch (g_pExistingCred->Type)
{
case CRED_TYPE_DOMAIN_PASSWORD:
CHECKPOINT(1,"Keymgr: Edit - Password cred edit");
ShowWindow(m_hwndChgPsw,SW_NORMAL);
ShowWindow(m_hwndPswLbl,SW_NORMAL);
//deliberate fallthrough
case CRED_TYPE_DOMAIN_CERTIFICATE:
CHECKPOINT(2,"keymgr: Edit - Certificate cred edit");
LoadString ( m_hInst, IDS_TITLE, szTitle, 200 );
SendMessage(m_hDlg,WM_SETTEXT,0,(LPARAM) szTitle);
break;
case CRED_TYPE_GENERIC:
// generic cred not supported yet
break;
case CRED_TYPE_DOMAIN_VISIBLE_PASSWORD:
// passport cred should not get this far.
ASSERT(0);
break;
default:
// type data bad
ASSERT(0);
break;
}
// Write targetname to the UI
SendMessage(m_hwndTName, WM_SETTEXT,0,(LPARAM) g_pExistingCred->TargetName);
// Write username to the UI - take directly from the existing cred
if (!Credential_SetUserName(m_hwndCred,g_pExistingCred->UserName))
{
// make a copy of the original username
_tcsncpy(m_szUsername,g_pExistingCred->UserName,CRED_MAX_USERNAME_LENGTH);
m_szUsername[CRED_MAX_USERNAME_LENGTH] = 0;
}
}
/**********************************************************************
Compose the UI string which describes the type and persistence of the
credential being created or edited. Write the text to the text control
on the dialog.
**********************************************************************/
void C_AddKeyDlg::ShowDescriptionText(DWORD dwtype, DWORD Persist)
{
WCHAR szMsg[DESCBUFFERLEN + 1];
WCHAR szTemp[DESCBUFFERLEN + 1];
INT iRem = DESCBUFFERLEN; // remaining space in the buffer
CHECKPOINT(3,"Keymgr: Edit - Show description on prop dialog");
memset(szMsg,0,sizeof(szMsg));
if ((dwtype != CRED_TYPE_DOMAIN_PASSWORD) &&
(dwtype != CRED_TYPE_DOMAIN_CERTIFICATE))
{
// A generic credential - not currently supported
LoadString ( m_hInst, IDS_DESCAPPCRED, szTemp, DESCBUFFERLEN );
wcsncpy(szMsg,szTemp,DESCBUFFERLEN);
szMsg[DESCBUFFERLEN] = 0;
iRem -= wcslen(szMsg);
}
else
{
// a domain-type credential
// Show usage local machine versis domain
if (Persist != CRED_PERSIST_ENTERPRISE)
{
// either local persist or session persist creds show this string
CHECKPOINT(12,L"Keymgr: Edit - Show properties of non-enterprise persist cred");
LoadString ( m_hInst, IDS_DESCLOCAL, szTemp, DESCBUFFERLEN );
}
else
{
// enterprise persistence - if you have a roaming profile, etc...
CHECKPOINT(13,L"Keymgr: Edit - Show properties of enterprise persist cred");
LoadString ( m_hInst, IDS_DESCBASE, szTemp, DESCBUFFERLEN );
}
wcsncpy(szMsg,szTemp,DESCBUFFERLEN);
szMsg[DESCBUFFERLEN] = 0;
iRem -= wcslen(szMsg);
}
// String: until you log off -or- until you delete it
if (Persist == CRED_PERSIST_SESSION)
{
// until you log off
CHECKPOINT(18,L"Keymgr: Edit - Show properties of session cred");
LoadString ( m_hInst, IDS_PERSISTLOGOFF, szTemp, DESCBUFFERLEN );
}
else
{
// until you delete it
CHECKPOINT(19,L"Keymgr: Edit - Show properties of non-session cred");
LoadString ( m_hInst, IDS_PERSISTDELETE, szTemp, DESCBUFFERLEN );
}
iRem -= wcslen(szTemp);
if (0 < iRem) wcsncat(szMsg,szTemp,iRem);
szMsg[DESCBUFFERLEN] = 0;
SendMessage(m_hwndDescription, WM_SETTEXT,0,(LPARAM) szMsg);
return;
}
//////////////////////////////////////////////////////////////////////////////
//
// OnInitDialog
//
// Dialog control and data initialization.
//
// parameters:
// hwndDlg window handle of the dialog box
// hwndFocus window handle of the control that will receive focus
//
// returns:
// TRUE if the system should set the default keyboard focus
// FALSE if the keyboard focus is set by this app
//
//////////////////////////////////////////////////////////////////////////////
BOOL
C_AddKeyDlg::OnInitDialog(
HWND hwndDlg,
HWND hwndFocus
)
{
C_Dlg::OnInitDialog(hwndDlg, hwndFocus);
m_hDlg = hwndDlg;
// get control handles, used for various purposes by other member fns
m_hwndCred = GetDlgItem(m_hDlg,IDC_CRED);
m_hwndTName = GetDlgItem(m_hDlg,IDC_TARGET_NAME);
m_hwndChgPsw = GetDlgItem(m_hDlg,IDC_CHGPSW);
m_hwndPswLbl = GetDlgItem(m_hDlg,IDC_DOMAINPSWLABEL);
m_hwndDescription = GetDlgItem(m_hDlg,IDC_DESCRIPTION);
// Initialize the cred control to show all usable authenticators
if (!Credential_InitStyle(m_hwndCred,CRS_USERNAMES | CRS_CERTIFICATES | CRS_SMARTCARDS))
{
return FALSE;
}
// Establish limits on string lengths from the user
SendMessage(m_hwndTName,EM_LIMITTEXT,CRED_MAX_GENERIC_TARGET_NAME_LENGTH,0);
// Show dummy password for edited credential
if (m_bEdit)
{
Credential_SetPassword(m_hwndCred,L"********");
}
// Set up the allowable persistence options depending on the type of user session
// Set the default persistence unless overriden by a cred read on edit
g_dwType = CRED_TYPE_DOMAIN_PASSWORD;
g_dwPersist = GetPersistenceOptions(CRED_TYPE_DOMAIN_PASSWORD);
// By default, hide all optional controls. These will be enabled as appropriate
ShowWindow(m_hwndChgPsw,SW_HIDE);
ShowWindow(m_hwndPswLbl,SW_HIDE);
// If editing an existing credential, fill dialog fields with existing data
// will also override type and persistence globals
if (m_bEdit)
{
EditFillDialog();
}
g_fPswChanged = FALSE; // password so far unedited
ShowDescriptionText(g_dwType,g_dwPersist);
return TRUE;
// On exit from OnInitDialog, g_szTargetName holds the currently selected
// credential's old name, undecorated (having had a null dropped before
// the suffix)
} // end C_AddKeyDlg::OnInitDialog
/**********************************************************************
Pro forma OnDestroyDialog()
**********************************************************************/
BOOL
C_AddKeyDlg::OnDestroyDialog(
void )
{
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////
//
// OnAppMessage
//
//////////////////////////////////////////////////////////////////////////////
BOOL
C_AddKeyDlg::OnAppMessage(
UINT uMessage,
WPARAM wparam,
LPARAM lparam)
{
return TRUE;
}
/**********************************************************************
On a help request event, get the control ID, map it to a help string,
and present this as a tooltip over the control.
**********************************************************************/
BOOL
C_AddKeyDlg::OnHelpInfo(LPARAM lp)
{
HELPINFO* pH;
INT iMapped;
pH = (HELPINFO *) lp;
HH_POPUP stPopUp;
RECT rcW;
UINT gID;
gID = pH->iCtrlId;
iMapped = MapID(gID);
CHECKPOINT(5,"Keymgr: Edit - Add dialog OnHelpInfo");
if (iMapped == 0) return TRUE;
if (IDS_NOHELP != iMapped)
{
memset(&stPopUp,0,sizeof(stPopUp));
stPopUp.cbStruct = sizeof(HH_POPUP);
stPopUp.hinst = g_hInstance;
stPopUp.idString = iMapped;
stPopUp.pszText = NULL;
stPopUp.clrForeground = -1;
stPopUp.clrBackground = -1;
stPopUp.rcMargins.top = -1;
stPopUp.rcMargins.bottom = -1;
stPopUp.rcMargins.left = -1;
stPopUp.rcMargins.right = -1;
// bug 393244 - leave NULL to allow HHCTRL.OCX to get font information of its own,
// which it needs to perform the UNICODE to multibyte conversion. Otherwise,
// HHCTRL must convert using this font without charset information.
stPopUp.pszFont = NULL;
if (GetWindowRect((HWND)pH->hItemHandle,&rcW))
{
stPopUp.pt.x = (rcW.left + rcW.right) / 2;
stPopUp.pt.y = (rcW.top + rcW.bottom) / 2;
}
else stPopUp.pt = pH->MousePos;
HtmlHelp((HWND) pH->hItemHandle,NULL,HH_DISPLAY_TEXT_POPUP,(DWORD_PTR) &stPopUp);
}
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////
//
// OnCommand
//
// Route WM_COMMAND message to appropriate handlers.
//
// parameters:
// wNotifyCode code describing action that has occured
// wSenderId id of the control sending the message, if the message
// is from a dialog
// hwndSender window handle of the window sending the message if the
// message is not from a dialog
//
// returns:
// TRUE if the message was processed completely
// FALSE if Windows is to process the message
//
////////////////////////////////////////////////////////////////////////////
BOOL
C_AddKeyDlg::OnCommand(
WORD wNotifyCode,
WORD wSenderId,
HWND hwndSender
)
{
BOOL fHandled = FALSE; // indicate message handled
switch (wSenderId)
{
case IDC_CRED:
{
if (wNotifyCode == CRN_PASSWORDCHANGE)
{
g_fPswChanged = TRUE;
}
}
break;
case IDOK:
if (BN_CLICKED == wNotifyCode)
{
OnOK( );
fHandled = TRUE;
}
break;
case IDC_CHGPSW:
{
OnChangePassword();
//EndDialog(IDCANCEL); do not cancel out of properties dialog
break;
}
case IDCANCEL:
if (BN_CLICKED == wNotifyCode)
{
EndDialog(IDCANCEL);
fHandled = TRUE;
}
break;
} // switch
return fHandled;
} // C_AddKeyDlg::OnCommand
////////////////////////////////////////////////////////////////////////////
//
// OnOK
//
// Validate user name, synthesize computer name, and destroy dialog.
//
// parameters:
// None.
//
// returns:
// Nothing.
//
//////////////////////////////////////////////////////////////////////////////
void
C_AddKeyDlg::OnOK( )
{
LONG_PTR j,lCType;
TCHAR szMsg[MAX_STRING_SIZE + 1];
TCHAR szTitle[MAX_STRING_SIZE + 1];
TCHAR szUser[FULLNAMEMAXLENGTH + 1]; // in from dialog
TCHAR szPsw[PWLEN + 1]; // in from dialog
TCHAR *pszNewTarget; // in from dialog
TCHAR *pszTrimdName; // mod'd in from dialog
DWORD dwFlags = 0; // in from dialog
CREDENTIAL stCredential; // local copy of cred
UINT cbPassword;
BOOL bResult;
BOOL IsCertificate = FALSE;
BOOL fDeleteOldCred = FALSE;
BOOL fRenameCred = FALSE;
BOOL fPsw = FALSE;
ASSERT(::IsWindow(m_hwnd));
szPsw[0]= 0;
szUser[0] = 0;
// Start with a blank cred if this is not an edit, else make a copy of existing one
if ((m_bEdit) && (g_pExistingCred))
memcpy((void *) &stCredential,(void *) g_pExistingCred,sizeof(CREDENTIAL));
else
memset((void *) &stCredential,0,sizeof(CREDENTIAL));
pszNewTarget = (TCHAR *) malloc((CRED_MAX_GENERIC_TARGET_NAME_LENGTH + 1) * sizeof(TCHAR));
if (NULL == pszNewTarget)
{
return;
}
pszNewTarget[0] = 0;
// Get Username from the cred control - find out if is a certificate by
// IsMarshalledName().
if (Credential_GetUserName(m_hwndCred,szUser,FULLNAMEMAXLENGTH))
{
IsCertificate = CredIsMarshaledCredential(szUser);
}
// fetch password/PIN into szPsw. set fPsw if value is valid
fPsw = Credential_GetPassword(m_hwndCred,szPsw,CRED_MAX_STRING_LENGTH);
// Check to see that both name and psw are not missing
if ( wcslen ( szUser ) == 0 &&
wcslen ( szPsw ) == 0 )
{
LoadString ( m_hInst, IDS_ADDFAILED, szMsg, MAX_STRING_SIZE );
LoadString ( m_hInst, IDS_APP_NAME, szTitle, MAX_STRING_SIZE );
MessageBox ( m_hDlg, szMsg, szTitle, MB_OK );
free(pszNewTarget);
return;
}
// If the user has typed a \\server style target name, strip the leading hacks
j = SendMessage(m_hwndTName,WM_GETTEXT,CRED_MAX_GENERIC_TARGET_NAME_LENGTH,(LPARAM)pszNewTarget);
ASSERT(j);
pszTrimdName = pszNewTarget;
while (*pszTrimdName == TCHAR('\\')) pszTrimdName++;
// Now have:
// pszTrimdName
// uzUser
// szPsw
// fPsw
// If target name edited, will need to rename
// If type changed or psw edited, psw blob will be removed/replaced
// If type changed, will need to remove old cred
if ((m_bEdit) && (g_pExistingCred))
{
CHECKPOINT(4,"Keymgr: Edit - OnOK for add/prop dialog");
if (0 != _tcscmp(pszTrimdName,g_szTargetName)) fRenameCred = TRUE;
// Note that currently DOMAIN_VISIBLE_PASSWORD creds cannot be edited
// or created, so there is no handler for those types.
if (g_pExistingCred->Type == CRED_TYPE_GENERIC)
{
lCType = CRED_TYPE_GENERIC;
}
else
{
if (IsCertificate) lCType = CRED_TYPE_DOMAIN_CERTIFICATE;
else lCType = CRED_TYPE_DOMAIN_PASSWORD;
}
// If the type of the cred changes, you can't save the psw info
if ((DWORD)lCType != g_pExistingCred->Type)
{
dwFlags &= ~CRED_PRESERVE_CREDENTIAL_BLOB;
fDeleteOldCred = TRUE;
}
else
{
dwFlags |= CRED_PRESERVE_CREDENTIAL_BLOB;
}
// You also don't save the psw info if the user changed it explicitly
if (g_fPswChanged)
{
dwFlags &= ~CRED_PRESERVE_CREDENTIAL_BLOB;
}
#if TESTAUDIT
if (dwFlags & CRED_PRESERVE_CREDENTIAL_BLOB)
{
CHECKPOINT(21,L"Keymgr: Edit - Saving a cred preserving the old psw (rename)");
}
else
{
CHECKPOINT(20,L"Keymgr: Edit - Saving a cred while not preserving the old password");
}
#endif
}
else
{
// if is a certificate marshalled name is cert or generic
// if not is generic or domain
if (IsCertificate)
{
lCType = CRED_TYPE_DOMAIN_CERTIFICATE;
}
else
{
lCType = CRED_TYPE_DOMAIN_PASSWORD;
}
}
// Save credential. If certificate type, do not include a psw blob.
// After save, if the name had changed, rename the cred
stCredential.UserName = szUser;
stCredential.Type = (DWORD) lCType;
// If not an edit, fill in targetname, else do rename later
if (!m_bEdit)
{
stCredential.TargetName = pszTrimdName;
}
stCredential.Persist = g_dwPersist;
// fill credential blob data with nothing if the cred control UI has
// disabled the password box. Otherwise supply psw information if
// the user has edited the box contents.
if (fPsw)
{
if (g_fPswChanged)
{
#ifdef LOUDLY
OutputDebugString(L"Storing new password data\n");
#endif
cbPassword = wcslen(szPsw) * sizeof(TCHAR);
stCredential.CredentialBlob = (unsigned char *)szPsw;
stCredential.CredentialBlobSize = cbPassword;
}
#ifdef LOUDLY
else
{
OutputDebugString(L"No password data stored.\n");
}
#endif
}
bResult = CredWrite(&stCredential,dwFlags);
SecureZeroMemory(szPsw,sizeof(szPsw)); // delete psw local copy
if ( bResult != TRUE )
{
#ifdef LOUDLY
WCHAR szw[200];
DWORD dwE = GetLastError();
swprintf(szw,L"CredWrite failed. Last Error is %x\n",dwE);
OutputDebugString(szw);
#endif
AdviseUser();
free(pszNewTarget);
return;
}
// Delete old credential only if type has changed
// Otherwise if name changed, do a rename of the cred
// If the old cred is deleted, rename is obviated
if (fDeleteOldCred)
{
#ifdef LOUDLY
OutputDebugString(L"CredDelete called\n");
#endif
CHECKPOINT(7,"Keymgr: Edit - OnOK - deleting old cred (type changed)");
CredDelete(g_szTargetName,(ULONG) g_pExistingCred->Type,0);
g_fReloadList = TRUE;
}
else if (fRenameCred)
{
CHECKPOINT(8,"Keymgr: Edit - OnOK - renaming current cred, same type");
bResult = CredRename(g_szTargetName, pszTrimdName, (ULONG) stCredential.Type,0);
g_fReloadList = TRUE;
#ifdef LOUDLY
OutputDebugString(L"CredRename called\n");
#endif
if (!bResult)
{
// bugbug: How can rename fail?
// If it does, what would you tell the user?
LoadString ( m_hInst, IDS_RENAMEFAILED, szMsg, MAX_STRING_SIZE );
LoadString ( m_hInst, IDS_APP_NAME, szTitle, MAX_STRING_SIZE );
MessageBox ( m_hDlg, szMsg, szTitle, MB_OK );
free(pszNewTarget);
return;
}
}
#if TESTAUDIT
if (stCredential.Type == CRED_TYPE_DOMAIN_PASSWORD) CHECKPOINT(16,"Keymgr: Edit - Saving password cred");
if (stCredential.Type == CRED_TYPE_DOMAIN_CERTIFICATE) CHECKPOINT(17,"Keymgr: Edit - Saving certificate cred");
#endif
free(pszNewTarget);
EndDialog(IDOK);
} // C_AddKeyDlg::OnOK
/**********************************************************************
**********************************************************************/
void C_AddKeyDlg::OnChangePassword()
{
CHECKPOINT(10,"Keymgr: Edit - Changing password on the domain for the cred");
C_ChangePasswordDlg CPdlg(m_hDlg, g_hInstance, IDD_CHANGEPASSWORD, NULL);
CPdlg.m_szDomain[0] = 0;
CPdlg.m_szUsername[0] = 0;
CPdlg.DoModal((LPARAM)&CPdlg);
}
/**********************************************************************
**********************************************************************/
void C_AddKeyDlg::AdviseUser(void)
{
DWORD dwErr;
TCHAR szMsg[MAX_STRING_SIZE];
TCHAR szTitle[MAX_STRING_SIZE];
dwErr = GetLastError();
CHECKPOINT(11,"Keymgr: Edit - Add/Edit failed: Show error message box to user");
if (dwErr == ERROR_NO_SUCH_LOGON_SESSION)
{
LoadString ( m_hInst, IDS_NOLOGON, szMsg, MAX_STRING_SIZE );
LoadString ( m_hInst, IDS_APP_NAME, szTitle, MAX_STRING_SIZE );
MessageBox ( m_hDlg, szMsg, szTitle, MB_OK );
// return leaving credential dialog up
return;
}
else if (dwErr == ERROR_BAD_USERNAME)
{
LoadString ( m_hInst, IDS_BADUNAME, szMsg, MAX_STRING_SIZE );
LoadString ( m_hInst, IDS_APP_NAME, szTitle, MAX_STRING_SIZE );
MessageBox ( m_hDlg, szMsg, szTitle, MB_OK );
// return leaving credential dialog up
return;
}
else if (dwErr == ERROR_INVALID_PASSWORD)
{
LoadString ( m_hInst, IDS_BADPASSWORD, szMsg, MAX_STRING_SIZE );
LoadString ( m_hInst, IDS_APP_NAME, szTitle, MAX_STRING_SIZE );
MessageBox ( m_hDlg, szMsg, szTitle, MB_OK );
// return leaving credential dialog up
return;
}
else
{
// ERROR_INVALID_PARAMETER, ERROR_INVALID_FLAGS, etc
LoadString ( m_hInst, IDS_ADDFAILED, szMsg, MAX_STRING_SIZE );
LoadString ( m_hInst, IDS_APP_NAME, szTitle, MAX_STRING_SIZE );
MessageBox ( m_hDlg, szMsg, szTitle, MB_OK );
// return leaving credential dialog up
return;
}
}