//+--------------------------------------------------------------------------- // // Microsoft Windows NT Security // Copyright (C) Microsoft Corporation, 1997 - 1998 // // File: ldapsp.cpp // // Contents: LDAP Scheme Provider for Remote Object Retrieval // // History: 23-Jul-97 kirtd Created // //---------------------------------------------------------------------------- #include #pragma hdrstop #include #include //+--------------------------------------------------------------------------- // // Function: LdapCrackUrl // // Synopsis: Crack an LDAP URL into its relevant parts. The result must // be freed using LdapFreeUrlComponents // //---------------------------------------------------------------------------- BOOL LdapCrackUrl ( LPCWSTR pwszUrl, PLDAP_URL_COMPONENTS pLdapUrlComponents ) { BOOL fResult = TRUE; ULONG cbUrl = INTERNET_MAX_PATH_LENGTH; LPWSTR pwszHostInfo = NULL; LPWSTR pwszDN = NULL; LPWSTR pwszAttrList = NULL; LPWSTR pwszScope = NULL; LPWSTR pwszFilter = NULL; LPWSTR pwszToken = NULL; WCHAR pwszBuffer[INTERNET_MAX_PATH_LENGTH+1]; PWCHAR pwsz = pwszBuffer; DWORD len = 0; HRESULT hr; // // Capture the URL and initialize the out parameter // if ( wcsncmp( pwszUrl, LDAP_SCHEME_U, wcslen( LDAP_SCHEME_U ) ) == 0 ) { __try { hr = UrlCanonicalizeW( pwszUrl, pwsz, &cbUrl, ICU_DECODE | URL_WININET_COMPATIBILITY); if(FAILED(hr)) { return( FALSE ); } } __except(EXCEPTION_EXECUTE_HANDLER) { SetLastError( GetExceptionCode() ); return( FALSE ); } } else { len = wcslen(pwszUrl); if (len > INTERNET_MAX_PATH_LENGTH) { pwsz = new WCHAR [len + 1]; if (pwsz == NULL) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return( FALSE ); } } wcscpy(pwsz, pwszUrl); } memset( pLdapUrlComponents, 0, sizeof( LDAP_URL_COMPONENTS ) ); // // Find the host // pwszHostInfo = pwsz + sizeof( "ldap://" ) - sizeof( CHAR ); if ( *pwszHostInfo == L'/' ) { pwszToken = pwszHostInfo + 1; pwszHostInfo = NULL; } else { pwszHostInfo = wcstok( pwszHostInfo, L"/" ); } // // Find the DN // if ( wcsncmp( pwszUrl, LDAP_SCHEME_U, wcslen( LDAP_SCHEME_U ) ) == 0 ) { if ( pwszToken != NULL ) { pwszDN = L""; if ( *pwszToken != L'\0' ) { if ( *pwszToken == L'?' ) { pwszToken += 1; } else { pwszDN = pwszToken; do { pwszToken += 1; } while ( ( *pwszToken != L'\0' ) && ( *pwszToken != L'?' ) ); if ( *pwszToken == L'?' ) { *pwszToken = L'\0'; pwszToken += 1; } } } } else { pwszDN = wcstok( pwszToken, L"?" ); pwszToken = NULL; if ( pwszDN == NULL ) { SetLastError( E_INVALIDARG ); return( FALSE ); } } // // Check for attributes // if ( pwszToken != NULL ) { if ( *pwszToken == L'?' ) { pwszAttrList = L""; pwszToken += 1; } else if ( *pwszToken == L'\0' ) { pwszAttrList = NULL; } else { pwszAttrList = wcstok( pwszToken, L"?" ); pwszToken = NULL; } } else { pwszAttrList = wcstok( NULL, L"?" ); } // // Check for a scope and filter // if ( pwszAttrList != NULL ) { pwszScope = wcstok( pwszToken, L"?" ); if ( pwszScope != NULL ) { pwszFilter = wcstok( NULL, L"?" ); } } if ( pwszScope == NULL ) { pwszScope = L"base"; } if ( pwszFilter == NULL ) { pwszFilter = L"(objectClass=*)"; } } else { if ( pwszToken != NULL ) { pwszDN = pwszToken; } else { // // pwszDN = wcstok( pwszToken, L"\0" ); // pwszDN = pwszHostInfo + wcslen( pwszHostInfo ) + 1; } pwszAttrList = NULL; pwszFilter = L"(objectClass=*)"; pwszScope = L"base"; } // // Now we build up our URL components // fResult = LdapParseCrackedHost( pwszHostInfo, pLdapUrlComponents ); if ( fResult == TRUE ) { fResult = LdapParseCrackedDN( pwszDN, pLdapUrlComponents ); } if ( fResult == TRUE ) { fResult = LdapParseCrackedAttributeList( pwszAttrList, pLdapUrlComponents ); } if ( fResult == TRUE ) { fResult = LdapParseCrackedScopeAndFilter( pwszScope, pwszFilter, pLdapUrlComponents ); } if ( fResult != TRUE ) { LdapFreeUrlComponents( pLdapUrlComponents ); } if (pwsz != pwszBuffer) { delete pwsz; } return( fResult ); } //+--------------------------------------------------------------------------- // // Function: LdapParseCrackedHost // // Synopsis: Parse the cracked host string (pwszHost is modified) // //---------------------------------------------------------------------------- BOOL LdapParseCrackedHost ( LPWSTR pwszHost, PLDAP_URL_COMPONENTS pLdapUrlComponents ) { LPWSTR pwszPort; if ( pwszHost == NULL ) { pLdapUrlComponents->pwszHost = NULL; pLdapUrlComponents->Port = LDAP_PORT; return( TRUE ); } pwszPort = wcschr( pwszHost, L':' ); if ( pwszPort != NULL ) { *pwszPort = L'\0'; pwszPort++; } pLdapUrlComponents->pwszHost = new WCHAR [wcslen( pwszHost ) + 1]; if ( pLdapUrlComponents->pwszHost == NULL ) { SetLastError( E_OUTOFMEMORY ); return( FALSE ); } wcscpy( pLdapUrlComponents->pwszHost, pwszHost ); pLdapUrlComponents->Port = 0; if ( pwszPort != NULL ) { pLdapUrlComponents->Port = _wtol( pwszPort ); } if ( pLdapUrlComponents->Port == 0 ) { pLdapUrlComponents->Port = LDAP_PORT; } return( TRUE ); } //+--------------------------------------------------------------------------- // // Function: LdapParseCrackedDN // // Synopsis: Parse the cracked DN // //---------------------------------------------------------------------------- BOOL LdapParseCrackedDN ( LPWSTR pwszDN, PLDAP_URL_COMPONENTS pLdapUrlComponents ) { pLdapUrlComponents->pwszDN = new WCHAR [wcslen( pwszDN ) + 1]; if ( pLdapUrlComponents->pwszDN == NULL ) { SetLastError( E_OUTOFMEMORY ); return( FALSE ); } wcscpy( pLdapUrlComponents->pwszDN, pwszDN ); return( TRUE ); } //+--------------------------------------------------------------------------- // // Function: LdapParseCrackedAttributeList // // Synopsis: Parse the cracked attribute list // //---------------------------------------------------------------------------- BOOL LdapParseCrackedAttributeList ( LPWSTR pwszAttrList, PLDAP_URL_COMPONENTS pLdapUrlComponents ) { LPWSTR pwsz; LPWSTR pwszAttr; ULONG cAttr = 0; ULONG cCount; if ( ( pwszAttrList == NULL ) || ( wcslen( pwszAttrList ) == 0 ) ) { pLdapUrlComponents->cAttr = 0; pLdapUrlComponents->apwszAttr = NULL; return( TRUE ); } pwsz = new WCHAR [wcslen( pwszAttrList ) + 1]; if ( pwsz == NULL ) { SetLastError( E_OUTOFMEMORY ); return( FALSE ); } wcscpy( pwsz, pwszAttrList ); pwszAttr = wcstok( pwsz, L"," ); while ( pwszAttr != NULL ) { cAttr += 1; pwszAttr = wcstok( NULL, L"," ); } pLdapUrlComponents->apwszAttr = new LPWSTR [cAttr+1]; if ( pLdapUrlComponents->apwszAttr == NULL ) { delete pwsz; SetLastError( E_OUTOFMEMORY ); return( FALSE ); } pLdapUrlComponents->cAttr = cAttr; for ( cCount = 0; cCount < cAttr; cCount++ ) { pLdapUrlComponents->apwszAttr[cCount] = pwsz; pwsz += ( wcslen(pwsz) + 1 ); } pLdapUrlComponents->apwszAttr[cAttr] = NULL; return( TRUE ); } //+--------------------------------------------------------------------------- // // Function: LdapParseCrackedScopeAndFilter // // Synopsis: Parse the cracked scope and filter // //---------------------------------------------------------------------------- BOOL LdapParseCrackedScopeAndFilter ( LPWSTR pwszScope, LPWSTR pwszFilter, PLDAP_URL_COMPONENTS pLdapUrlComponents ) { ULONG Scope; if ( _wcsicmp( pwszScope, L"base" ) == 0 ) { Scope = LDAP_SCOPE_BASE; } else if ( _wcsicmp( pwszScope, L"one" ) == 0 ) { Scope = LDAP_SCOPE_ONELEVEL; } else if ( _wcsicmp( pwszScope, L"sub" ) == 0 ) { Scope = LDAP_SCOPE_SUBTREE; } else { SetLastError( E_INVALIDARG ); return( FALSE ); } pLdapUrlComponents->pwszFilter = new WCHAR [wcslen( pwszFilter ) + 1]; if ( pLdapUrlComponents->pwszFilter == NULL ) { SetLastError( E_OUTOFMEMORY ); return( FALSE ); } wcscpy( pLdapUrlComponents->pwszFilter, pwszFilter ); pLdapUrlComponents->Scope = Scope; return( TRUE ); } //+--------------------------------------------------------------------------- // // Function: LdapFreeUrlComponents // // Synopsis: Frees allocate URL components returned from LdapCrackUrl // //---------------------------------------------------------------------------- VOID LdapFreeUrlComponents ( PLDAP_URL_COMPONENTS pLdapUrlComponents ) { delete pLdapUrlComponents->pwszHost; delete pLdapUrlComponents->pwszDN; if ( pLdapUrlComponents->apwszAttr != NULL ) { delete pLdapUrlComponents->apwszAttr[0]; } delete pLdapUrlComponents->apwszAttr; delete pLdapUrlComponents->pwszFilter; } //+--------------------------------------------------------------------------- // // Function: LdapGetBindings // // Synopsis: allocates and initializes the LDAP session binding // //---------------------------------------------------------------------------- BOOL LdapGetBindings ( LPWSTR pwszHost, ULONG Port, DWORD dwRetrievalFlags, DWORD dwTimeout, LDAP** ppld ) { BOOL fResult = TRUE; LDAP* pld; pld = ldap_initW( pwszHost, Port ); if ( pld != NULL ) { ULONG ldaperr; if ( dwTimeout != 0 ) { ldap_set_option( pld, LDAP_OPT_TIMELIMIT, (void *)&dwTimeout ); } fResult = LdapBindWithOptionalRediscover( pld, pwszHost ); } else { fResult = FALSE; } if ( fResult == TRUE ) { *ppld = pld; } return( fResult ); } //+--------------------------------------------------------------------------- // // Function: LdapFreeBindings // // Synopsis: frees allocated LDAP session binding // //---------------------------------------------------------------------------- VOID LdapFreeBindings ( LDAP* pld ) { if ( pld != NULL ) { ldap_unbind_s( pld ); } } //+--------------------------------------------------------------------------- // // Function: LdapBindWithOptionalRediscover // // Synopsis: bind to the host with optional DC rediscovery if the host is // NULL (which means use default via DsGetDcName) // //---------------------------------------------------------------------------- BOOL LdapBindWithOptionalRediscover (LDAP* pld, LPWSTR pwszHost) { BOOL fResult = TRUE; ULONG ldaperr; ULONG ldapsaveerr; DWORD dwFlags = DS_FORCE_REDISCOVERY; ldaperr = ldap_bind_sW( pld, NULL, NULL, LDAP_AUTH_SSPI ); if ( ( ldaperr != LDAP_SUCCESS ) && ( pwszHost == NULL ) ) { ldapsaveerr = ldaperr; ldaperr = ldap_set_option( pld, LDAP_OPT_GETDSNAME_FLAGS, (LPVOID)&dwFlags ); if ( ldaperr == LDAP_SUCCESS ) { ldaperr = ldap_bind_sW( pld, NULL, NULL, LDAP_AUTH_SSPI ); } else { ldaperr = ldapsaveerr; } } if ( ldaperr != LDAP_SUCCESS ) { fResult = FALSE; SetLastError( LdapMapErrorToWin32(ldaperr) ); } return( fResult ); }