|
|
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
ldap.c
Abstract:
This Module implements the utility LDAP functions to read information from the DS schema
Author:
Mac McLain (MacM) 10-02-96
Environment:
User Mode
Revision History:
--*/
#define LDAP_UNICODE 0
#include <delegate.h>
#include <dsgetdc.h>
#include <lmcons.h>
#include <lmapibuf.h>
DWORD LDAPBind ( IN PSTR pszObject, OUT PLDAP *ppLDAP ) /*++
Routine Description:
This routine will bind to the appropriate server for the path
Arguments:
pszObject - Object server to bind to ppLDAP - Where the ldap binding is returned
Return Value:
ERROR_SUCCESS - Success
--*/ { DWORD dwErr = ERROR_SUCCESS;
PDOMAIN_CONTROLLER_INFOA pDCI;
//
// First, get the address of our server. Note that we are binding to
// a machine in a local domain. Normally, a valid DNS domain name
// would be passed in.
//
dwErr = DsGetDcNameA(NULL, NULL, NULL, NULL, DS_IP_REQUIRED, &pDCI);
if(dwErr == ERROR_SUCCESS) { PSTR pszDomain = pDCI[0].DomainControllerAddress; if(*pszDomain == '\\') { pszDomain += 2; } *ppLDAP = ldap_open(pszDomain, LDAP_PORT);
if(*ppLDAP == NULL) { dwErr = ERROR_PATH_NOT_FOUND; } else { //
// Do a bind...
//
dwErr = ldap_bind(*ppLDAP, NULL, NULL, LDAP_AUTH_SSPI); }
NetApiBufferFree(pDCI); }
return(dwErr); }
VOID LDAPUnbind ( IN PLDAP pLDAP ) /*++
Routine Description:
This routine will unbind a previously bound connection
Arguments:
pLDAP - LDAP connection to unbind
Return Value:
void
--*/ { if(pLDAP != NULL) { ldap_unbind(pLDAP); } }
DWORD LDAPReadAttribute ( IN PSTR pszBase, IN PSTR pszAttribute, IN PLDAP pLDAP, OUT PDWORD pcValues, OUT PSTR **pppszValues ) /*++
Routine Description:
This routine will read the specified attribute from the base path
Arguments:
pszBase - Base object path to read from pszAttribute - Attribute to read pcValues - Where the count of read items is returned pppszValues - Where the list of items is returned ppLDAP - LDAP connection handle to use/initialize
Return Value:
ERROR_SUCCESS - Success ERROR_NOT_ENOUGH_MEMORY - A memory allocation failed ERROR_INVALID_PARAMETER - The LDAP connection that was given is not correct
Notes:
The returned values list should be freed via a call to LDAPFreeValues
--*/ { DWORD dwErr = ERROR_SUCCESS; PLDAPMessage pMessage = NULL; PSTR rgAttribs[2];
rgAttribs[0] = NULL;
//
// Ensure that our LDAP connection is valid
//
if(pLDAP == NULL) { dwErr = ERROR_INVALID_PARAMETER; }
//
// Then, do the search...
//
if(dwErr == ERROR_SUCCESS) { rgAttribs[0] = pszAttribute; rgAttribs[1] = NULL;
dwErr = ldap_search_s(pLDAP, pszBase, LDAP_SCOPE_BASE, "(objectClass=*)", rgAttribs, 0, &pMessage); }
if(dwErr == ERROR_SUCCESS) { LDAPMessage *pEntry = NULL; pEntry = ldap_first_entry(pLDAP, pMessage);
if(pEntry == NULL) { dwErr = pLDAP->ld_errno; } else { //
// Now, we'll have to get the values
//
*pppszValues = ldap_get_values(pLDAP, pEntry, rgAttribs[0]); if(*pppszValues == NULL) { dwErr = pLDAP->ld_errno; } else { *pcValues = ldap_count_values(*pppszValues); } }
ldap_msgfree(pMessage); }
return(dwErr); }
VOID LDAPFreeValues ( IN PSTR *ppszValues ) /*++
Routine Description:
Frees the results of an LDAPReadAttribute call
Arguments:
ppwszValues - List to be freed
Return Value:
Void
--*/ { ldap_value_free(ppszValues); }
DWORD LDAPReadSchemaPath ( IN PWSTR pwszOU, OUT PSTR *ppszSchemaPath, OUT PLDAP *ppLDAP ) /*++
Routine Description:
Reads the path to the schema from the DS
Arguments:
pwszOU - OU path for which the schema path needs to be obtained ppszSchemaPath - Where the schema path is returned ppLDAP - LDAP connection to be returned following the successful completion of this routine
Return Value:
ERROR_SUCCESS - Success ERROR_INVALID_PARAMETER - The OU given was not correct ERROR_PATH_NOT_FOUND - The path to the schema could not be found ERROR_NOT_ENOUGH_MEMORY - A memory allocation failed
Notes:
The returned schema path should be free via a call to LocalFree. The LDAP connection should be freed via a call to LDAPUnbind
--*/ { DWORD dwErr = ERROR_SUCCESS; PSTR *ppszValues = NULL; ULONG cValues; PSTR pszOU = NULL; HANDLE hDS = NULL; PDS_NAME_RESULTW pNameRes = NULL;
*ppLDAP = NULL;
//
// Get our OU name into a form we can recognize
//
dwErr = DsBindW(NULL, NULL, &hDS);
if(dwErr == ERROR_SUCCESS) { dwErr = DsCrackNamesW(hDS, DS_NAME_NO_FLAGS, DS_UNKNOWN_NAME, DS_FQDN_1779_NAME, 1, &pwszOU, &pNameRes); }
if(dwErr == ERROR_SUCCESS) { if(pNameRes->cItems == 0 || pNameRes->rItems[0].status != 0) {
dwErr = ERROR_PATH_NOT_FOUND; } else { PSTR pszDomain = NULL;
dwErr = ConvertStringWToStringA(pNameRes->rItems[0].pDomain, &pszDomain); if(dwErr == ERROR_SUCCESS) { //
// Now, we'll bind to the object, and then do the read
//
dwErr = LDAPBind(pszDomain, ppLDAP); LocalFree(pszDomain); } } }
if(hDS != NULL) { DsUnBindW(&hDS); }
if(dwErr == ERROR_SUCCESS) { dwErr = ConvertStringWToStringA(pNameRes->rItems[0].pName, &pszOU); if(dwErr == ERROR_SUCCESS) { dwErr = LDAPReadAttribute(pszOU, "subschemaSubentry", *ppLDAP, &cValues, &ppszValues); } }
if(dwErr == ERROR_SUCCESS) { PSTR pszSchemaPath = NULL; PWSTR pwszSchemaPath = NULL;
pszSchemaPath = strstr(ppszValues[0], "CN=Schema"); if(pszSchemaPath == NULL) { dwErr = ERROR_PATH_NOT_FOUND; } else { //
// Now that we have the proper schema path, we'll return it
//
*ppszSchemaPath = (PSTR)LocalAlloc(LMEM_FIXED, strlen(pszSchemaPath) + 1); if(*ppszSchemaPath == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; } else { strcpy(*ppszSchemaPath, pszSchemaPath); }
}
//
// Don't need the LDAP returned schema path anymore...
//
LDAPFreeValues(ppszValues); }
if(dwErr != ERROR_SUCCESS) { LDAPUnbind(*ppLDAP); *ppLDAP = NULL; }
DsFreeNameResultW(pNameRes);
return(dwErr); }
DWORD LDAPReadSecAndObjIdAsString ( IN PLDAP pLDAP, IN PSTR pszSchemaPath, IN PSTR pszObject, OUT PWSTR *ppwszObjIdAsString, OUT PACTRL_ACCESS *ppAccess ) /*++
Routine Description:
Reads the schemaID off of the specified object type and converts it to a string
Arguments:
pLDAP - LDAP connection to use for attribute read pszSchemaPath - Path to the schema for this object pszObject - LDAP name of the object for which to get the GUID ppwszObjIdAsString - Where the string representation of the GUID is returned
Return Value:
ERROR_SUCCESS - Success ERROR_NOT_ENOUGH_MEMORY - A memory allocation failed
Notes:
The returned string should be freed via a call to RpcFreeString (or as part of the whole list, by FreeIdList)
--*/ { DWORD dwErr = ERROR_SUCCESS;
//
// Ok, first, build the new schema path...
//
PSTR pszBase = NULL; PSTR *ppszValues = NULL; ULONG cValues; DWORD i,j;
pszBase = (PSTR)LocalAlloc(LMEM_FIXED, 3 + // strlen("CN=")
strlen(pszObject) + 1 + // strlen(",")
strlen(pszSchemaPath) + 1); if(pszBase == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; } else { sprintf(pszBase, "CN=%s,%s", pszObject, pszSchemaPath);
//
// We may not always want the object name
//
if(ppwszObjIdAsString != NULL) { dwErr = LDAPReadAttribute(pszBase, "SchemaIdGUID", pLDAP, &cValues, &ppszValues); if(dwErr == ERROR_SUCCESS) { //
// The object we get back is actually a GUID
//
GUID *pGuid = (GUID *)ppszValues[0];
dwErr = UuidToStringW((GUID *)ppszValues[0], ppwszObjIdAsString);
LDAPFreeValues(ppszValues); } }
//
// Then, if that worked, and we need to, we'll read the default
// security
//
if(dwErr == ERROR_SUCCESS && ppAccess != NULL) { dwErr = LDAPReadAttribute(pszBase, "defaultSecurityDescriptor", pLDAP, &cValues, &ppszValues); if(dwErr == ERROR_SUCCESS) { //
// Get it as a security descriptor
//
PSECURITY_DESCRIPTOR pSD = (PSECURITY_DESCRIPTOR)ppszValues[0]; //
// This is an NT5 security API
//
dwErr = ConvertSecurityDescriptorToAccessNamedW (NULL, // There is no object
SE_DS_OBJECT, pSD, ppAccess, NULL, NULL, NULL); LDAPFreeValues(ppszValues); } else { //
// If the attribute wasn't found, try looking up the chain
//
if(dwErr == LDAP_NO_SUCH_ATTRIBUTE) { dwErr = LDAPReadAttribute(pszBase, "subClassOf", pLDAP, &cValues, &ppszValues); //
// Ok, if that worked, we'll call ourselves. Note that
// we don't care about the object name
//
if(dwErr == ERROR_SUCCESS) { dwErr = LDAPReadSecAndObjIdAsString(pLDAP, ppszValues[0], pszSchemaPath, NULL, ppAccess); LDAPFreeValues(ppszValues); } } }
//
// If it worked in that we read the access, we'll go through
// and create all these as inherit entries
//
if(dwErr == ERROR_SUCCESS) { for(i = 0; i < (DWORD)((*ppAccess)->cEntries); i++) { for(j = 0; j < (DWORD)((*ppAccess)->pPropertyAccessList[i]. pAccessEntryList->cEntries); j++) { (*ppAccess)->pPropertyAccessList[i]. pAccessEntryList->pAccessList[j]. lpInheritProperty = *ppwszObjIdAsString; (*ppAccess)->pPropertyAccessList[i]. pAccessEntryList->pAccessList[j].Inheritance |= SUB_CONTAINERS_AND_OBJECTS_INHERIT; } } }
//
// If it failed, don't forget to deallocate our memory
//
if(dwErr != ERROR_SUCCESS && ppwszObjIdAsString != NULL) { RpcStringFree(ppwszObjIdAsString); } }
//
// Free our memory
//
LocalFree(pszBase); } return(dwErr); }
|