www.pudn.com > 44w.rar > AccessEnum.cpp
#define _WIN32_WINNT 0x0400 // WM_MOUSEWHEEL support #include#include #include #include #include #include #include // ASSERT #include // bstr_t support #include #include #include "AccessEnum.h" #include "resource.h" #include "resizer.h" #include "listview.h" #include "Enumeration.h" PSID DomainAdminSid(); bool IsDomainAdmin(); int GetAccountName( TCHAR * buf, const TCHAR * host, PSID sid ); const TCHAR ALL_DOMAINS[] = _T(" "); struct _globals { HINSTANCE hInst; HWND Abort; // 'abort in progress' window bool ShowAllFiles; CShare * ShareList; long ThreadCount; HWND hMainDlg; _bstr_t Exclude; } g; const DWORD CFileEnumeration::READ_MASK = GENERIC_ALL|GENERIC_READ|GENERIC_EXECUTE|READ_CONTROL|FILE_READ_ATTRIBUTES|FILE_READ_DATA|FILE_READ_EA; const DWORD CFileEnumeration::WRITE_MASK = GENERIC_ALL|GENERIC_WRITE|DELETE|WRITE_DAC|WRITE_OWNER|FILE_APPEND_DATA|FILE_WRITE_ATTRIBUTES|FILE_WRITE_DATA|FILE_WRITE_EA; const DWORD CRegEnumeration::READ_MASK = GENERIC_ALL|GENERIC_READ|GENERIC_EXECUTE|READ_CONTROL|KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS|KEY_NOTIFY; const DWORD CRegEnumeration::WRITE_MASK = GENERIC_ALL|GENERIC_WRITE|DELETE|WRITE_DAC|WRITE_OWNER|KEY_SET_VALUE|KEY_CREATE_SUB_KEY|KEY_CREATE_LINK; // Everyone static const SID SID_EVERYONE = { 1, 1, SECURITY_WORLD_SID_AUTHORITY, SECURITY_NULL_RID }; // creator owner static const SID SID_CREATOR_OWNER = { 1, 1, SECURITY_CREATOR_SID_AUTHORITY, SECURITY_CREATOR_OWNER_RID }; static const SID SID_CREATOR_GROUP = { 1, 1, SECURITY_CREATOR_SID_AUTHORITY, SECURITY_CREATOR_GROUP_RID }; static const SID SID_CREATOR_OWNERSERVER = { 1, 1, SECURITY_CREATOR_SID_AUTHORITY, SECURITY_CREATOR_OWNER_SERVER_RID }; static const SID SID_CREATOR_GROUPSERVER = { 1, 1, SECURITY_CREATOR_SID_AUTHORITY, SECURITY_CREATOR_GROUP_SERVER_RID }; // local system static const SID SID_NTAUTHORITY_SYSTEM = { 1, 1, SECURITY_NT_AUTHORITY, SECURITY_LOCAL_SYSTEM_RID }; // alias sids #if 0 static const SID SID_BUILTIN_ADMIN = { 1, 1, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS }; static const SID SID_BUILTIN_POWERUSERS = { 1, 1, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS }; static const SID SID_BUILTIN_GUESTS = { 1, 1, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_GUESTS }; static const SID SID_BUILTIN_USERS = { 1, 1, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_USERS }; #endif static struct LISTVIEW_COLUMN Columns[] = { { TEXT("Path"), 240, DATATYPE_TEXT }, { TEXT("Read"), 120, DATATYPE_TEXT }, { TEXT("Write"), 120, DATATYPE_TEXT }, { TEXT("Deny"), 80, DATATYPE_TEXT }, { NULL, 0, (DATATYPE)-1 } }; // Power Users PSID SidLocalPowerUserAlias() { static PSID sid = NULL; if ( sid == NULL ) { SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY; AllocateAndInitializeSid( &SystemSidAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0, 0, &sid ); } return sid; } // None PSID SidNone() { static PSID sid = NULL; if ( sid == NULL ) { SID_IDENTIFIER_AUTHORITY SystemSidAuthority = SECURITY_NT_AUTHORITY; AllocateAndInitializeSid( &SystemSidAuthority, 5, SECURITY_NT_NON_UNIQUE, 0x56252AE1, 0xAEF28A35, 0x7D8EE907, 0x00000201, 0, 0, 0, &sid ); } return sid; } // Local Administrators PSID SidLocalAdminAlias() { static PSID sid = NULL; if ( sid == NULL ) { SID_IDENTIFIER_AUTHORITY ntauth = SECURITY_NT_AUTHORITY; AllocateAndInitializeSid( &ntauth, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &sid ); } return sid; } const TCHAR * FormattedMessage( DWORD status ) { static TCHAR msg[ 1024 ]; msg[0] = 0; FormatMessage( FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM, NULL, status, 0, msg, sizeof msg/sizeof msg[0], NULL ); if ( msg[0] != 0 ) { TCHAR * ptr = _tcschr( msg, 0 ); while ( ptr > msg && isspace( *--ptr ) ) *ptr = 0; } else { _stprintf( msg, _T("Error %d"), status ); } return msg; } bool ShowFileProperties( HWND hDlg, const TCHAR * Path ) { SHELLEXECUTEINFO shellExecuteInfo = { 0 }; shellExecuteInfo.cbSize = sizeof shellExecuteInfo; shellExecuteInfo.fMask = SEE_MASK_INVOKEIDLIST; shellExecuteInfo.hwnd = hDlg; shellExecuteInfo.lpVerb = _T("properties"); shellExecuteInfo.lpFile = Path; return ShellExecuteEx( &shellExecuteInfo ) != FALSE; } bool ExploreFile( HWND hDlg, const TCHAR * Path ) { if ( _tcsnicmp( Path, _T("HK"), 2 ) == 0 ) { // registry key RegeditJump( hDlg, Path ); return true; } else { // file SHELLEXECUTEINFO shellExecuteInfo = { 0 }; shellExecuteInfo.cbSize = sizeof shellExecuteInfo; shellExecuteInfo.fMask = SEE_MASK_INVOKEIDLIST; shellExecuteInfo.hwnd = hDlg; shellExecuteInfo.lpVerb = _T("explore"); shellExecuteInfo.lpFile = Path; return ShellExecuteEx( &shellExecuteInfo ) != FALSE; } } TCHAR * GetTextualSid( PSID pSid ) { PSID_IDENTIFIER_AUTHORITY psia; DWORD dwSubAuthorities; DWORD dwSidRev=SID_REVISION; DWORD dwCounter; DWORD dwSidSize; // Validate the binary SID. if ( ! IsValidSid( pSid ) ) return NULL; // Get the identifier authority value from the SID. psia = GetSidIdentifierAuthority( pSid ); // Get the number of subauthorities in the SID. dwSubAuthorities = *GetSidSubAuthorityCount(pSid); // Compute the buffer length. // S-SID_REVISION- + IdentifierAuthority- + subauthorities- + NULL dwSidSize = (15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(TCHAR); // Check input buffer length. // If too small, indicate the proper size and set last error. TCHAR * TextualSid = new TCHAR[ dwSidSize ]; // Add 'S' prefix and revision number to the string. dwSidSize = wsprintf( TextualSid, TEXT("S-%lu-"), dwSidRev ); // Add SID identifier authority to the string. if ( (psia->Value[0] != 0) || (psia->Value[1] != 0) ) { dwSidSize += wsprintf( TextualSid + dwSidSize, TEXT("0x%02hx%02hx%02hx%02hx%02hx%02hx"), (USHORT)psia->Value[0], (USHORT)psia->Value[1], (USHORT)psia->Value[2], (USHORT)psia->Value[3], (USHORT)psia->Value[4], (USHORT)psia->Value[5]); } else { dwSidSize += wsprintf( TextualSid + dwSidSize, TEXT("%lu"), (ULONG)(psia->Value[5] ) + (ULONG)(psia->Value[4] << 8) + (ULONG)(psia->Value[3] << 16) + (ULONG)(psia->Value[2] << 24) ); } // Add SID subauthorities to the string. // for ( dwCounter = 0; dwCounter < dwSubAuthorities; dwCounter++ ) { dwSidSize += wsprintf( TextualSid + dwSidSize, TEXT("-%lu"), *GetSidSubAuthority(pSid, dwCounter) ); } return TextualSid; } struct ACCOUNT { PSID Sid; const TCHAR * Name; const GROUP_USERS_INFO_0 * GroupNetList; DWORD GroupNetCnt; const LOCALGROUP_USERS_INFO_0 * GroupLocalList; DWORD GroupLocalCnt; SID_NAME_USE Use; }; #define UNDEFINED_ACCOUNT ((ACCOUNT *)-1) const ACCOUNT * LookupSid( PSID pSid, const TCHAR * host ) { static ACCOUNT ** AccountList = NULL; static DWORD AccountCnt = 0; static DWORD AccountMax = 0; for ( DWORD idx = 0; idx < AccountCnt; ++idx ) if ( EqualSid( pSid, AccountList[idx]->Sid ) ) return AccountList[idx]; ACCOUNT * act = new ACCOUNT; // get copy of sid DWORD sidlen = GetLengthSid( pSid ); act->Sid = new BYTE[ sidlen ]; memcpy( act->Sid, pSid, sidlen ); // Get account name for sid. TCHAR domainName[MAX_PATH+1+2] = _T("\\\\"); TCHAR userName[MAX_PATH+1]; DWORD userLength = MAX_PATH; DWORD domainLength = MAX_PATH; TCHAR fullName[ 2 * MAX_PATH ]; if ( LookupAccountSid( host, pSid, userName, &userLength, domainName+2, &domainLength, &act->Use ) ) { // found account on remote system switch ( act->Use ) { case SidTypeAlias: _stprintf( fullName, _T("%s"), userName ); break; case SidTypeUser: _stprintf( fullName, _T("%s\\%s"), domainName+2, userName ); break; case SidTypeDeletedAccount: _stprintf( fullName, _T("%s\\%s(Deleted)"), domainName+2, userName ); break; default: _ASSERT(false); // fall through case SidTypeGroup: case SidTypeWellKnownGroup: if ( domainName[2] ) _stprintf( fullName, _T("%s\\%s"), domainName+2, userName ); else _stprintf( fullName, _T("%s"), userName ); break; } act->Name = _tcsdup( fullName ); } else if ( host && LookupAccountSid( NULL, pSid, userName, &userLength, domainName+2, &domainLength, &act->Use ) ) { _ASSERT(false); // found account on local system switch ( act->Use ) { case SidTypeAlias: _stprintf( fullName, _T("%s"), userName ); break; case SidTypeUser: _stprintf( fullName, _T("%s\\%s"), domainName+2, userName ); break; case SidTypeDeletedAccount: _stprintf( fullName, _T("%s\\%s(Deleted)"), domainName+2, userName ); break; default: _ASSERT(false); // fall through case SidTypeGroup: case SidTypeWellKnownGroup: if ( domainName[2] ) _stprintf( fullName, _T("%s\\%s"), domainName+2, userName ); else _stprintf( fullName, _T("%s"), userName ); break; } act->Name = _tcsdup( fullName ); } else { if ( EqualSid( pSid, SidLocalPowerUserAlias() ) ) { _tcscpy( fullName, _T("Power Users") ); act->Name = _tcsdup( fullName ); } else { // Use plain SID act->Name = GetTextualSid( pSid ); act->Use = SidTypeUnknown; fullName[0] = 0; } } act->GroupNetList = NULL; act->GroupLocalList = NULL; act->GroupNetCnt = 0; act->GroupLocalCnt = 0; if ( act->Use == SidTypeUser ) { NET_API_STATUS status; // see what groups account belongs to DWORD total = 0; status = NetUserGetGroups( domainName, userName, 0, (BYTE **)&act->GroupNetList, MAX_PREFERRED_LENGTH, &act->GroupNetCnt, &total ); _ASSERT( status == 0 || status == ERROR_ACCESS_DENIED ); // ERROR_INVALID_FUNCTION, NERR_InvalidComputer total = 0; TCHAR server[ MAX_PATH ]; if ( host ) { _stprintf( server, _T("\\\\%s"), host ); host = server; } status = NetUserGetLocalGroups( host, fullName, 0, LG_INCLUDE_INDIRECT, (BYTE **)&act->GroupLocalList, MAX_PREFERRED_LENGTH, &act->GroupLocalCnt, &total ); _ASSERT( status == 0 || status == ERROR_ACCESS_DENIED ); // ERROR_INVALID_FUNCTION, NERR_InvalidComputer } // add account to list if ( AccountCnt >= AccountMax ) { AccountMax = AccountMax ? 2*AccountMax : 1024; AccountList = (ACCOUNT **)realloc( AccountList, AccountMax * sizeof AccountList[0] ); } AccountList[ AccountCnt++ ] = act; return act; } struct ACCOUNT_RIGHTS { const ACCOUNT * Account; DWORD AllowMask; DWORD DenyMask; }; inline int CompareAccount( const ACCOUNT * pa, const ACCOUNT * pb ) { if ( pa == pb ) return 0; return _tcsicmp( pa->Name, pb->Name ); } int __cdecl CompareAccountRights( const void * pa, const void * pb ) { return CompareAccount( ((const ACCOUNT_RIGHTS *)pa)->Account, ((const ACCOUNT_RIGHTS *)pb)->Account ); } class CEnumeration; bool GetCannonicalRights( const TCHAR * host, const PSECURITY_DESCRIPTOR sd, const CEnumeration * root, const ACCOUNT * Read[], const ACCOUNT * Write[], const ACCOUNT * Deny[] ) { BOOL present, defaulted; PACL acl = NULL; if ( host && host[0] == 0 ) host = NULL; // Get DACL if ( !IsValidSecurityDescriptor( sd ) || !GetSecurityDescriptorDacl( sd, &present, &acl, &defaulted ) || !present ) { // can't say anything about the rights Read[0] = UNDEFINED_ACCOUNT; Write[0] = UNDEFINED_ACCOUNT; Deny[0] = UNDEFINED_ACCOUNT; Read[1] = NULL; Write[1] = NULL; Deny[1] = NULL; return false; } if ( acl == NULL ) { // NULL dacl grants full access to everyone Read[0] = LookupSid( (PSID)&SID_EVERYONE, host ); Write[0] = Read[0]; Deny[0] = Read[0]; Read[1] = NULL; Write[1] = NULL; Deny[1] = NULL; return true; } // First we'll get a list of all accounts and the rights each has. ACCOUNT_RIGHTS AccountList[ MAX_ACCOUNTS_PER_ACL ]; DWORD AccountCnt = 0; // Iterate over aces and acculate a list of accounts for ( int idx = 0; idx < acl->AceCount; ++idx ) { ACCESS_ALLOWED_ACE * ace; // Get the ace GetAce( acl, idx, (void **)&ace ); if ( ace->Header.AceType != ACCESS_ALLOWED_ACE_TYPE && ace->Header.AceType != ACCESS_DENIED_ACE_TYPE ) { continue; } // Get SID for ace PSID pSid = &ace->SidStart; if ( ! IsValidSid( pSid ) ) continue; // translate CREATOR_OWNER sid to owner sid if ( EqualSid( pSid, (PSID)&SID_CREATOR_OWNER ) ) { PSID pOwner = NULL; BOOL defaulted; if ( ! GetSecurityDescriptorOwner( sd, &pOwner, &defaulted ) ) continue; if ( pOwner == NULL ) continue; // no owner, therefore no permissions to report pSid = pOwner; } else if ( EqualSid( pSid, (PSID)&SID_CREATOR_GROUP ) ) { PSID pOwner = NULL; BOOL defaulted; if ( ! GetSecurityDescriptorGroup( sd, &pOwner, &defaulted ) ) continue; if ( pOwner == NULL ) continue; // no owner, therefore no permissions to report pSid = pOwner; } // Skip LocalSystem account if ( EqualSid( pSid, (PSID)&SID_NTAUTHORITY_SYSTEM ) ) { // who cares? continue; } // Check if SID already is in our list for ( DWORD i = 0; i < AccountCnt; ++i ) if ( EqualSid( pSid, AccountList[i].Account->Sid ) ) break; // Create new list entry if not already present if ( i >= AccountCnt ) { if ( AccountCnt+1 >= MAX_ACCOUNTS_PER_ACL ) { MessageBox( g.hMainDlg, _T("Internal error: Too many accounts in ACL"), APPNAME, MB_OK|MB_ICONSTOP ); return false; } ++AccountCnt; AccountList[i].Account = LookupSid( pSid, host ); AccountList[i].AllowMask = 0; AccountList[i].DenyMask = 0; } #if 0 // Skip None group if ( EqualSid( pSid, SidNone() ) ) { // who cares? continue; } #endif // Merge rights for this ace into existing account rights if ( ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE ) AccountList[i].AllowMask |= ace->Mask; else AccountList[i].DenyMask |= ace->Mask; } // Convert rights for each account to generic rights. This // simplifies the bit arithmetic we do later. for ( DWORD actIdx = 0; actIdx < AccountCnt; ++actIdx ) { DWORD & mask = AccountList[actIdx].AllowMask; mask = (root->AllowRead(mask) ? GENERIC_READ : 0) | (root->AllowWrite(mask) ? GENERIC_WRITE : 0); } #if 1 // Check group membership for each account and // subtract rights granted by group(s) from account rights. for ( actIdx = 0; actIdx < AccountCnt; ++actIdx ) { for ( DWORD other = 0; other < AccountCnt; ++other ) { // make sure other item is a group, and not us if ( actIdx == other ) continue; if ( AccountList[other].Account->Use != SidTypeGroup && AccountList[other].Account->Use != SidTypeWellKnownGroup && AccountList[other].Account->Use != SidTypeAlias ) continue; // If Everyone is present then always assume membership if ( EqualSid( AccountList[other].Account->Sid, (PSID)&SID_EVERYONE ) ) { // Everyone is a member of Everyone AccountList[actIdx].AllowMask &= ~AccountList[other].AllowMask; AccountList[actIdx].DenyMask &= ~AccountList[other].DenyMask; continue; } // check each of our groups to see if we belong to other for ( DWORD actGrp = 0; actGrp < AccountList[actIdx].Account->GroupLocalCnt; ++actGrp ) { if ( _tcsicmp( AccountList[actIdx].Account->GroupLocalList[actGrp].lgrui0_name, AccountList[other].Account->Name ) == 0 ) { // There is another group that we are a member of. // Subtract any rights they grant from our rights. AccountList[actIdx].AllowMask &= ~AccountList[other].AllowMask; AccountList[actIdx].DenyMask &= ~AccountList[other].DenyMask; } } for ( actGrp = 0; actGrp < AccountList[actIdx].Account->GroupNetCnt; ++actGrp ) { if ( _tcsicmp( AccountList[actIdx].Account->GroupNetList[actGrp].grui0_name, AccountList[other].Account->Name ) == 0 ) { // There is another group that we are a member of // Subtract any rights they grant from our rights. AccountList[actIdx].AllowMask &= ~AccountList[other].AllowMask; AccountList[actIdx].DenyMask &= ~AccountList[other].DenyMask; } } } } #endif // sort list of accounts qsort( AccountList, AccountCnt, sizeof AccountList[0], CompareAccountRights ); // Generate lists of the accounts with Read, Write and Deny rights present. DWORD ReadCnt = 0; DWORD WriteCnt = 0; DWORD DenyCnt = 0; for ( actIdx = 0; actIdx < AccountCnt; ++actIdx ) { if ( AccountList[actIdx].AllowMask & GENERIC_READ ) { Read[ReadCnt++] = AccountList[actIdx].Account; } if ( AccountList[actIdx].AllowMask & GENERIC_WRITE ) { Write[WriteCnt++] = AccountList[actIdx].Account; } if ( AccountList[actIdx].DenyMask ) { Deny[DenyCnt++] = AccountList[actIdx].Account; } } // set null terminator Read[ReadCnt] = NULL; Write[WriteCnt] = NULL; Deny[DenyCnt] = NULL; return true; } // Both account lists must be sorted bool AccountListEqual( const ACCOUNT * Account1[], const ACCOUNT * Account2[] ) { if ( Account1[0] == UNDEFINED_ACCOUNT || Account2[0] == UNDEFINED_ACCOUNT ) { // if either is undefined, then the undefined one is the superset return Account2[0] == Account1[0]; } // Compare each account in turn, using the same comparison function used to sort the lists. for ( int idx = 0; Account1[idx] && Account2[idx]; ++idx ) { int diff = CompareAccount( Account1[idx], Account2[idx] ); if ( diff ) return false; } return Account1[idx] == Account2[idx]; } bool AccountListSubset( const ACCOUNT * Sub[], const ACCOUNT * Super[] ) { // if either is undefined, then the undefined one is the superset if ( Sub[0] == UNDEFINED_ACCOUNT ) return Super[0] == UNDEFINED_ACCOUNT; if ( Super[0] == UNDEFINED_ACCOUNT ) return false; // Compare each account in turn, using the same comparison function used to sort the lists. for ( int iSub = 0, iSuper = 0; Sub[iSub] && Super[iSuper];) { int diff = CompareAccount( Sub[iSub], Super[iSuper] ); if ( diff == 0 ) { ++iSub; ++iSuper; } else if ( diff > 0 ) { ++iSuper; } else { return false; } } return Sub[iSub] == NULL; } int AddListviewRow( HWND hListview, const TCHAR * path, const TCHAR * OtherRead, const TCHAR * OtherWrite, const TCHAR * deny ) { CShare * share = new CShare( path, OtherRead, OtherWrite, deny, ',' ); share->InsertInList( &g.ShareList ); // get icon int iImage; if ( _tcsnicmp( path, _T("HK"), 2 ) == 0 ) { // registry key HIMAGELIST hImageList = ListView_GetImageList( hListview, LVSIL_SMALL ); iImage = ImageList_AddIcon( hImageList, LoadIcon( g.hInst, MAKEINTRESOURCE(IDI_FOLDERCLOSED) ) ); } else { // file SHFILEINFO info = { 0 }; SHGetFileInfo( path, 0, &info, sizeof info, SHGFI_ICON|SHGFI_SMALLICON ); HIMAGELIST hImageList = ListView_GetImageList( hListview, LVSIL_SMALL ); iImage = ImageList_AddIcon( hImageList, info.hIcon ); DestroyIcon( info.hIcon ); } // Add to listview LVITEM item; item.mask = LVIF_TEXT | LVIF_IMAGE; item.iItem = 0x7FFFFFFF; item.iSubItem = 0; item.iImage = iImage; item.pszText = (TCHAR *) path; item.iItem = ListView_InsertItem( hListview, &item ); // set param to index, so we can look ourself up during sorting item.mask = LVIF_PARAM; item.lParam = item.iItem; ListView_SetItem( hListview, &item ); item.mask = LVIF_TEXT; item.iSubItem += 1; item.pszText = (TCHAR *) OtherRead; ListView_SetItem( hListview, &item ); item.iSubItem += 1; item.pszText = (TCHAR *) OtherWrite; ListView_SetItem( hListview, &item ); item.iSubItem += 1; item.pszText = (TCHAR *) deny; ListView_SetItem( hListview, &item ); return item.iItem; } //============================================================== // // EnumerateDomains // // Create a list of computer domains accessible to this system // //============================================================== class CWorker { public: void Start() { InterlockedIncrement( &g.ThreadCount ); UpdateStatus(); #if _MT DWORD id; HANDLE hThread = CreateThread( NULL, 0, Work, this, CREATE_SUSPENDED, &id ); SetThreadPriority( hThread, THREAD_PRIORITY_LOWEST ); ResumeThread( hThread ); #else Work(); #endif } virtual ~CWorker() { } protected: void UpdateStatus() { TCHAR * msg = g.ThreadCount ? _T("Searching...") : _T(""); SetWindowText( GetDlgItem( g.hMainDlg, IDC_STATUS ), msg ); } static int ProcessException( int code, const EXCEPTION_POINTERS * ep ) { TCHAR buf[ MAX_PATH ]; _stprintf( buf, _T("An internal error occured: Exception #0x%X"), code ); MessageBox( g.hMainDlg, buf, APPNAME, MB_OK ); EXCEPTION_RECORD * ExceptionRecord = ep->ExceptionRecord; CONTEXT * ContextRecord = ep->ContextRecord; return EXCEPTION_EXECUTE_HANDLER; } static DWORD WINAPI Work( void * This ) { CWorker * obj = (CWorker *)This; __try { obj->Work(); } __except ( ProcessException( GetExceptionCode(), GetExceptionInformation() ) ) { } return 0; } virtual void Work() { if ( InterlockedDecrement( &g.ThreadCount ) == 0 ) { // We're done enumerating PostMessage( g.hMainDlg, WM_APP_ENUM_COMPLETE, 0, 0 ); } UpdateStatus(); delete this; } }; class CTraversal : public CWorker { HWND m_hListview; const bstr_t m_Host; CEnumeration * m_Root; #define MISSING_DACL ((PACL) 0xFFFFFFFF) inline bool EXPLICIT_DACL( PACL d ) { return d != NULL && d != MISSING_DACL; } public: CTraversal( HWND hListview, const TCHAR * Host, CEnumeration * Root ) : m_hListview( hListview ), m_Host( Host ), m_Root( Root ) { } ~CTraversal() { } private: void GetAccountNames( TCHAR * Text, const ACCOUNT * Account[] ) { // Analyze DACL if ( Account[0] == UNDEFINED_ACCOUNT ) { _tcscpy( Text, _T("???") ); } else { // convert acl to text TCHAR * TextStart = Text; for ( int i = 0; Account[i]; ++i ) { Text += _stprintf( Text, _T("%s, "), Account[i]->Name ); } // Trim trailing commas in lists if ( Text == TextStart ) { Text[0] = 0; } else { Text[-2] = 0; } } } void ShowAccounts( const TCHAR * Path, const ACCOUNT * Read[], const ACCOUNT * Write[], const ACCOUNT * Deny[] ) { // Get permissions TCHAR szRead[ MAX_TEXT ]; TCHAR szWrite[ MAX_TEXT ]; TCHAR szDeny[ MAX_TEXT ]; GetAccountNames( szRead, Read ); GetAccountNames( szWrite, Write ); GetAccountNames( szDeny, Deny ); // Add to list view AddListviewRow( m_hListview, Path, szRead, szWrite, szDeny ); } void Enumerate( CEnumeration * Root, const ACCOUNT * ParentRead[], const ACCOUNT * ParentWrite[], const ACCOUNT * ParentDeny[] ) { // If path is a subdirectory of Exclude then skip it if ( !!g.Exclude ) { if ( _tcsnicmp( Root->Path(), g.Exclude, _tcslen(g.Exclude) ) == 0 ) return; else g.Exclude = (TCHAR *) NULL; } #if 0 if ( _tcsicmp( Root->Path(), _T("HKLM\\Software\\Classes\\Installer\\Components") ) == 0 ) __asm int 3; #endif // Show progress SetDlgItemText( GetParent(m_hListview), IDC_PATH, Root->Path() ); #if 0 if ( wcslen( Root->Path() ) > 100 ) Path = (TCHAR *)9999999999; #endif // Get security descriptor PSECURITY_DESCRIPTOR sd = Root->GetSecurity(); // Convert acl to rights list const ACCOUNT * Read[ MAX_ACCOUNTS_PER_ACL ]; const ACCOUNT * Write[ MAX_ACCOUNTS_PER_ACL ]; const ACCOUNT * Deny[ MAX_ACCOUNTS_PER_ACL ]; GetCannonicalRights( m_Host, sd, Root, Read, Write, Deny ); bool show; if ( Root->IsDir() || g.ShowAllFiles ) { // directory permissions must match exactly show = !AccountListEqual( Read, ParentRead ) || !AccountListEqual( Write, ParentWrite ) || !AccountListEqual( Deny, ParentDeny ); } else { // file permissions its okay to be a subset of parent show = !AccountListSubset( Read, ParentRead ) || !AccountListSubset( Write, ParentWrite ) || !AccountListSubset( Deny, ParentDeny ); } if ( show ) { // Display permissions ShowAccounts( Root->Path(), Read, Write, Deny ); } // Recurse if a directory if ( Root->IsDir() ) { DWORD status; CEnumeration * Child = Root->FindNext( &status ); if ( status ) { // indicate error while reading children const TCHAR * msg = FormattedMessage( status ); _bstr_t fullpath = Root->Path() + _T("\\*"); AddListviewRow( m_hListview, fullpath, msg, _T(""), _T("") ); } else { while ( Child ) { if ( g.Abort ) break; // Compute full path and evaluate #if 0 if ( end - Path + _tcslen( info.cFileName ) + 1 >= MAX_UNCPATH ) { MessageBox( NULL, _T("Fatal error: MAX_UNCPATH exceeded"), APPNAME, MB_ICONSTOP ); exit(1); } _tcscpy( end+1, info.cFileName ); #endif #if 0 static TCHAR oldPath[ 2*MAX_UNCPATH ]; _tcscpy( oldPath, Path ); if ( _tcscmp( oldPath, _T("C:\\WINDOWS\\Help\\SBSI\\Training\\Database\\bookmrk.CDX") ) == 0 ) __asm int 3; #endif Enumerate( Child, Read, Write, Deny ); delete Child; Child = Root->FindNext( &status ); } } } delete sd; } void Work() { // Enumerate files in the directory bool isDir = m_Root->IsDir(); // Get permissions const ACCOUNT * Account[2] = { UNDEFINED_ACCOUNT, NULL }; Enumerate( m_Root, Account, Account, Account ); // restore original path SetDlgItemText( GetParent(m_hListview), IDC_PATH, m_Root->Path() ); CWorker::Work(); } // Work }; // CTraversal bool ExportFile( HWND hListView, const TCHAR * path ) { HANDLE hFile = CreateFile( path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if ( hFile == INVALID_HANDLE_VALUE ) return false; LV_ITEM lvi; DWORD nb; // Mark file as unicode #if UNICODE WORD uni = 0xFEFF; WriteFile( hFile, &uni, sizeof uni, &nb, NULL ); #endif // print headers for ( lvi.iSubItem = 0; lvi.iSubItem < sizeof(Columns)/sizeof(Columns[0])-1; ++lvi.iSubItem ) { WriteFile( hFile, _T("\""), sizeof(TCHAR), &nb, NULL ); WriteFile( hFile, Columns[lvi.iSubItem].Title, _tcslen(Columns[lvi.iSubItem].Title)*sizeof(TCHAR), &nb, NULL ); WriteFile( hFile, _T("\"\t"), 2*sizeof(TCHAR), &nb, NULL ); } WriteFile( hFile, _T("\r\n"), 2*sizeof(TCHAR), &nb, NULL ); // Get text int max = ListView_GetItemCount( hListView ); for ( lvi.iItem = 0; lvi.iItem < max; ++lvi.iItem ) { // Get item lvi.mask = TVIF_TEXT; for ( lvi.iSubItem = 0; lvi.iSubItem < sizeof(Columns)/sizeof(Columns[0])-1; ++lvi.iSubItem ) { TCHAR Item[ MAX_TEXT ]; lvi.pszText = Item; lvi.cchTextMax = MAX_TEXT; if ( ! ListView_GetItem( hListView, &lvi ) ) *Item = 0; for ( int i = 0; Item[i]; ++i ) if ( Item[i] == ',' && Item[i+1] == ' ' ) { Item[i] = ' '; Item[i+1] = 0x0A; } WriteFile( hFile, _T("\""), sizeof(TCHAR), &nb, NULL ); WriteFile( hFile, Item, _tcslen(Item)*sizeof(TCHAR), &nb, NULL ); WriteFile( hFile, _T("\"\t"), 2*sizeof(TCHAR), &nb, NULL ); } WriteFile( hFile, _T("\r\n"), 2*sizeof(TCHAR), &nb, NULL ); } CloseHandle( hFile ); return true; } void PrintAllRecurse( CEnumeration * parent ) { PSECURITY_DESCRIPTOR sd = parent->GetSecurity(); delete sd; for (;;) { DWORD status; CEnumeration * child = parent->FindNext( &status ); if ( child == NULL ) break; PrintAllRecurse( child ); delete child; } } void PrintAll() { CFileEnumeration file( _T("C:"), true ); CRegEnumeration reg( _T("SOFTWARE"), true ); PrintAllRecurse( ® ); PrintAllRecurse( &file ); } INT_PTR CALLBACK AbortDialog( HWND hDlg, UINT message, UINT wParam, LONG lParam ) { RECT parentRc, childRc; switch ( message ) { case WM_INITDIALOG: GetWindowRect( GetParent(hDlg), &parentRc ); GetWindowRect( hDlg, &childRc ); parentRc.left = ((parentRc.left + parentRc.right) - (childRc.right - childRc.left)) / 2; parentRc.top = ((parentRc.top + parentRc.bottom) - (childRc.bottom - childRc.top)) / 2; MoveWindow( hDlg, parentRc.left, parentRc.top, childRc.right - childRc.left, childRc.bottom - childRc.top, TRUE ); return TRUE; case WM_CLOSE: EndDialog( hDlg, 0 ); return TRUE; default: break; } return FALSE; } INT_PTR CALLBACK AboutDialog( HWND hDlg, UINT message, UINT wParam, LONG lParam ) { RECT parentRc, childRc; static HWND hLink; static BOOL underline_link; static HFONT hFontNormal = NULL; static HFONT hFontUnderline = NULL; static HCURSOR hHandCursor = NULL; static HCURSOR hRegularCursor; LOGFONT logfont; switch ( message ) { case WM_INITDIALOG: GetWindowRect( GetParent(hDlg), &parentRc ); GetWindowRect( hDlg, &childRc ); parentRc.left += 70; parentRc.top += 60; MoveWindow( hDlg, parentRc.left, parentRc.top, childRc.right - childRc.left, childRc.bottom - childRc.top, TRUE ); underline_link = TRUE; hLink = GetDlgItem( hDlg, IDC_LINK ); // get link fonts hFontNormal = (HFONT) GetStockObject(DEFAULT_GUI_FONT); GetObject( hFontNormal, sizeof logfont, &logfont); logfont.lfUnderline = TRUE; hFontUnderline = CreateFontIndirect( &logfont ); // get hand hHandCursor = LoadCursor( g.hInst, TEXT("HAND") ); hRegularCursor = LoadCursor( NULL, IDC_ARROW ); return TRUE; case WM_CTLCOLORSTATIC: if ( (HWND)lParam == hLink ) { HDC hdc = (HDC)wParam; SetBkMode( hdc, TRANSPARENT ); if ( GetSysColorBrush(26/*COLOR_HOTLIGHT*/) ) SetTextColor( hdc, GetSysColor(26/*COLOR_HOTLIGHT*/) ); else SetTextColor( hdc, RGB(0,0,255) ); SelectObject( hdc, underline_link ? hFontUnderline : hFontNormal ); return (LONG)GetSysColorBrush( COLOR_BTNFACE ); } break; case WM_MOUSEMOVE: { POINT pt = { LOWORD(lParam), HIWORD(lParam) }; HWND hChild = ChildWindowFromPoint( hDlg, pt ); if ( underline_link == (hChild == hLink) ) { underline_link = !underline_link; InvalidateRect( hLink, NULL, FALSE ); } if ( underline_link ) SetCursor( hRegularCursor ); else SetCursor( hHandCursor ); break; } case WM_LBUTTONDOWN: { POINT pt = { LOWORD(lParam), HIWORD(lParam) }; HWND hChild = ChildWindowFromPoint( hDlg, pt ); if ( hChild == hLink ) { ShellExecute( hDlg, TEXT("open"), TEXT("http://www.sysinternals.com"), NULL, NULL, SW_SHOWNORMAL ); } break; } case WM_COMMAND: switch ( wParam ) { case IDOK: case IDCANCEL: EndDialog( hDlg, 0 ); return TRUE; } break; case WM_CLOSE: EndDialog( hDlg, 0 ); return TRUE; default: break; } return FALSE; } INT_PTR CALLBACK FilePermDialog( HWND hDlg, UINT message, UINT wParam, LONG lParam ) { switch ( message ) { case WM_INITDIALOG: CheckDlgButton( hDlg, IDYES, g.ShowAllFiles ? BST_CHECKED : BST_UNCHECKED ); CheckDlgButton( hDlg, IDNO, !g.ShowAllFiles ? BST_CHECKED : BST_UNCHECKED ); return true; case WM_COMMAND: switch ( LOWORD(wParam) ) { case IDOK: g.ShowAllFiles = IsDlgButtonChecked( hDlg, IDYES ) == BST_CHECKED; case IDCANCEL: EndDialog( hDlg, 0 ); break; } break; } return false; } INT_PTR CALLBACK HelpDialog( HWND hDlg, UINT message, UINT wParam, LONG lParam ) { static const TCHAR HelpText[] = _T("AccessEnum displays who has access to the files and folders within a directory. Although every ") _T("file/directory is examined, AccessEnum displays only those with permissions that differ from ") _T("their parent folder, allowing you to quickly determine deviations in your security policy.") _T("\r\n\r\n") _T("AccessEnum abstracts Window's access-control model to just Read, Write and Deny permissions. ") _T("A file is shown as granting Write permission whether it grants just a single write right (such ") _T("as Write Owner) or the full suite of write rights via Full Control. Read and Deny permissions ") _T("are handled similarly.") _T("\r\n\r\n") _T("When AccessEnum compares a file/folder and its parent to determine whether their permissions ") _T("are equivalent, it looks only at whether the same set of accounts are granted Read, Write and ") _T("Deny access respectively. If a file grants just Write Owner access, and its parent just Delete ") _T("access, the two will still be considered equivalent since both allow some form of writing.") _T("\r\n\r\n") _T("AccessEnum condenses the number of accounts displayed as having access to a file/folder by ") _T("hiding accounts with permissions that are duplicated by a group to which the account belongs. ") _T("For example, if a file grants Read access to both user Bob and group Marketing, and Bob is a ") _T("member of the Marketing group, then only Marketing will be shown in the list of accounts having ") _T("Read access.") _T("\r\n\r\n") _T("AccessEnum handles files slightly differently than folders. When comparing the permissions of a ") _T("file to its parent the file is displayed only when its permissions are less strict than the parent ") _T("folder. You can change this behavior using the Options menu."); switch ( message ) { case WM_INITDIALOG: SetDlgItemText( hDlg, IDC_EDIT, HelpText ); return true; case WM_COMMAND: switch ( LOWORD(wParam) ) { case IDOK: case IDCANCEL: EndDialog( hDlg, 0 ); break; } break; } return false; } _bstr_t GetTreePath( HWND hTree, HTREEITEM hItem ) { _bstr_t Path; for (;;) { TVITEM tvi; TCHAR Name[ MAX_UNCPATH ]; tvi.mask = TVIF_TEXT; tvi.hItem = hItem; tvi.pszText = Name; tvi.cchTextMax = MAX_UNCPATH; TreeView_GetItem( hTree, &tvi ); Path = Name + Path; hItem = TreeView_GetParent( hTree, hItem ); if ( hItem == NULL ) return Path; Path = _T("\\") + Path; } } INT_PTR CALLBACK BrowseRegDialog( HWND hDlg, UINT message, UINT wParam, LONG lParam ) { HWND hTree; TVINSERTSTRUCT tvi; int i; NMHDR * nmhdr; HIMAGELIST hImageList; static _bstr_t * ReturnPath; static const TCHAR * Root[] = { _T("HKEY_CLASSES_ROOT"), _T("HKEY_CURRENT_USER"), _T("HKEY_LOCAL_MACHINE"), _T("HKEY_USERS"), _T("HKEY_CURRENT_CONFIG") }; switch ( message ) { case WM_INITDIALOG: ReturnPath = (_bstr_t *) lParam; hTree = GetDlgItem( hDlg, IDC_TREE ); // create images for nodes hImageList = ImageList_Create( 16, 16, ILC_COLOR | ILC_MASK, 4, 4 ); ImageList_AddIcon( hImageList, LoadIcon( g.hInst, MAKEINTRESOURCE(IDI_FOLDERCLOSED) ) ); ImageList_AddIcon( hImageList, LoadIcon( g.hInst, MAKEINTRESOURCE(IDI_FOLDEROPEN) ) ); TreeView_SetImageList( hTree, hImageList, TVSIL_NORMAL ); // add root entries for ( i = 0; i < 5; ++i ) { tvi.hParent = TVI_ROOT; tvi.hInsertAfter = TVI_LAST; tvi.item.mask = TVIF_TEXT | TVIF_CHILDREN | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE; tvi.item.pszText = (TCHAR *) Root[i]; tvi.item.cChildren = I_CHILDRENCALLBACK; tvi.item.iImage = 0; tvi.item.iSelectedImage = 1; tvi.item.lParam = false; // not expanded yet TreeView_InsertItem( hTree, &tvi ); } EnableWindow( GetDlgItem( hDlg, IDOK ), false ); return false; case WM_NOTIFY: nmhdr = (NMHDR *) lParam; if ( nmhdr->code == TVN_SELCHANGED ) { EnableWindow( GetDlgItem( hDlg, IDOK ), true ); } if ( nmhdr->code == TVN_GETDISPINFO ) { NMTVDISPINFO * tvnm = (NMTVDISPINFO *) nmhdr; if ( tvnm->item.mask & TVIF_CHILDREN ) { // Get number of children in key _bstr_t Path = GetTreePath( GetDlgItem( hDlg, IDC_TREE ), tvnm->item.hItem ); HKEY hKey = CRegEnumeration::OpenPath( Path, NULL ); tvnm->item.cChildren = 0; RegQueryInfoKey( hKey, NULL, NULL, NULL, (DWORD *)&tvnm->item.cChildren, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); RegCloseKey( hKey ); } } if ( nmhdr->code == TVN_ITEMEXPANDING ) { NMTREEVIEW * tvnm = (NMTREEVIEW *) nmhdr; if ( tvnm->action == TVE_EXPAND && tvnm->itemNew.lParam == 0 ) { // add children to parent hTree = GetDlgItem( hDlg, IDC_TREE ); _bstr_t Path = GetTreePath( hTree, tvnm->itemNew.hItem ); HKEY hKey = CRegEnumeration::OpenPath( Path, NULL ); TCHAR Name[ MAX_PATH ]; for ( int i = 0; RegEnumKey( hKey, i, Name, MAX_PATH ) == 0; ++i ) { TVINSERTSTRUCT tvi; tvi.hParent = tvnm->itemNew.hItem; tvi.hInsertAfter = TVI_LAST; tvi.item.mask = TVIF_TEXT | TVIF_CHILDREN | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE; tvi.item.pszText = Name; tvi.item.cChildren = I_CHILDRENCALLBACK; tvi.item.iImage = 0; tvi.item.iSelectedImage = 1; tvi.item.lParam = false; // not expanded yet TreeView_InsertItem( hTree, &tvi ); } RegCloseKey( hKey ); // mark parent as expanded TVITEM tvi; tvi.mask = TVIF_CHILDREN | TVIF_PARAM; tvi.hItem = tvnm->itemNew.hItem; tvi.cChildren = i; tvi.lParam = true; // expanded TreeView_SetItem( hTree, &tvi ); } } break; case WM_COMMAND: switch ( LOWORD(wParam) ) { case IDOK: hTree = GetDlgItem( hDlg, IDC_TREE ); *ReturnPath = GetTreePath( hTree, TreeView_GetSelection( hTree ) ); EndDialog( hDlg, 1 ); break; case IDCANCEL: EndDialog( hDlg, 0 ); break; } break; } return false; } _bstr_t GetTreeItemText( HWND hTree, int Item, int SubItem ) { // apparently there is no way to determine the length of the text in a list view TCHAR tmp[ 64 * 1024 ]; LVITEM lvi; lvi.mask = LVIF_TEXT; lvi.iItem = Item; lvi.iSubItem = SubItem; lvi.pszText = tmp; lvi.cchTextMax = sizeof tmp/sizeof tmp[0]; SendMessage( hTree, LVM_GETITEMTEXT, Item, (LPARAM) &lvi ); _bstr_t Text( tmp ); return Text; } //---------------------------------------------------------------------- // // MainDialog // // Main interface for editing output // //---------------------------------------------------------------------- LRESULT CALLBACK MainDialog( HWND hDlg, UINT message, UINT wParam, LONG lParam ) { static CResizer resizer; int idx; OPENFILENAME open; static TCHAR exportPath[ MAX_PATH ]; TCHAR * p; bool ok; DWORD style; static bool Starting = true; static HCURSOR hCursor; switch ( message ) { case WM_INITDIALOG: // set anchor points resizer.OnInitDialog( hDlg ); resizer.SetHorz( GetDlgItem(hDlg,IDC_REFRESH), ANCHOR_LEFT ); resizer.SetHorz( GetDlgItem(hDlg,IDC_EXPORT), ANCHOR_LEFT ); resizer.SetVert( GetDlgItem(hDlg,IDC_LIST), ANCHOR_BOTH ); resizer.SetHorz( GetDlgItem(hDlg,IDC_PATH), ANCHOR_BOTH ); resizer.SetHorz( GetDlgItem(hDlg,IDC_DESCRIPTION), ANCHOR_LEFT ); resizer.SetHorz( GetDlgItem(hDlg,IDC_STATUS), ANCHOR_BOTH ); // clear status text SetWindowText( GetDlgItem(hDlg,IDC_STATUS), _T("") ); // Set cursor for window hCursor = LoadCursor( NULL, IDC_ARROW ); SetClassLong( hDlg, GCL_HCURSOR, (LONG)hCursor ); SetCursor( hCursor ); // Create listview columns InitListViewColumns( GetDlgItem(hDlg,IDC_LIST), Columns, sizeof Columns/sizeof Columns[0] - 1 ); style = GetWindowLong( GetDlgItem(hDlg,IDC_LIST), GWL_STYLE ); style |= LVS_SHOWSELALWAYS; SetWindowLong( GetDlgItem(hDlg,IDC_LIST), GWL_STYLE, style ); ListView_SetExtendedListViewStyleEx( GetDlgItem(hDlg,IDC_LIST), LVS_EX_LABELTIP, LVS_EX_LABELTIP ); #if 0 if ( ! IsDomainAdmin() ) { MessageBox( hDlg, _T("Information may be incomplete because you are not a domain administrator"), APPNAME, MB_OK|MB_ICONWARNING ); } #endif { TCHAR Path[ MAX_PATH ] = _T(""); GetEnvironmentVariable( _T("SYSTEMROOT"), Path, MAX_PATH ); SetDlgItemText( hDlg, IDC_PATH, Path ); } return TRUE; case WM_SETCURSOR: switch ( LOWORD(lParam) ) { case HTTOP: case HTBOTTOM: case HTLEFT: case HTRIGHT: case HTTOPLEFT: case HTTOPRIGHT: case HTBOTTOMLEFT: case HTBOTTOMRIGHT: break; default: SetCursor( hCursor ); return true; } break; case WM_APP_ENUM_COMPLETE: EnableWindow( GetDlgItem( hDlg, IDC_REFRESH ), true ); EnableWindow( GetDlgItem( hDlg, IDC_PATH ), true ); EnableWindow( GetDlgItem( hDlg, IDC_BROWSE_FILE ), true ); EnableWindow( GetDlgItem( hDlg, IDC_BROWSE_REG ), true ); EnableWindow( GetDlgItem( hDlg, IDCANCEL ), false ); EnableWindow( GetDlgItem( hDlg, IDC_EXPORT ), true ); hCursor = LoadCursor( NULL, IDC_ARROW ); SetClassLong( hDlg, GCL_HCURSOR, (LONG)hCursor ); SetCursor( hCursor ); if ( g.Abort ) { SendMessage( g.Abort, WM_CLOSE, 0, 0 ); // MessageBox( hDlg, _T("Scan cancelled by user"), APPNAME, MB_OK|MB_ICONINFORMATION ); } break; case WM_NOTIFY: if ( LOWORD(wParam) == IDC_LIST ) { NMLISTVIEW * nm = (NMLISTVIEW *) lParam; switch( nm->hdr.code ) { case LVN_COLUMNCLICK: // sort column SortListView( nm->hdr.hwndFrom, nm->iSubItem, Columns ); break; case NM_DBLCLK: // double click item, so display device properties idx = ListView_GetSelectionMark( GetDlgItem(hDlg,IDC_LIST) ); if ( idx >= 0 ) { TCHAR path[ MAX_UNCPATH ]; ListView_GetItemText( GetDlgItem(hDlg,IDC_LIST), idx, 0, path, MAX_UNCPATH ); ShellExecute( NULL, _T("explore"), path, NULL, NULL, SW_SHOWNORMAL ); } break; case NM_RCLICK: // Create pop-up menu idx = ListView_GetSelectionMark( GetDlgItem(hDlg,IDC_LIST) ); if ( idx >= 0 ) { TCHAR path[ MAX_UNCPATH ]; ListView_GetItemText( GetDlgItem(hDlg,IDC_LIST), idx, 0, path, MAX_UNCPATH ); idx = _tcsnicmp( path, _T("HK"), 2 ) ? MF_ENABLED : MF_GRAYED; } else { idx = MF_ENABLED; } { HMENU hMenu = LoadMenu( g.hInst, _T("POPUP") ); HMENU hSubMenu = GetSubMenu( hMenu, 0 ); POINT pt; GetCursorPos( &pt ); EnableMenuItem( hSubMenu, IDC_PROPERTIES, MF_BYCOMMAND|idx ); TrackPopupMenu( hSubMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, hDlg, NULL); DestroyMenu( hMenu ); } break; } } break; case WM_COMMAND: // Normal notifications switch ( LOWORD(wParam) ) { case IDC_QUIT: // quit SendMessage( hDlg, WM_CLOSE, 0, 0 ); break; case IDCANCEL: // is an enumeration in progress? if ( ! IsWindowEnabled( GetDlgItem( hDlg, IDC_REFRESH ) ) ) { // have we already cancelled it? if ( g.Abort == NULL ) { g.Abort = CreateDialog( g.hInst, _T("ABORT"), hDlg, AbortDialog ); } } break; case IDC_ABOUT: DialogBox( g.hInst, _T("ABOUT"), hDlg, AboutDialog ); break; case IDC_FILEOPTIONS: DialogBox( g.hInst, _T("FILEPERM"), hDlg, FilePermDialog ); break; case IDC_HELPCONTENTS: DialogBox( g.hInst, _T("HELP"), hDlg, HelpDialog ); break; case IDOK: // convert to IDC_REFRESH return SendMessage( hDlg, WM_COMMAND, MAKEWPARAM(IDC_REFRESH,HIWORD(wParam)), lParam ); case IDC_BROWSE_FILE: { BROWSEINFO bi = { 0 }; bi.hwndOwner = hDlg; bi.ulFlags = BIF_NONEWFOLDERBUTTON | BIF_RETURNONLYFSDIRS ; bi.lpszTitle = _T("Select the folder to enumerate:"); ITEMIDLIST * pidl = SHBrowseForFolder( &bi ); TCHAR Path[ MAX_UNCPATH ]; if ( pidl && SHGetPathFromIDList( pidl, Path ) ) { SetDlgItemText( hDlg, IDC_PATH, Path ); LPMALLOC pMalloc = NULL; SHGetMalloc( &pMalloc ); pMalloc->Free( pidl ); } } break; case IDC_BROWSE_REG: { _bstr_t Path; if ( DialogBoxParam( g.hInst, _T("REGBROWSE"), hDlg, BrowseRegDialog, (LPARAM)&Path ) ) SetDlgItemText( hDlg, IDC_PATH, Path ); } break; case IDC_REFRESH: if ( IsWindowEnabled( GetDlgItem( hDlg, IDC_REFRESH ) ) ) { // Create a list of all file permissions EnableWindow( GetDlgItem( hDlg, IDC_REFRESH ), false ); EnableWindow( GetDlgItem( hDlg, IDC_PATH ), false ); EnableWindow( GetDlgItem( hDlg, IDC_BROWSE_FILE ), false ); EnableWindow( GetDlgItem( hDlg, IDC_BROWSE_REG ), false ); EnableWindow( GetDlgItem( hDlg, IDCANCEL ), true ); EnableWindow( GetDlgItem( hDlg, IDC_EXPORT ), false ); hCursor = LoadCursor( NULL, IDC_APPSTARTING ); SetClassLong( hDlg, GCL_HCURSOR, (LONG)hCursor ); SetCursor( hCursor ); delete g.ShareList; g.ShareList = NULL; g.Abort = NULL; ListView_DeleteAllItems( GetDlgItem(hDlg,IDC_LIST) ); g.Exclude = (TCHAR *)NULL; // get path to enumerate TCHAR Path[ MAX_PATH ]; GetDlgItemText( hDlg, IDC_PATH, Path, MAX_PATH ); // if it is on a network then get name of system it is on TCHAR NetworkPath[ MAX_PATH ] = _T("\0\0\0"); if ( Path[0] == '\\' && Path[1] == '\\' ) { _tcscpy( NetworkPath, Path ); } else if ( Path[1] == ':' ) { // convert drive to unc path, if share TCHAR DevicePath[ 3 ] = { Path[0], ':', 0 }; DWORD nb = MAX_PATH; WNetGetConnection( DevicePath, NetworkPath, &nb ); } if ( NetworkPath[0] ) { // get file server name TCHAR * ptr = _tcschr( NetworkPath+2, '\\' ); if ( ptr ) *ptr = 0; else NetworkPath[0] = 0; } CEnumeration * root = NULL; if ( _tcsnicmp( Path, _T("HK"), 2 ) == 0 ) { // traverse registry root = new CRegEnumeration( Path, true ); } else { // traverse directory root = new CFileEnumeration( Path, true ); } if ( root == NULL ) { MessageBox( hDlg, _T("Path not found"), APPNAME, MB_OK|MB_ICONWARNING ); break; } CTraversal * e = new CTraversal( GetDlgItem(hDlg,IDC_LIST), NetworkPath[0] ? NetworkPath+2 : _T(""), root ); e->Start(); // delete root; // Add path to list of paths in combo box idx = SendMessage( GetDlgItem(hDlg,IDC_PATH), CB_FINDSTRINGEXACT, -1, (LPARAM) Path ); if ( idx != CB_ERR ) SendMessage( GetDlgItem(hDlg,IDC_PATH), CB_DELETESTRING, idx, 0 ); SendMessage( GetDlgItem(hDlg,IDC_PATH), CB_INSERTSTRING, 0, (LPARAM) Path ); } break; case IDC_EXCLUDE: idx = ListView_GetSelectionMark( GetDlgItem(hDlg,IDC_LIST) ); if ( idx >= 0 ) { // make sure enumeration thread has finished with last exclude: while ( !!g.Exclude && !IsWindowEnabled( GetDlgItem( hDlg, IDC_REFRESH ) ) ) { Sleep( 100 ); } HWND hList = GetDlgItem(hDlg,IDC_LIST); _bstr_t Path = GetTreeItemText( hList, idx, 0 ); // copy path to where enumeration thread can see it: g.Exclude = Path; // remove any items with this path LVFINDINFO find; find.flags = LVFI_STRING | LVFI_PARTIAL; find.psz = Path; idx = -1; for (;;) { idx = ListView_FindItem( hList, idx, &find ); if ( idx < 0 ) break; ListView_DeleteItem( hList, idx ); --idx; } } break; case IDC_PROPERTIES: idx = ListView_GetSelectionMark( GetDlgItem(hDlg,IDC_LIST) ); if ( idx >= 0 ) { HWND hList = GetDlgItem(hDlg,IDC_LIST); TCHAR Path[ MAX_UNCPATH ]; ListView_GetItemText( hList, idx, 0, Path, MAX_UNCPATH ); ShowFileProperties( hDlg, Path ); } break; case IDC_EXPLORE: idx = ListView_GetSelectionMark( GetDlgItem(hDlg,IDC_LIST) ); if ( idx >= 0 ) { HWND hList = GetDlgItem(hDlg,IDC_LIST); TCHAR Path[ MAX_UNCPATH ]; ListView_GetItemText( hList, idx, 0, Path, MAX_UNCPATH ); ExploreFile( hDlg, Path ); } break; case IDC_EXPORT: // get export file name memset( &open, 0, sizeof open ); open.lStructSize = sizeof open; open.hwndOwner = hDlg; open.lpstrFilter = TEXT("Unicode Text (*.txt)\0*.txt\0"); open.lpstrFile = exportPath; open.nMaxFile = sizeof exportPath / sizeof(TCHAR); open.Flags = OFN_HIDEREADONLY; open.lpstrTitle = TEXT("Save as"); if ( ! GetSaveFileName( &open ) ) break; p = _tcschr( exportPath, 0 ); p -= 4; if ( p < exportPath || _tcsicmp( p, TEXT(".txt") ) != 0 ) _tcscat( exportPath, TEXT(".txt") ); DeleteFile( exportPath ); ok = ExportFile( GetDlgItem(hDlg,IDC_LIST), exportPath ); if ( ! ok ) MessageBox( hDlg, TEXT("Error exporting settings"), APPNAME, MB_OK|MB_ICONSTOP ); break; case IDC_COMPARE: CreateDialogParam( g.hInst, _T("COMPARE"), hDlg, CompareDialog, (LPARAM)g.ShareList ); break; } break; case WM_GETMINMAXINFO: resizer.OnGetMinMaxInfo( wParam, lParam ); return 0; case WM_SIZE: resizer.OnSize( wParam, lParam ); UpdateWindow( hDlg ); return 0; case WM_NCHITTEST: return resizer.OnNcHitTest( wParam, lParam ); case WM_PAINT: resizer.OnPaint( wParam, lParam ); break; case WM_CLOSE: SendMessage( hDlg, WM_COMMAND, IDCANCEL, 0 ); SaveListViewColumns( GetDlgItem(hDlg,IDC_LIST)); PostQuitMessage( 0 ); break; } return DefWindowProc( hDlg, message, wParam, lParam ); } //---------------------------------------------------------------------- // // WinMain // // Initialize and start application // //---------------------------------------------------------------------- int CALLBACK WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { #if 0 PrintAll(); return 0; #endif // initialize things InitCommonControls(); CoInitializeEx( NULL, COINIT_APARTMENTTHREADED ); g.hInst = hInstance; // register window class WNDCLASSEX wndclass = { 0 }; wndclass.cbSize = sizeof wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = MainDialog; wndclass.hInstance = hInstance; wndclass.cbWndExtra = DLGWINDOWEXTRA; wndclass.hIcon = LoadIcon( hInstance, TEXT("APPICON") ); wndclass.hIconSm = LoadIcon( hInstance, TEXT("APPICON") ); wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ); wndclass.hbrBackground = (HBRUSH) (COLOR_BTNFACE+1); wndclass.lpszClassName = TEXT("ShareEnumClass"); if ( RegisterClassEx( &wndclass ) == 0 ) GetLastError(); g.hMainDlg = CreateDialog( hInstance, TEXT("MAIN"), NULL, (DLGPROC)MainDialog ); if ( g.hMainDlg == NULL ) { GetLastError(); return 1; } // make top window //SetWindowPos( hMainDlg, HWND_TOP, 1, 1, 0, 0, SWP_NOSIZE ); // Make the window visible ShowWindow( g.hMainDlg, nCmdShow ); // Paint window UpdateWindow( g.hMainDlg ); // Keyboard accelerators HACCEL hAccel = LoadAccelerators( hInstance, TEXT("ACCELERATORS") ); // Message loop MSG msg; while ( GetMessage( &msg, NULL, 0, 0 )) { if ( TranslateAccelerator( g.hMainDlg, hAccel, &msg ) ) continue; if ( IsDialogMessage( g.hMainDlg, &msg ) ) continue; // process message TranslateMessage( &msg ); DispatchMessage( &msg ); } return 0; }