1077 lines
22 KiB
C++
1077 lines
22 KiB
C++
/* ----------------------------------------------------------------------
|
|
|
|
Module: ULS.DLL (Service Provider)
|
|
File: spils.cpp
|
|
Content: This file contains the ILS specifics.
|
|
History:
|
|
12/10/96 Chu, Lon-Chan [lonchanc]
|
|
Created.
|
|
|
|
Copyright (c) Microsoft Corporation 1996-1997
|
|
|
|
---------------------------------------------------------------------- */
|
|
|
|
#include "ulsp.h"
|
|
#include "spinc.h"
|
|
|
|
#include "winsock.h"
|
|
#include "ping.h"
|
|
|
|
// Constant string for ISBU's special modify-operation attribute
|
|
//
|
|
const TCHAR c_szModOp[] = { TEXT ('s'), TEXT ('m'), TEXT ('o'), TEXT ('d'),
|
|
TEXT ('o'), TEXT ('p'), TEXT ('\0'),
|
|
TEXT ('0'), TEXT ('\0')}; //TEXT ("smodop\0000");
|
|
|
|
ULONG g_cbUserPrefix = sizeof (c_szModOp);
|
|
TCHAR *g_pszUserPrefix = NULL;
|
|
ULONG g_cbMtgPrefix = sizeof (c_szModOp);
|
|
TCHAR *g_pszMtgPrefix = NULL;
|
|
|
|
|
|
CPing *g_pPing = NULL;
|
|
|
|
|
|
HRESULT
|
|
IlsInitialize ( VOID )
|
|
{
|
|
// Allocate the ping object
|
|
//
|
|
g_pPing = new CPing;
|
|
if (g_pPing == NULL)
|
|
return ILS_E_MEMORY;
|
|
|
|
// Allocate user prefix
|
|
//
|
|
g_pszUserPrefix = (TCHAR *) MemAlloc (g_cbUserPrefix);
|
|
if (g_pszUserPrefix == NULL)
|
|
return ILS_E_MEMORY;
|
|
|
|
// Fill in user prefix string
|
|
//
|
|
TCHAR *psz = g_pszUserPrefix;
|
|
lstrcpy (psz, &c_szModOp[0]);
|
|
psz += lstrlen (psz) + 1;
|
|
lstrcpy (psz, TEXT ("0"));
|
|
|
|
// Allocate mtg prefix
|
|
//
|
|
g_pszMtgPrefix = (TCHAR *) MemAlloc (g_cbMtgPrefix);
|
|
if (g_pszMtgPrefix == NULL)
|
|
{
|
|
MemFree (g_pszUserPrefix);
|
|
g_pszUserPrefix = NULL;
|
|
return ILS_E_MEMORY;
|
|
}
|
|
|
|
// Fill in mtg prefix string
|
|
//
|
|
psz = g_pszMtgPrefix;
|
|
lstrcpy (psz, &c_szModOp[0]);
|
|
psz += lstrlen (psz) + 1;
|
|
lstrcpy (psz, TEXT ("0"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
IlsCleanup ( VOID )
|
|
{
|
|
// Free the ping object
|
|
//
|
|
if (g_pPing != NULL)
|
|
{
|
|
delete g_pPing;
|
|
g_pPing = NULL;
|
|
}
|
|
|
|
// Free user prefix string
|
|
//
|
|
MemFree (g_pszUserPrefix);
|
|
g_pszUserPrefix = NULL;
|
|
|
|
// Free mtg prefix string
|
|
//
|
|
MemFree (g_pszMtgPrefix);
|
|
g_pszMtgPrefix = NULL;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
ULONG
|
|
IlsCalcModifyListSize ( ULONG cAttrs )
|
|
{
|
|
ULONG cbSize;
|
|
|
|
// array itself
|
|
cbSize = (cAttrs + 1) * sizeof (LDAPMod *);
|
|
|
|
// array elements
|
|
cbSize += cAttrs * sizeof (LDAPMod);
|
|
|
|
// single valued attribute requires two pointers
|
|
cbSize += cAttrs * 2 * sizeof (TCHAR *);
|
|
|
|
return cbSize;
|
|
}
|
|
|
|
|
|
LDAPMod *
|
|
IlsGetModifyListMod ( LDAPMod ***pppMod, ULONG cAttrs, LONG AttrIdx )
|
|
{
|
|
return (LDAPMod *) (((BYTE *) *pppMod) +
|
|
(cAttrs + 1) * sizeof (LDAPMod *) +
|
|
AttrIdx * (sizeof (LDAPMod) + 2 * sizeof (TCHAR *)));
|
|
}
|
|
|
|
|
|
VOID
|
|
IlsFillModifyListItem (
|
|
LDAPMod *pMod,
|
|
TCHAR *pszAttrName,
|
|
TCHAR *pszAttrValue )
|
|
{
|
|
MyAssert (pMod != NULL);
|
|
MyAssert (pszAttrName != NULL);
|
|
|
|
// Set attribute name
|
|
//
|
|
pMod->mod_type = pszAttrName;
|
|
|
|
// Set single valued attribute value
|
|
//
|
|
TCHAR **ppsz = (TCHAR **) (pMod + 1);
|
|
pMod->mod_values = ppsz;
|
|
*ppsz++ = (pszAttrValue != NULL) ? pszAttrValue : STR_EMPTY;
|
|
|
|
// Set null string to terminate this array of values
|
|
//
|
|
*ppsz = NULL;
|
|
}
|
|
|
|
|
|
VOID
|
|
IlsFillModifyListForAnyAttrs (
|
|
LDAPMod *apMod[],
|
|
ULONG *puIndex,
|
|
ANY_ATTRS *pAnyAttrs )
|
|
{
|
|
LDAPMod *pMod;
|
|
TCHAR *pszName, *pszValue;
|
|
ULONG i = *puIndex, j;
|
|
|
|
// Put in extended attributes to add
|
|
//
|
|
pszName = pAnyAttrs->pszAttrsToAdd;
|
|
for (j = 0; j < pAnyAttrs->cAttrsToAdd; j++)
|
|
{
|
|
pMod = apMod[i++];
|
|
pMod->mod_op = LDAP_MOD_ADD;
|
|
pszValue = pszName + lstrlen (pszName) + 1;
|
|
IlsFillModifyListItem (pMod, pszName, pszValue);
|
|
pszName = pszValue + lstrlen (pszValue) + 1;
|
|
}
|
|
|
|
// Put in extended attributes to modify
|
|
//
|
|
pszName = pAnyAttrs->pszAttrsToModify;
|
|
for (j = 0; j < pAnyAttrs->cAttrsToModify; j++)
|
|
{
|
|
pMod = apMod[i++];
|
|
pMod->mod_op = LDAP_MOD_REPLACE;
|
|
pszValue = pszName + lstrlen (pszName) + 1;
|
|
IlsFillModifyListItem (pMod, pszName, pszValue);
|
|
pszName = pszValue + lstrlen (pszValue) + 1;
|
|
}
|
|
|
|
// Put in extended attributes to remove
|
|
//
|
|
pszName = pAnyAttrs->pszAttrsToRemove;
|
|
for (j = 0; j < pAnyAttrs->cAttrsToRemove; j++)
|
|
{
|
|
pMod = apMod[i++];
|
|
pMod->mod_op = LDAP_MOD_DELETE;
|
|
IlsFillModifyListItem (pMod, pszName, NULL);
|
|
pszName = pszName + lstrlen (pszName) + 1;
|
|
}
|
|
|
|
// Return the running index
|
|
//
|
|
*puIndex = i;
|
|
}
|
|
|
|
|
|
TCHAR c_szModOp_AddApp[] = TEXT ("0");
|
|
TCHAR c_szModOp_DeleteApp[] = TEXT ("1");
|
|
TCHAR c_szModOp_ModifyUser[] = TEXT ("2");
|
|
TCHAR c_szModOp_ModifyApp[] = TEXT ("3");
|
|
|
|
|
|
VOID
|
|
IlsFixUpModOp ( LDAPMod *pMod, LONG LdapModOp, LONG IsbuModOp )
|
|
{
|
|
MyAssert (pMod != NULL);
|
|
|
|
pMod->mod_op = LdapModOp;
|
|
// pMod->mod_op = LDAP_MOD_ADD; // lonchanc: MUST MUST MUST
|
|
pMod->mod_type = (TCHAR *) &c_szModOp[0];
|
|
pMod->mod_values = (TCHAR **) (pMod + 1);
|
|
|
|
switch (IsbuModOp)
|
|
{
|
|
case ISBU_MODOP_ADD_APP:
|
|
*(pMod->mod_values) = &c_szModOp_AddApp[0];
|
|
break;
|
|
case ISBU_MODOP_DELETE_APP:
|
|
*(pMod->mod_values) = &c_szModOp_DeleteApp[0];
|
|
break;
|
|
case ISBU_MODOP_MODIFY_USER:
|
|
*(pMod->mod_values) = &c_szModOp_ModifyUser[0];
|
|
break;
|
|
case ISBU_MODOP_MODIFY_APP:
|
|
*(pMod->mod_values) = &c_szModOp_ModifyApp[0];
|
|
break;
|
|
default:
|
|
MyAssert (FALSE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
IlsParseRefreshPeriod (
|
|
LDAP *ld,
|
|
LDAPMessage *pLdapMsg,
|
|
const TCHAR *pszTtlAttrName,
|
|
ULONG *puTTL )
|
|
{
|
|
MyAssert (ld != NULL);
|
|
MyAssert (pLdapMsg != NULL);
|
|
MyAssert (pszTtlAttrName != NULL);
|
|
MyAssert (puTTL != NULL);
|
|
|
|
HRESULT hr;
|
|
ULONG uRefreshPeriod;
|
|
ULONG tcRefreshPeriod;
|
|
|
|
// Get the first entry
|
|
//
|
|
LDAPMessage *pEntry = ldap_first_entry (ld, pLdapMsg);
|
|
if (pEntry == NULL)
|
|
{
|
|
MyAssert (FALSE);
|
|
hr = ILS_E_MEMORY;
|
|
goto MyExit;
|
|
}
|
|
|
|
// Get the sTTL attribute
|
|
//
|
|
TCHAR **ppszAttrVal;
|
|
ppszAttrVal = my_ldap_get_values (ld, pEntry, (TCHAR *) pszTtlAttrName);
|
|
if (ppszAttrVal == NULL || *ppszAttrVal == NULL)
|
|
{
|
|
MyAssert (FALSE);
|
|
hr = ILS_E_MEMORY;
|
|
goto MyExit;
|
|
}
|
|
|
|
// Convert string to long
|
|
//
|
|
uRefreshPeriod = ::GetStringLong (*ppszAttrVal);
|
|
|
|
// Reserve two-minute overhead
|
|
//
|
|
if (uRefreshPeriod > ILS_DEF_REFRESH_MARGIN_MINUTE)
|
|
uRefreshPeriod -= ILS_DEF_REFRESH_MARGIN_MINUTE;
|
|
|
|
// Make sure we have a safe, reasonable refresh period at least
|
|
//
|
|
if (uRefreshPeriod < ILS_DEF_REFRESH_MARGIN_MINUTE)
|
|
uRefreshPeriod = ILS_DEF_REFRESH_MARGIN_MINUTE;
|
|
|
|
// Convert min to ms
|
|
//
|
|
tcRefreshPeriod = Minute2TickCount (uRefreshPeriod);
|
|
|
|
// Free the attribute value
|
|
//
|
|
ldap_value_free (ppszAttrVal);
|
|
|
|
// Update ttl
|
|
//
|
|
*puTTL = uRefreshPeriod; // in unit of minute
|
|
|
|
hr = S_OK;
|
|
|
|
MyExit:
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
MyAssert (FALSE);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
IlsUpdateOneAttr (
|
|
SERVER_INFO *pServerInfo,
|
|
TCHAR *pszDN,
|
|
TCHAR *pszAttrName,
|
|
TCHAR *pszAttrValue,
|
|
LONG nModifyMagic,
|
|
ULONG cPrefix,
|
|
TCHAR *pszPrefix,
|
|
SP_CSession **ppSession, // output
|
|
ULONG *puMsgID ) // output
|
|
{
|
|
MyAssert (pServerInfo != NULL);
|
|
MyAssert (pszDN != NULL);
|
|
MyAssert (pszAttrName != NULL);
|
|
MyAssert (pszAttrValue != NULL);
|
|
MyAssert ( nModifyMagic == ISBU_MODOP_MODIFY_USER ||
|
|
nModifyMagic == ISBU_MODOP_MODIFY_APP);
|
|
MyAssert (ppSession != NULL);
|
|
MyAssert (puMsgID != NULL);
|
|
|
|
// Build modify array for ldap_modify()
|
|
//
|
|
LDAP *ld;
|
|
LDAPMod **ppMod = NULL;
|
|
ULONG cTotal = 0;
|
|
HRESULT hr = IlsFillDefStdAttrsModArr (&ppMod,
|
|
1, // one attribute (i.e. IP addr)
|
|
1, // max? there is only one attr, come on
|
|
&cTotal,
|
|
nModifyMagic,
|
|
cPrefix,
|
|
pszPrefix);
|
|
if (hr != S_OK)
|
|
goto MyExit;
|
|
|
|
// Fill in modify list
|
|
//
|
|
MyAssert (ppMod != NULL);
|
|
LDAPMod *pMod;
|
|
pMod = ppMod[cPrefix];
|
|
MyAssert (pMod != NULL);
|
|
pMod->mod_type = pszAttrName;
|
|
|
|
// Put in ip address
|
|
//
|
|
pMod->mod_values = (TCHAR **) (pMod + 1);
|
|
*(pMod->mod_values) = pszAttrValue;
|
|
|
|
// Get the session object
|
|
//
|
|
hr = g_pSessionContainer->GetSession (ppSession, pServerInfo, FALSE);
|
|
if (hr != S_OK)
|
|
goto MyExit;
|
|
MyAssert (*ppSession != NULL);
|
|
|
|
// Get the ldap session
|
|
//
|
|
ld = (*ppSession)->GetLd ();
|
|
MyAssert (ld != NULL);
|
|
|
|
// Send the data over the wire
|
|
//
|
|
*puMsgID = ldap_modify (ld, pszDN, ppMod);
|
|
if (*puMsgID == -1)
|
|
{
|
|
hr = ::LdapError2Hresult (ld->ld_errno);
|
|
(*ppSession)->Disconnect ();
|
|
goto MyExit;
|
|
}
|
|
|
|
// Success
|
|
//
|
|
hr = S_OK;
|
|
|
|
MyExit:
|
|
|
|
MemFree (ppMod);
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
IlsUpdateIPAddress (
|
|
SERVER_INFO *pServerInfo,
|
|
TCHAR *pszDN,
|
|
TCHAR *pszIPAddrName,
|
|
TCHAR *pszIPAddrValue,
|
|
LONG nModifyMagic,
|
|
ULONG cPrefix,
|
|
TCHAR *pszPrefix )
|
|
{
|
|
SP_CSession *pSession = NULL;
|
|
LDAP *ld;
|
|
ULONG uMsgID;
|
|
|
|
// Update the ip address attribute on the server
|
|
//
|
|
HRESULT hr = IlsUpdateOneAttr ( pServerInfo,
|
|
pszDN,
|
|
pszIPAddrName,
|
|
pszIPAddrValue,
|
|
nModifyMagic,
|
|
cPrefix,
|
|
pszPrefix,
|
|
&pSession,
|
|
&uMsgID);
|
|
if (hr != S_OK)
|
|
return hr;
|
|
|
|
// Get the ldap session
|
|
//
|
|
MyAssert (pSession != NULL);
|
|
ld = pSession->GetLd ();
|
|
MyAssert (ld != NULL);
|
|
|
|
// Let's wait for the result
|
|
//
|
|
LDAP_TIMEVAL TimeVal;
|
|
TimeVal.tv_usec = 0;
|
|
TimeVal.tv_sec = pSession->GetServerTimeoutInSecond ();
|
|
|
|
// We don't care the result.
|
|
// Should it fails, nothing we can do.
|
|
// We can try it again in next keep alive time.
|
|
//
|
|
LDAPMessage *pLdapMsg;
|
|
pLdapMsg = NULL;
|
|
ldap_result (ld, uMsgID, LDAP_MSG_ALL, &TimeVal, &pLdapMsg);
|
|
|
|
// Free message
|
|
//
|
|
if (pLdapMsg != NULL)
|
|
ldap_msgfree (pLdapMsg);
|
|
|
|
|
|
// Free up the session
|
|
//
|
|
if (pSession != NULL)
|
|
pSession->Disconnect ();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
IlsSendRefreshMsg (
|
|
SERVER_INFO *pServerInfo,
|
|
TCHAR *pszBaseDN,
|
|
TCHAR *pszTTL,
|
|
TCHAR *pszRefreshFilter,
|
|
ULONG *puTTL )
|
|
{
|
|
MyAssert (pServerInfo != NULL);
|
|
MyAssert (MyIsGoodString (pszBaseDN));
|
|
MyAssert (MyIsGoodString (pszTTL));
|
|
MyAssert (MyIsGoodString (pszRefreshFilter));
|
|
MyAssert (puTTL != NULL);
|
|
|
|
// Let's check to see if we need to use Ping...
|
|
//
|
|
if (g_pPing != NULL && g_pPing->IsAutodialEnabled ())
|
|
{
|
|
LPTSTR pszServerName = My_strdup(pServerInfo->pszServerName);
|
|
if (NULL == pszServerName)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
LPTSTR pszSeparator = My_strchr(pszServerName, _T(':'));
|
|
if (NULL != pszSeparator)
|
|
{
|
|
*pszSeparator = _T('\0');
|
|
}
|
|
|
|
DWORD dwIPAddr = inet_addr (pszServerName);
|
|
MemFree(pszServerName);
|
|
if (dwIPAddr != INADDR_NONE)
|
|
{
|
|
if (g_pPing->Ping (dwIPAddr, 10 * 1000, 9) == S_FALSE)
|
|
{
|
|
MyDebugMsg ((ZONE_KA, "KA: ping failed, network down\r\n"));
|
|
|
|
// The "ping" operation failed, but other operations failed
|
|
//
|
|
return ILS_E_NETWORK_DOWN;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get the connection object
|
|
//
|
|
SP_CSession *pSession = NULL;
|
|
HRESULT hr = g_pSessionContainer->GetSession (&pSession, pServerInfo, FALSE);
|
|
if (hr != S_OK)
|
|
{
|
|
MyDebugMsg ((ZONE_KA, "KA: network down, hr=0x%lX\r\n", hr));
|
|
|
|
// Report error
|
|
//
|
|
return ILS_E_NETWORK_DOWN;
|
|
}
|
|
MyAssert (pSession != NULL);
|
|
|
|
// Get the ldap session
|
|
//
|
|
LDAP *ld = pSession->GetLd ();
|
|
MyAssert (ld != NULL);
|
|
|
|
// Set attributes to return
|
|
//
|
|
TCHAR *apszAttrNames[2];
|
|
apszAttrNames[0] = pszTTL;
|
|
apszAttrNames[1] = NULL;
|
|
|
|
// Update options in ld
|
|
//
|
|
ld->ld_sizelimit = 0; // no limit in the num of entries to return
|
|
ld->ld_timelimit = 0; // no limit on the time to spend on the search
|
|
ld->ld_deref = LDAP_DEREF_ALWAYS;
|
|
|
|
// Send search query
|
|
//
|
|
MyDebugMsg ((ZONE_KA, "KA: calling ldap_search()...\r\n"));
|
|
ULONG uMsgID = ::ldap_search ( ld,
|
|
pszBaseDN, // base DN
|
|
LDAP_SCOPE_BASE, // scope
|
|
pszRefreshFilter, // filter
|
|
&apszAttrNames[0], // attrs[]
|
|
0); // both type and value
|
|
if (uMsgID == -1)
|
|
{
|
|
MyDebugMsg ((ZONE_KA, "KA: ldap_search() failed\r\n"));
|
|
hr = ::LdapError2Hresult (ld->ld_errno);
|
|
pSession->Disconnect ();
|
|
return hr;
|
|
}
|
|
|
|
// Let's wait for the result
|
|
//
|
|
LDAP_TIMEVAL TimeVal;
|
|
TimeVal.tv_usec = 0;
|
|
TimeVal.tv_sec = pSession->GetServerTimeoutInSecond ();
|
|
|
|
// Wait and get the result back
|
|
//
|
|
LDAPMessage *pLdapMsg = NULL;
|
|
INT ResultType = ::ldap_result (ld, uMsgID, LDAP_MSG_ALL, &TimeVal, &pLdapMsg);
|
|
if (ResultType == LDAP_RES_SEARCH_ENTRY ||
|
|
ResultType == LDAP_RES_SEARCH_RESULT)
|
|
{
|
|
if (pLdapMsg != NULL)
|
|
{
|
|
switch (pLdapMsg->lm_returncode)
|
|
{
|
|
case LDAP_NO_SUCH_OBJECT:
|
|
MyDebugMsg ((ZONE_KA, "KA: no such object!\r\n"));
|
|
|
|
// Report error
|
|
//
|
|
hr = ILS_E_NEED_RELOGON;
|
|
break;
|
|
|
|
case LDAP_SUCCESS:
|
|
// Get the new refresh period
|
|
//
|
|
hr = ::IlsParseRefreshPeriod (ld, pLdapMsg, pszTTL, puTTL);
|
|
break;
|
|
|
|
default:
|
|
MyDebugMsg ((ZONE_KA, "KA: unknown lm_returncode=%ld\r\n", pLdapMsg->lm_returncode));
|
|
MyAssert (FALSE);
|
|
hr = ::LdapError2Hresult (ld->ld_errno);
|
|
break;
|
|
}
|
|
|
|
// Free this message
|
|
//
|
|
ldap_msgfree (pLdapMsg);
|
|
} // if (pLdapMsg != NULL)
|
|
else
|
|
{
|
|
hr = ILS_E_FAIL;
|
|
}
|
|
} // not timeout
|
|
else
|
|
{
|
|
// Timeout
|
|
//
|
|
hr = ILS_E_TIMEOUT;
|
|
}
|
|
|
|
// Free up the session
|
|
//
|
|
pSession->Disconnect ();
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
IlsFillDefStdAttrsModArr (
|
|
LDAPMod ***pppMod,
|
|
DWORD dwFlags,
|
|
ULONG cMaxAttrs,
|
|
ULONG *pcTotal, // in/out parameter!!!
|
|
LONG IsbuModOp,
|
|
ULONG cPrefix,
|
|
TCHAR *pszPrefix )
|
|
{
|
|
|
|
MyAssert (pppMod != NULL);
|
|
MyAssert (pcTotal != NULL);
|
|
MyAssert ( (cPrefix == 0 && pszPrefix == NULL) ||
|
|
(cPrefix != 0 && pszPrefix != NULL));
|
|
|
|
// Figure out the num of attributes
|
|
//
|
|
ULONG cAttrs = 0;
|
|
for (ULONG i = 0; i < cMaxAttrs; i++)
|
|
{
|
|
if (dwFlags & 0x01)
|
|
cAttrs++;
|
|
dwFlags >>= 1;
|
|
}
|
|
|
|
// Allocate modify list
|
|
//
|
|
ULONG cTotal = *pcTotal + cPrefix + cAttrs;
|
|
ULONG cbMod = IlsCalcModifyListSize (cTotal);
|
|
*pppMod = (LDAPMod **) MemAlloc (cbMod);
|
|
if (*pppMod == NULL)
|
|
return ILS_E_MEMORY;
|
|
|
|
// Fill in the modify list
|
|
//
|
|
LDAPMod *pMod;
|
|
for (i = 0; i < cTotal; i++)
|
|
{
|
|
pMod = IlsGetModifyListMod (pppMod, cTotal, i);
|
|
(*pppMod)[i] = pMod;
|
|
pMod->mod_values = (TCHAR **) (pMod + 1);
|
|
|
|
if (i < cPrefix)
|
|
{
|
|
pMod->mod_op = LDAP_MOD_REPLACE;
|
|
pMod->mod_type = pszPrefix;
|
|
pszPrefix += lstrlen (pszPrefix) + 1;
|
|
*(pMod->mod_values) = pszPrefix;
|
|
pszPrefix += lstrlen (pszPrefix) + 1;
|
|
}
|
|
}
|
|
|
|
// Fix up the first and the last ones
|
|
//
|
|
IlsFixUpModOp ((*pppMod)[0], LDAP_MOD_REPLACE, IsbuModOp);
|
|
(*pppMod)[cTotal] = NULL;
|
|
|
|
// Return the total number of entries
|
|
//
|
|
*pcTotal = cTotal;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
const TCHAR c_szAnyAttrPrefix[] = TEXT ("ILSA");
|
|
#define SIZE_ANY_ATTR_PREFIX (sizeof (c_szAnyAttrPrefix) / sizeof (TCHAR))
|
|
|
|
|
|
const TCHAR *
|
|
UlsLdap_GetExtAttrNamePrefix ( VOID )
|
|
{
|
|
return &c_szAnyAttrPrefix[0];
|
|
}
|
|
|
|
|
|
const TCHAR *
|
|
IlsSkipAnyAttrNamePrefix ( const TCHAR *pszAttrName )
|
|
{
|
|
MyAssert (pszAttrName != NULL);
|
|
|
|
const TCHAR *psz = IlsIsAnyAttrName (pszAttrName);
|
|
if (psz == NULL)
|
|
{
|
|
MyAssert (FALSE);
|
|
psz = pszAttrName;
|
|
}
|
|
|
|
return psz;
|
|
}
|
|
|
|
|
|
const TCHAR *
|
|
IlsIsAnyAttrName ( const TCHAR *pszAttrName )
|
|
{
|
|
BOOL fRet = FALSE;
|
|
TCHAR *psz = (TCHAR *) pszAttrName;
|
|
|
|
if (pszAttrName != NULL)
|
|
{
|
|
if (lstrlen (pszAttrName) > SIZE_ANY_ATTR_PREFIX)
|
|
{
|
|
TCHAR c = pszAttrName[SIZE_ANY_ATTR_PREFIX-1];
|
|
psz[SIZE_ANY_ATTR_PREFIX-1] = TEXT ('\0');
|
|
fRet = (My_lstrcmpi (pszAttrName, &c_szAnyAttrPrefix[0]) == 0);
|
|
psz[SIZE_ANY_ATTR_PREFIX-1] = c;
|
|
}
|
|
}
|
|
|
|
return (fRet ? &pszAttrName[SIZE_ANY_ATTR_PREFIX-1] : NULL);
|
|
}
|
|
|
|
|
|
TCHAR *
|
|
IlsPrefixNameValueArray (
|
|
BOOL fPair,
|
|
ULONG cAttrs,
|
|
const TCHAR *pszAttrs )
|
|
{
|
|
if (cAttrs == 0 || pszAttrs == NULL)
|
|
{
|
|
MyAssert (FALSE);
|
|
return NULL;
|
|
}
|
|
|
|
// compute the total size required
|
|
ULONG cbTotalSize = 0;
|
|
ULONG cbThisSize;
|
|
TCHAR *pszSrc = (TCHAR *) pszAttrs;
|
|
for (ULONG i = 0; i < cAttrs; i++)
|
|
{
|
|
// get name size
|
|
cbThisSize = lstrlen (pszSrc) + 1;
|
|
pszSrc += lstrlen (pszSrc) + 1;
|
|
|
|
// get value size as needed
|
|
if (fPair)
|
|
{
|
|
cbThisSize += lstrlen (pszSrc) + 1;
|
|
pszSrc += lstrlen (pszSrc) + 1;
|
|
}
|
|
|
|
// adjust the size
|
|
cbThisSize += SIZE_ANY_ATTR_PREFIX;
|
|
cbThisSize *= sizeof (TCHAR);
|
|
|
|
// accumulate it
|
|
cbTotalSize += cbThisSize;
|
|
}
|
|
|
|
// allocate the new buffer
|
|
TCHAR *pszPrefixAttrs = (TCHAR *) MemAlloc (cbTotalSize);
|
|
if (pszPrefixAttrs == NULL)
|
|
return NULL;
|
|
|
|
// copy the strings over to the new buffer
|
|
pszSrc = (TCHAR *) pszAttrs;
|
|
TCHAR *pszDst = pszPrefixAttrs;
|
|
for (i = 0; i < cAttrs; i++)
|
|
{
|
|
// copy prefix
|
|
lstrcpy (pszDst, &c_szAnyAttrPrefix[0]);
|
|
pszDst += lstrlen (pszDst); // no plus 1
|
|
|
|
// copy name
|
|
lstrcpy (pszDst, pszSrc);
|
|
pszDst += lstrlen (pszDst) + 1;
|
|
pszSrc += lstrlen (pszSrc) + 1;
|
|
|
|
// copy value as needed
|
|
if (fPair)
|
|
{
|
|
lstrcpy (pszDst, pszSrc);
|
|
pszDst += lstrlen (pszDst) + 1;
|
|
pszSrc += lstrlen (pszSrc) + 1;
|
|
}
|
|
}
|
|
|
|
return pszPrefixAttrs;
|
|
}
|
|
|
|
|
|
TCHAR *
|
|
IlsBuildDN (
|
|
TCHAR *pszBaseDN,
|
|
TCHAR *pszC,
|
|
TCHAR *pszO,
|
|
TCHAR *pszCN,
|
|
TCHAR *pszObjectClass )
|
|
{
|
|
MyAssert (MyIsGoodString (pszCN));
|
|
MyAssert (MyIsGoodString (pszObjectClass));
|
|
|
|
static TCHAR s_szC[] = TEXT ("c=");
|
|
static TCHAR s_szO[] = TEXT ("o=");
|
|
static TCHAR s_szCN[] = TEXT ("cn=");
|
|
static TCHAR s_szObjectClass[] = TEXT ("objectClass=");
|
|
static TCHAR s_szDelimiter[] = TEXT (", ");
|
|
enum { C_LENGTH = 2 };
|
|
enum { O_LENGTH = 2 };
|
|
enum { CN_LENGTH = 3 };
|
|
enum { OBJECTCLASS_LENGTH = 12 };
|
|
enum { DELIMITER_LENGTH = 2 };
|
|
|
|
ULONG cchDN = 1;
|
|
BOOL fInBaseDN;
|
|
|
|
ASSERT(MyIsGoodString(pszC));
|
|
|
|
cchDN += lstrlen (pszC) + DELIMITER_LENGTH + C_LENGTH;
|
|
|
|
if (MyIsGoodString (pszBaseDN))
|
|
{
|
|
fInBaseDN = TRUE;
|
|
|
|
cchDN += lstrlen (pszBaseDN) + DELIMITER_LENGTH;
|
|
}
|
|
else
|
|
{
|
|
fInBaseDN = FALSE;
|
|
|
|
if (MyIsGoodString (pszO))
|
|
cchDN += lstrlen (pszO) + DELIMITER_LENGTH + O_LENGTH;
|
|
}
|
|
|
|
if (MyIsGoodString (pszCN))
|
|
cchDN += lstrlen (pszCN) + CN_LENGTH;
|
|
|
|
if (MyIsGoodString (pszObjectClass))
|
|
cchDN += lstrlen (pszObjectClass) + DELIMITER_LENGTH + OBJECTCLASS_LENGTH;
|
|
|
|
TCHAR *pszDN = (TCHAR *) MemAlloc (cchDN * sizeof (TCHAR));
|
|
if (pszDN != NULL)
|
|
{
|
|
TCHAR *psz = pszDN;
|
|
psz[0] = TEXT ('\0');
|
|
|
|
if (MyIsGoodString (pszC))
|
|
{
|
|
lstrcpy (psz, &s_szC[0]);
|
|
psz += lstrlen (psz);
|
|
lstrcpy (psz, pszC);
|
|
psz += lstrlen (psz);
|
|
}
|
|
|
|
if (fInBaseDN)
|
|
{
|
|
if (psz != pszDN)
|
|
{
|
|
lstrcpy (psz, &s_szDelimiter[0]);
|
|
psz += lstrlen (psz);
|
|
}
|
|
|
|
lstrcpy (psz, pszBaseDN);
|
|
psz += lstrlen (psz);
|
|
}
|
|
else
|
|
{
|
|
if (MyIsGoodString (pszO))
|
|
{
|
|
if (psz != pszDN)
|
|
{
|
|
lstrcpy (psz, &s_szDelimiter[0]);
|
|
psz += lstrlen (psz);
|
|
}
|
|
|
|
lstrcpy (psz, &s_szO[0]);
|
|
psz += lstrlen (psz);
|
|
lstrcpy (psz, pszO);
|
|
psz += lstrlen (psz);
|
|
}
|
|
}
|
|
|
|
if (MyIsGoodString (pszCN))
|
|
{
|
|
if (psz != pszDN)
|
|
{
|
|
lstrcpy (psz, &s_szDelimiter[0]);
|
|
psz += lstrlen (psz);
|
|
}
|
|
|
|
lstrcpy (psz, &s_szCN[0]);
|
|
psz += lstrlen (psz);
|
|
lstrcpy (psz, pszCN);
|
|
psz += lstrlen (psz);
|
|
}
|
|
|
|
if (MyIsGoodString (pszObjectClass))
|
|
{
|
|
if (psz != pszDN)
|
|
{
|
|
lstrcpy (psz, &s_szDelimiter[0]);
|
|
psz += lstrlen (psz);
|
|
}
|
|
|
|
lstrcpy (psz, &s_szObjectClass[0]);
|
|
psz += lstrlen (psz);
|
|
lstrcpy (psz, pszObjectClass);
|
|
psz += lstrlen (psz);
|
|
}
|
|
|
|
MyAssert (psz == pszDN + cchDN - 1);
|
|
}
|
|
|
|
return pszDN;
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
IlsCreateAnyAttrsPrefix ( ANY_ATTRS *pAnyAttrs )
|
|
{
|
|
if (pAnyAttrs->cAttrsToAdd != 0)
|
|
{
|
|
MyAssert (pAnyAttrs->pszAttrsToAdd != NULL);
|
|
pAnyAttrs->pszAttrsToAdd = IlsPrefixNameValueArray (
|
|
TRUE,
|
|
pAnyAttrs->cAttrsToAdd,
|
|
(const TCHAR *) pAnyAttrs->pszAttrsToAdd);
|
|
if (pAnyAttrs->pszAttrsToAdd == NULL)
|
|
return ILS_E_MEMORY;
|
|
}
|
|
|
|
if (pAnyAttrs->cAttrsToModify != 0)
|
|
{
|
|
MyAssert (pAnyAttrs->pszAttrsToModify != NULL);
|
|
pAnyAttrs->pszAttrsToModify = IlsPrefixNameValueArray (
|
|
TRUE,
|
|
pAnyAttrs->cAttrsToModify,
|
|
(const TCHAR *) pAnyAttrs->pszAttrsToModify);
|
|
if (pAnyAttrs->pszAttrsToModify == NULL)
|
|
{
|
|
MemFree (pAnyAttrs->pszAttrsToAdd);
|
|
pAnyAttrs->pszAttrsToAdd = NULL;
|
|
return ILS_E_MEMORY;
|
|
}
|
|
}
|
|
|
|
if (pAnyAttrs->cAttrsToRemove != 0)
|
|
{
|
|
MyAssert (pAnyAttrs->pszAttrsToRemove != NULL);
|
|
pAnyAttrs->pszAttrsToRemove = IlsPrefixNameValueArray (
|
|
FALSE,
|
|
pAnyAttrs->cAttrsToRemove,
|
|
(const TCHAR *) pAnyAttrs->pszAttrsToRemove);
|
|
if (pAnyAttrs->pszAttrsToRemove == NULL)
|
|
{
|
|
MemFree (pAnyAttrs->pszAttrsToAdd);
|
|
MemFree (pAnyAttrs->pszAttrsToModify);
|
|
pAnyAttrs->pszAttrsToAdd = NULL;
|
|
pAnyAttrs->pszAttrsToModify = NULL;
|
|
return ILS_E_MEMORY;
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
VOID
|
|
IlsReleaseAnyAttrsPrefix ( ANY_ATTRS *pAnyAttrs )
|
|
{
|
|
MemFree (pAnyAttrs->pszAttrsToAdd);
|
|
MemFree (pAnyAttrs->pszAttrsToModify);
|
|
MemFree (pAnyAttrs->pszAttrsToRemove);
|
|
ZeroMemory (pAnyAttrs, sizeof (*pAnyAttrs));
|
|
}
|
|
|
|
|
|
|
|
|
|
TCHAR **my_ldap_get_values ( LDAP *ld, LDAPMessage *pEntry, TCHAR *pszRetAttrName )
|
|
{
|
|
MyAssert (ld != NULL);
|
|
MyAssert (pEntry != NULL);
|
|
MyAssert (pszRetAttrName != NULL);
|
|
|
|
// Examine the first attribute
|
|
//
|
|
struct berelement *pContext = NULL;
|
|
TCHAR *pszAttrName = ldap_first_attribute (ld, pEntry, &pContext);
|
|
if (My_lstrcmpi (pszAttrName, pszRetAttrName) != 0)
|
|
{
|
|
// Examine the other attributes
|
|
//
|
|
while ((pszAttrName = ldap_next_attribute (ld, pEntry, pContext))
|
|
!= NULL)
|
|
{
|
|
if (My_lstrcmpi (pszAttrName, pszRetAttrName) == 0)
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Get the attribute value if needed
|
|
//
|
|
TCHAR **ppszAttrValue = NULL;
|
|
if (pszAttrName != NULL)
|
|
ppszAttrValue = ldap_get_values (ld, pEntry, pszAttrName);
|
|
|
|
return ppszAttrValue;
|
|
}
|
|
|
|
|
|
ULONG my_ldap_count_1st_entry_attributes ( LDAP *ld, LDAPMessage *pLdapMsg )
|
|
{
|
|
MyAssert (ld != NULL);
|
|
MyAssert (pLdapMsg != NULL);
|
|
|
|
ULONG cAttrs = 0;
|
|
|
|
// there should be only an entry
|
|
ULONG cEntries = ldap_count_entries (ld, pLdapMsg);
|
|
if (cEntries > 0)
|
|
{
|
|
// there should be only one entry
|
|
MyAssert (cEntries == 1);
|
|
|
|
TCHAR *pszAttrName;
|
|
|
|
// get this entry
|
|
LDAPMessage *pEntry = ldap_first_entry (ld, pLdapMsg);
|
|
if (pEntry == NULL)
|
|
{
|
|
MyAssert (FALSE);
|
|
return cAttrs;
|
|
}
|
|
|
|
// examine the first attribute
|
|
struct berelement *pContext = NULL;
|
|
pszAttrName = ldap_first_attribute (ld, pEntry, &pContext);
|
|
if (pszAttrName == NULL)
|
|
{
|
|
MyAssert (FALSE);
|
|
return 0;
|
|
}
|
|
cAttrs = 1;
|
|
|
|
TCHAR **ppszAttrVal;
|
|
ppszAttrVal = ldap_get_values (ld, pEntry, pszAttrName);
|
|
if (ppszAttrVal != NULL)
|
|
ldap_value_free (ppszAttrVal);
|
|
|
|
// step through the others
|
|
while ((pszAttrName = ldap_next_attribute (ld, pEntry, pContext)) != NULL)
|
|
{
|
|
cAttrs++;
|
|
|
|
ppszAttrVal = ldap_get_values (ld, pEntry, pszAttrName);
|
|
if (ppszAttrVal != NULL)
|
|
ldap_value_free (ppszAttrVal);
|
|
}
|
|
} // if cEntries > 0
|
|
|
|
return cAttrs;
|
|
}
|
|
|
|
|