#include #include "admcmn.h" // For Net* calls: #include #include #include #include // For CAddr:: calls: #include "cpool.h" #include "abook.h" #include "abtype.h" #include "address.hxx" #include "webhlpr.h" static HRESULT GetDCName ( LPCWSTR wszServer, LPCWSTR wszDomain, LPWSTR * pwszDC ); #if 0 // Taken from smtp/shash.hxx #define TABLE_SIZE 241 static unsigned long ElfHash (const unsigned char * UserName); static HRESULT RecursiveDeleteDirectory ( LPCWSTR wszPath ); #endif // // Exported functions: // HRESULT EnumerateTrustedDomains ( LPCWSTR wszComputer, LPWSTR * pmszDomains ) { _ASSERT ( wszComputer && *wszComputer ); _ASSERT ( pmszDomains ); HRESULT hr = NOERROR; DWORD dwErr = NOERROR; LPWSTR mszDomains = NULL; DWORD cchDomains = 0; DWORD cchLocalDomain = 0; LPWSTR wszPrimaryDomain = NULL; DWORD cchPrimaryDomain = 0; LPWSTR wszCurrent; LPWSTR mszResult = NULL; *pmszDomains = NULL; // // Get a list of the trusted 1st tier domains: // dwErr = NetEnumerateTrustedDomains ( const_cast (wszComputer), &mszDomains ); if ( dwErr != NOERROR ) { // // This didn't work, but we should always add the primary // domain & computer name. Make an empty multisz to signify // no trusted domains. // dwErr = NetApiBufferAllocate ( 2 * sizeof ( WCHAR ), (LPVOID *) &mszDomains ); if ( dwErr != NOERROR ) { BAIL_WITH_FAILURE ( hr, HRESULT_FROM_WIN32 ( dwErr ) ); } mszDomains[0] = NULL; mszDomains[1] = NULL; } _ASSERT ( mszDomains ); if ( mszDomains == NULL ) { BAIL_WITH_FAILURE ( hr, E_UNEXPECTED ); } // // Check for an empty domain list: // if ( mszDomains[0] == NULL && mszDomains[1] == NULL ) { cchDomains = 2; } else { wszCurrent = mszDomains; if ( mszDomains[0] == _T('\0') && mszDomains[1] == _T('\0') ) { } while ( wszCurrent && *wszCurrent ) { DWORD cchCurrent; cchCurrent = lstrlen ( wszCurrent ) + 1; cchDomains += cchCurrent; wszCurrent += cchCurrent; } cchDomains += 1; // Terminating NULL } // // Add the local machine and primary domain: // hr = GetPrimaryDomain ( wszComputer, &wszPrimaryDomain ); BAIL_ON_FAILURE ( hr ); // // PREFIX flagged this as something we need to fix. Easier to // add check than to argue. // if ( !wszPrimaryDomain ) { hr = E_FAIL; goto Exit; } _ASSERT ( wszPrimaryDomain ); cchPrimaryDomain = lstrlen ( wszPrimaryDomain ) + 1; if ( wszPrimaryDomain[0] != _T('\\') || wszPrimaryDomain[1] != _T('\\') || lstrcmpi ( wszPrimaryDomain + 2, wszComputer ) ) { // // The primary domain isn't the local machine, so add the local // machine to the list. // cchLocalDomain = lstrlen ( _T("\\\\") ) + lstrlen ( wszComputer ) + 1; } else { // // The primary domain is the local machine - no need to add it twice. // cchLocalDomain = 0; } mszResult = new WCHAR [ cchDomains + cchLocalDomain + cchPrimaryDomain]; if ( !mszResult ) { BAIL_WITH_FAILURE ( hr, E_OUTOFMEMORY ); } if ( cchLocalDomain ) { wsprintf ( mszResult, _T("\\\\%s"), wszComputer ); StringToUpper ( mszResult ); } wsprintf ( mszResult + cchLocalDomain, _T("%s"), wszPrimaryDomain ); StringToUpper ( mszResult + cchLocalDomain ); // // Copy the rest of the domains in the domain list: // CopyMemory ( mszResult + cchLocalDomain + cchPrimaryDomain, mszDomains, cchDomains * sizeof (WCHAR) ); *pmszDomains = mszResult; Exit: if ( wszPrimaryDomain ) { delete [] wszPrimaryDomain; } if ( mszDomains ) { NetApiBufferFree ( mszDomains ); } return hr; } HRESULT GetPrimaryDomain ( LPCWSTR wszComputer, LPWSTR * pwszPrimaryDomain ) { HRESULT hr = NOERROR; DWORD dwErr = NOERROR; WKSTA_INFO_100 * pwkstaInfo = NULL; LPWSTR wszLangroup = NULL; *pwszPrimaryDomain = NULL; // // Get the workstation info to get the primary domain: // dwErr = NetWkstaGetInfo ( const_cast (wszComputer), 100, (LPBYTE *)&pwkstaInfo ); if ( dwErr != NOERROR ) { BAIL_WITH_FAILURE ( hr, HRESULT_FROM_WIN32 ( dwErr ) ); } _ASSERT ( pwkstaInfo ); wszLangroup = pwkstaInfo->wki100_langroup; if ( wszLangroup && *wszLangroup ) { *pwszPrimaryDomain = new WCHAR [ lstrlen ( wszLangroup ) + 1 ]; if ( !*pwszPrimaryDomain ) { BAIL_WITH_FAILURE(hr, E_OUTOFMEMORY); } lstrcpy ( *pwszPrimaryDomain, wszLangroup ); } else { // // If there is no primary domain, use the computer name prefixed // by backslashes. // *pwszPrimaryDomain = new WCHAR [ 2 + lstrlen ( wszComputer ) + 1 ]; if ( !*pwszPrimaryDomain ) { BAIL_WITH_FAILURE(hr, E_OUTOFMEMORY); } wsprintf ( *pwszPrimaryDomain, _T("\\\\%s"), wszComputer ); } StringToUpper ( *pwszPrimaryDomain ); Exit: if ( pwkstaInfo ) { NetApiBufferFree ( pwkstaInfo ); } return hr; } HRESULT CheckNTAccount ( LPCWSTR wszComputer, LPCWSTR wszUsername, BOOL * pfExists ) { HRESULT hr = NOERROR; DWORD dwErr = NOERROR; BOOL fFound; BYTE sidUser [ MAX_PATH ]; DWORD cbSid = ARRAY_SIZE ( sidUser ); WCHAR wszDomain [ 512 ]; DWORD cchDomain = ARRAY_SIZE ( wszDomain ); SID_NAME_USE nuUser; *pfExists = FALSE; fFound = LookupAccountName ( wszComputer, wszUsername, &sidUser, &cbSid, wszDomain, &cchDomain, &nuUser ); if ( !fFound ) { dwErr = GetLastError ( ); // // The not found error is ERROR_NONE_MAPPED: // if ( dwErr != ERROR_NONE_MAPPED ) { BAIL_WITH_FAILURE ( hr, HRESULT_FROM_WIN32 ( dwErr ) ); } } *pfExists = fFound; Exit: return hr; } HRESULT CreateNTAccount ( LPCWSTR wszComputer, LPCWSTR wszDomain, LPCWSTR wszUsername, LPCWSTR wszPassword // = "" ) { HRESULT hr = NOERROR; DWORD dwErr = NOERROR; DWORD dwParmErr = 0; LPWSTR wszDC = NULL; USER_INFO_3 UserInfo; WCHAR wszNull[] = { 0 }; hr = GetDCName ( wszComputer, wszDomain, &wszDC ); BAIL_ON_FAILURE(hr); ZeroMemory ( &UserInfo, sizeof ( UserInfo ) ); UserInfo.usri3_name = const_cast (wszUsername); UserInfo.usri3_full_name = const_cast (wszUsername); UserInfo.usri3_password = const_cast (wszPassword); // UserInfo.usri3_password_age UserInfo.usri3_priv = USER_PRIV_USER; UserInfo.usri3_home_dir = wszNull; UserInfo.usri3_comment = wszNull; UserInfo.usri3_flags = UF_SCRIPT | UF_NORMAL_ACCOUNT; UserInfo.usri3_script_path = wszNull; UserInfo.usri3_auth_flags = 0; UserInfo.usri3_usr_comment = wszNull; UserInfo.usri3_parms = wszNull; UserInfo.usri3_workstations = wszNull; // UserInfo.usri3_last_logon =; // UserInfo.usri3_last_logoff =; UserInfo.usri3_acct_expires = TIMEQ_FOREVER; UserInfo.usri3_max_storage = USER_MAXSTORAGE_UNLIMITED; // UserInfo.usri3_units_per_week =; // UserInfo.usri3_logon_hours = NULL; // UserInfo.usri3_bad_pw_count =; // UserInfo.usri3_num_logons =; UserInfo.usri3_logon_server = wszNull; UserInfo.usri3_country_code = 0; UserInfo.usri3_code_page = CP_ACP; // UserInfo.usri3_user_id =; UserInfo.usri3_primary_group_id = DOMAIN_GROUP_RID_USERS; UserInfo.usri3_profile = wszNull; UserInfo.usri3_home_dir_drive = wszNull; UserInfo.usri3_password_expired = FALSE; // // Add the user: // dwErr = NetUserAdd ( wszDC, 3, (LPBYTE) &UserInfo, &dwParmErr ); if ( dwErr != NOERROR ) { // TRACE ( _T("Failed to add user: %d, parmerr = %d\r\n"), dwErr, dwParmErr ); BAIL_WITH_FAILURE ( hr, HRESULT_FROM_WIN32 ( dwErr ) ); } #if 0 // // Attempt to add the user to the "USERS" group: // dwErr = NetGroupAddUser ( wszDC, // (LPWSTR) (LPCWSTR) CString ( strDC + L"\\Users" ), (LPWSTR) (LPCWSTR) strUsername ); if ( dwErr != NOERROR ) { TRACE ( _T("Couldn't add user to USERS group: %d\r\n"), dwErr ); } #endif Exit: delete wszDC; return hr; } LPCWSTR StripBackslashesFromComputerName ( LPCWSTR wsz ) { if ( wsz[0] == _T('\\') && wsz[1] == _T('\\') ) { return wsz + 2; } else { return wsz; } } static LPWSTR DuplicateString ( LPCWSTR wsz ) { LPWSTR wszResult; _ASSERT ( wsz ); wszResult = new WCHAR [ lstrlen ( wsz ) + 1 ]; if ( wszResult ) { lstrcpy ( wszResult, wsz ); } return wszResult; } void StringToUpper ( LPWSTR wsz ) { while ( *wsz ) { *wsz = towupper ( *wsz ); wsz++; } } HRESULT GetDCName ( LPCWSTR wszServer, LPCWSTR wszDomain, LPWSTR * pwszDC ) { HRESULT hr = NOERROR; DWORD dwError = NOERROR; LPWSTR wszServerCopy = NULL; LPWSTR wszDomainCopy = NULL; LPCWSTR wszPlainServer = NULL; LPCWSTR wszPlainDomain = NULL; LPWSTR wszDC = NULL; if ( wszServer == NULL ) { wszServer = _T(""); } wszServerCopy = DuplicateString ( wszServer ); wszDomainCopy = DuplicateString ( wszDomain ); if ( !wszServerCopy || !wszDomainCopy ) { BAIL_WITH_FAILURE ( hr, E_OUTOFMEMORY ); } StringToUpper ( wszServerCopy ); StringToUpper ( wszDomainCopy ); wszPlainServer = StripBackslashesFromComputerName ( wszServerCopy ); wszPlainDomain = StripBackslashesFromComputerName ( wszDomainCopy ); if ( ! lstrcmp ( wszPlainServer, wszPlainDomain ) ) { *pwszDC = new WCHAR [ lstrlen (_T("\\\\")) + lstrlen (wszPlainServer) + 1 ]; if ( *pwszDC == NULL ) { BAIL_WITH_FAILURE(hr, E_OUTOFMEMORY); } wsprintf ( *pwszDC, _T("\\\\%s"), wszPlainServer ); goto Exit; } dwError = NetGetDCName ( wszServer, wszDomain, (LPBYTE *) &wszDC ); if ( dwError != NOERROR ) { // // Error, try to get any DC name: // _ASSERT ( wszDC == NULL ); hr = HRESULT_FROM_WIN32 ( dwError ); dwError = NetGetAnyDCName ( wszServer, wszDomain, (LPBYTE *) &wszDC ); if ( dwError != NOERROR ) { goto Exit; } } _ASSERT ( dwError == NOERROR ); _ASSERT ( wszDC[0] == _T('\\') ); _ASSERT ( wszDC[1] == _T('\\') ); *pwszDC = new WCHAR [ lstrlen ( wszDC ) + 1 ]; if ( *pwszDC == NULL ) { BAIL_WITH_FAILURE(hr, E_OUTOFMEMORY); } lstrcpy ( *pwszDC, wszDC ); Exit: delete wszServerCopy; delete wszDomainCopy; if ( wszDC ) { NetApiBufferFree ( wszDC ); } return hr; } BOOL IsValidEmailAddress ( LPCWSTR wszEmailAddress ) { char szBuf[512]; int cchCopied; cchCopied = WideCharToMultiByte ( CP_ACP, 0, wszEmailAddress, -1, szBuf, sizeof (szBuf), NULL, NULL ); if ( cchCopied == 0 ) { return FALSE; } return CAddr::ValidateEmailName( szBuf, FALSE ); } #if 0 HRESULT DeleteMailbox ( LPCWSTR wszServer, LPCWSTR wszAlias, LPCWSTR wszVDirPath, LPCWSTR wszUsername, // OPTIONAL LPCWSTR wszPassword // OPTIONAL ) { TraceFunctEnter ( "DeleteMailbox" ); HRESULT hr = NOERROR; UCHAR szAlias[512]; ULONG lHashValue; DWORD cchMailboxPath; LPWSTR wszMailboxPath; LPCWSTR wszFormat; if ( !wszServer || !wszAlias || !wszVDirPath ) { BAIL_WITH_FAILURE ( hr, E_INVALIDARG ); } if ( !*wszServer || !*wszAlias || !*wszVDirPath ) { BAIL_WITH_FAILURE ( hr, E_INVALIDARG ); } // // Compute the mailbox hash value: // WideCharToMultiByte ( CP_ACP, 0, wszAlias, -1, (char *) szAlias, ARRAY_SIZE ( szAlias ), NULL, NULL ); DebugTrace ( 0, "Deleting mailbox for %s", szAlias ); lHashValue = ElfHash ( szAlias ) % TABLE_SIZE; DebugTrace ( 0, "Hash value = %u", lHashValue ); // // Compute the mailbox directory path, // this is: \\ // cchMailboxPath = lstrlen ( wszVDirPath ) + // 1 + // '\' 20 + // 1 + // '\' lstrlen ( wszAlias ) + // 1; // null terminator wszMailboxPath = new WCHAR [ cchMailboxPath ]; if ( !wszMailboxPath ) { BAIL_WITH_FAILURE ( hr, E_OUTOFMEMORY ); } // Avoid too many '\'s if ( wszVDirPath [ lstrlen ( wszVDirPath ) - 1 ] == _T('\\') ) { wszFormat = _T("%s%u\\%s"); } else { wszFormat = _T("%s\\%u\\%s"); } wsprintf ( wszMailboxPath, wszFormat, wszVDirPath, lHashValue, wszAlias ); RecursiveDeleteDirectory ( wszMailboxPath ); Exit: TraceFunctLeave (); return hr; } //---[ ElfHash() ]------------------------------------------------------------ // // Pulled this function from the stacks project. Calculates the hash value // given a username. The mailbox of a user is stored in a subdirectory of // the form \\. // The username is the lowercase of the name part of the proxy address for // e.g. username@x.com. // // Params: // UserName The username to be hashed. // // Return: (HRESULT) // NOERROR if success, ADSI error code if failed. // //---------------------------------------------------------------------------- unsigned long ElfHash (const unsigned char * UserName) { unsigned long HashValue = 0, g; while (*UserName) { HashValue = (HashValue << 4) + *UserName++; if( g = HashValue & 0xF0000000) HashValue ^= g >> 24; HashValue &= ~g; } return HashValue; } HRESULT RecursiveDeleteDirectory ( LPCWSTR wszPath ) { TraceFunctEnter ( "DeleteDirectory" ); HRESULT hr = NOERROR; DWORD cchOldCurrentDirectory; LPWSTR wszOldCurrentDirectory = NULL; DWORD cchPath = lstrlen ( wszPath ); HANDLE hSearch = INVALID_HANDLE_VALUE; WIN32_FIND_DATA find; BOOL fOk = TRUE; HANDLE hFile; // // Save the current directory: // cchOldCurrentDirectory = GetCurrentDirectory ( 0, NULL ); _ASSERT ( cchOldCurrentDirectory > 0 ); wszOldCurrentDirectory = new WCHAR [ cchOldCurrentDirectory ]; if ( !wszOldCurrentDirectory ) { BAIL_WITH_FAILURE(hr, E_OUTOFMEMORY); } GetCurrentDirectory ( cchOldCurrentDirectory, wszOldCurrentDirectory ); // // Set the current directory to the path: // SetCurrentDirectory ( wszPath ); // // Create the search string: // hSearch = FindFirstFile ( _T("*.*"), &find ); while ( hSearch != INVALID_HANDLE_VALUE && fOk ) { // // Skip the . and .. directories: // if ( lstrcmp ( find.cFileName, _T(".") ) && lstrcmp ( find.cFileName, _T("..") ) ) { if ( find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { hr = RecursiveDeleteDirectory ( find.cFileName ); BAIL_ON_FAILURE(hr); } else { // // Delete this file: // hFile = CreateFile ( find.cFileName, GENERIC_WRITE, FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL ); if ( hFile != INVALID_HANDLE_VALUE ) { CloseHandle ( hFile ); } // Otherwise, press on... } } // Get the next file: fOk = FindNextFile ( hSearch, &find ); } // // Delete the directory: // if ( hSearch != INVALID_HANDLE_VALUE ) { FindClose ( hSearch ); hSearch = INVALID_HANDLE_VALUE; } hFile = CreateFile ( wszPath, GENERIC_WRITE, FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL ); if ( hFile != INVALID_HANDLE_VALUE ) { CloseHandle ( hFile ); } Exit: if ( wszOldCurrentDirectory ) { // // Restore the current directory: // SetCurrentDirectory ( wszOldCurrentDirectory ); delete wszOldCurrentDirectory; } if ( hSearch != INVALID_HANDLE_VALUE ) { FindClose ( hSearch ); hSearch = INVALID_HANDLE_VALUE; } TraceFunctLeave ( ); return hr; } #endif