|
|
/* ----------------------------------------------------------------------
Module: ULS.DLL (Service Provider) File: spluser.cpp Content: This file contains the local user object. History: 10/15/96 Chu, Lon-Chan [lonchanc] Created.
Copyright (c) Microsoft Corporation 1996-1997
---------------------------------------------------------------------- */
#include "ulsp.h"
#include "spinc.h"
// Array of constant strings for user object's attribute names
//
const TCHAR *c_apszUserStdAttrNames[COUNT_ENUM_USERATTR] = { TEXT ("cn"), TEXT ("givenname"), TEXT ("surname"), TEXT ("rfc822mailbox"), TEXT ("location"), #ifdef USE_DEFAULT_COUNTRY
TEXT ("aCountryName"), #endif
TEXT ("comment"), TEXT ("sipaddress"), TEXT ("sflags"), TEXT ("c"),
TEXT ("ssecurity"), TEXT ("sttl"),
TEXT ("objectClass"), TEXT ("o"), };
/* ---------- public methods ----------- */
UlsLdap_CLocalUser:: UlsLdap_CLocalUser ( VOID ) { // Reference count
//
m_cRefs = 0;
// User object's signature
//
m_uSignature = USEROBJ_SIGNATURE;
// Clean up attached server info structure
//
ZeroMemory (&m_ServerInfo, sizeof (m_ServerInfo));
// Clean up the scratch buffer for caching pointers to attribute values
//
ZeroMemory (&m_UserInfo, sizeof (m_UserInfo));
// Clean up DN (old and current ones)
m_pszDN = NULL; m_pszOldDN = NULL;
// Clean up the refresh search filter
//
m_pszRefreshFilter = NULL;
// Indicate this user is not registered yet
//
SetRegNone ();
// Reset time to live value
m_uTTL = ULS_DEF_REFRESH_MINUTE; // in unit of minute: no effect on current ils, but to avoid legacy issue later
m_dwIPAddress = 0; }
UlsLdap_CLocalUser:: ~UlsLdap_CLocalUser ( VOID ) { // Invalidate the user object's signature
//
m_uSignature = (ULONG) -1;
// Free server info structure
//
::IlsFreeServerInfo (&m_ServerInfo);
// Free DN (old and current ones)
//
MemFree (m_pszDN); MemFree (m_pszOldDN);
// Free the refresh search filter
//
MemFree (m_pszRefreshFilter); }
ULONG UlsLdap_CLocalUser:: AddRef ( VOID ) { InterlockedIncrement (&m_cRefs); return m_cRefs; }
ULONG UlsLdap_CLocalUser:: Release ( VOID ) { MyAssert (m_cRefs != 0);
if (m_cRefs != 0) { InterlockedDecrement (&m_cRefs); }
ULONG cRefs = m_cRefs; if (cRefs == 0) delete this;
return cRefs; }
HRESULT UlsLdap_CLocalUser:: Register ( ULONG *puRespID, SERVER_INFO *pServerInfo, LDAP_USERINFO *pInfo ) { MyAssert (puRespID != NULL); MyAssert (pInfo != NULL);
MyAssert ( pServerInfo->pszServerName != NULL && pServerInfo->pszServerName[0] != TEXT ('\0')); MyAssert ( pServerInfo->pszBaseDN != NULL && pServerInfo->pszBaseDN[0] != TEXT ('\0'));
// cache the server info
HRESULT hr = ::IlsCopyServerInfo (&m_ServerInfo, pServerInfo); if (hr != S_OK) return hr;
// cache user info
hr = CacheUserInfo (pInfo); if (hr != S_OK) return hr;
// get ip address
m_dwIPAddress = 0; hr = ::GetLocalIPAddress (&m_dwIPAddress); if (hr != S_OK) return hr;
// Create IP address string
//
m_UserInfo.apszStdAttrValues[ENUM_USERATTR_IP_ADDRESS] = &m_UserInfo.szIPAddress[0]; ::GetLongString (m_dwIPAddress, &m_UserInfo.szIPAddress[0]);
// Create client signature string
//
m_UserInfo.apszStdAttrValues[ENUM_USERATTR_CLIENT_SIG] = &m_UserInfo.szClientSig[0]; ::GetLongString (g_dwClientSig, &m_UserInfo.szClientSig[0]);
// Create TTL string
//
m_UserInfo.apszStdAttrValues[ENUM_USERATTR_TTL] = &m_UserInfo.szTTL[0]; ::GetLongString (m_uTTL, &m_UserInfo.szTTL[0]);
// ideally, o= and c= should be read in from registiry
// but for now, we simply hard code it
m_UserInfo.apszStdAttrValues[ENUM_USERATTR_OBJECT_CLASS] = (TCHAR *) &c_szRTPerson[0]; m_UserInfo.apszStdAttrValues[ENUM_USERATTR_O] = (TCHAR *) &c_szDefO[0]; #ifdef USE_DEFAULT_COUNTRY
m_UserInfo.apszStdAttrValues[ENUM_USERATTR_C] = (TCHAR *) &c_szDefC[0]; #endif
// build DN
hr = BuildDN (); if (hr != S_OK) return hr;
// build refreh filter
m_pszRefreshFilter = UserCreateRefreshFilter (m_UserInfo.apszStdAttrValues[ENUM_USERATTR_CN]); if (m_pszRefreshFilter == NULL) return ULS_E_MEMORY;
// build modify array for ldap_add()
LDAPMod **ppMod = NULL; hr = CreateRegisterModArr (&ppMod); if (hr != S_OK) return hr; MyAssert (ppMod != NULL);
// so far, we are done with local preparation
// get the connection object
UlsLdap_CSession *pSession = NULL; hr = g_pSessionContainer->GetSession (&pSession, &m_ServerInfo); if (hr != S_OK) { MemFree (ppMod); return hr; } MyAssert (pSession != NULL);
// get the ldap session
LDAP *ld = pSession->GetLd (); MyAssert (ld != NULL);
// send the data over the wire
ULONG uMsgID = ldap_add (ld, GetDN (), ppMod); MemFree (ppMod); if (uMsgID == -1) { hr = ::LdapError2Hresult (ld->ld_errno); pSession->Disconnect (); return hr; }
// construct a pending info
PENDING_INFO PendingInfo; ::FillDefPendingInfo (&PendingInfo, ld, uMsgID, INVALID_MSG_ID); PendingInfo.uLdapResType = LDAP_RES_ADD; PendingInfo.uNotifyMsg = WM_ULS_REGISTER_USER; PendingInfo.hObject = (HANDLE) this;
// queue it
hr = g_pPendingQueue->EnterRequest (pSession, &PendingInfo); if (hr != S_OK) { ldap_abandon (ld, uMsgID); pSession->Disconnect (); MyAssert (FALSE); }
*puRespID = PendingInfo.uRespID; return hr; }
HRESULT UlsLdap_CLocalUser:: UnRegister ( ULONG *puRespID ) { MyAssert (puRespID != NULL);
// Make sure that there is not refresh scheduled for this object
//
if (g_pRefreshScheduler != NULL) { g_pRefreshScheduler->RemoveUserObject (this); } else { MyAssert (FALSE); }
// Unregister it locally
//
if (! IsRegRemotely ()) { *puRespID = ::GetUniqueNotifyID (); SetRegNone (); PostMessage (g_hWndNotify, WM_ULS_UNREGISTER_USER, *puRespID, S_OK); return S_OK; }
SetRegNone ();
// Get the session object
//
UlsLdap_CSession *pSession = NULL; HRESULT hr = g_pSessionContainer->GetSession (&pSession, &m_ServerInfo); if (hr != S_OK) return hr; MyAssert (pSession != NULL);
// Get the ldap session
//
LDAP *ld = pSession->GetLd (); MyAssert (ld != NULL);
// LONCHANC: notify global user object of this unregister user
// send the data over the wire
ULONG uMsgID = ldap_delete (ld, GetDN ()); if (uMsgID == -1) { hr = ::LdapError2Hresult (ld->ld_errno); pSession->Disconnect (); return hr; }
// construct a pending info
PENDING_INFO PendingInfo; ::FillDefPendingInfo (&PendingInfo, ld, uMsgID, INVALID_MSG_ID); PendingInfo.uLdapResType = LDAP_RES_DELETE; PendingInfo.uNotifyMsg = WM_ULS_UNREGISTER_USER;
// queue it
hr = g_pPendingQueue->EnterRequest (pSession, &PendingInfo); if (hr != S_OK) { ldap_abandon (ld, uMsgID); pSession->Disconnect (); MyAssert (FALSE); }
*puRespID = PendingInfo.uRespID; return hr; }
HRESULT UlsLdap_CLocalUser:: SetStdAttrs ( ULONG *puRespID, LDAP_USERINFO *pInfo ) { MyAssert (puRespID != NULL); MyAssert (pInfo != NULL);
ULONG uMsgID_modify, uMsgID_modrdn; UlsLdap_CSession *pSession; LDAP *ld; HRESULT hr;
// Get the session object
//
hr = g_pSessionContainer->GetSession (&pSession, GetServerInfo ()); if (hr != S_OK) return hr; MyAssert (pSession != NULL);
// Get the ldap session
//
ld = pSession->GetLd (); MyAssert (ld != NULL);
// Change cn?
//
if (pInfo->uOffsetEMailName != 0) { // Cache user info such that cn is refreshed
//
hr = CacheUserInfo (pInfo); if (hr != S_OK) { pSession->Disconnect (); return hr; }
// We have to use ldap_modrdn to modify cn and this must be
// done before any other attribute changes
//
uMsgID_modrdn = ldap_modrdn2 ( ld, GetDN (), m_UserInfo.apszStdAttrValues[ENUM_USERATTR_CN], 1); if (uMsgID_modrdn == -1) { pSession->Disconnect (); hr = ::LdapError2Hresult (ld->ld_errno); return hr; }
// Update DN
//
BuildDN (); } else { uMsgID_modrdn = INVALID_MSG_ID; }
// Set standard attributes
//
hr = UlsLdap_CStdAttrs::SetStdAttrs ( NULL, &uMsgID_modify, 0, (VOID *) pInfo, GetServerInfo (), GetDN ()); if (hr != S_OK) { if (uMsgID_modrdn != INVALID_MSG_ID) { ldap_abandon (ld, uMsgID_modrdn); pSession->Disconnect (); } return hr; }
// Construct a pending info
//
PENDING_INFO PendingInfo; if (uMsgID_modrdn == INVALID_MSG_ID) ::FillDefPendingInfo (&PendingInfo, ld, uMsgID_modify, INVALID_MSG_ID); else ::FillDefPendingInfo (&PendingInfo, ld, uMsgID_modrdn, uMsgID_modify); PendingInfo.uLdapResType = LDAP_RES_MODIFY; PendingInfo.uNotifyMsg = WM_ULS_SET_USER_INFO; PendingInfo.hObject = (HANDLE) this; // for DN rollback
// Queue it
//
hr = g_pPendingQueue->EnterRequest (pSession, &PendingInfo); if (hr != S_OK) { if (uMsgID_modrdn != INVALID_MSG_ID) { ldap_abandon (ld, uMsgID_modrdn); pSession->Disconnect (); } ldap_abandon (ld, uMsgID_modify); MyAssert (FALSE); }
*puRespID = PendingInfo.uRespID; return hr; }
VOID UlsLdap_CLocalUser:: RollbackDN ( VOID ) { if (m_pszOldDN != NULL) { MemFree (m_pszDN); m_pszDN = m_pszOldDN; m_pszOldDN = NULL; } }
HRESULT UlsLdap_CLocalUser:: UpdateIPAddress ( BOOL fPrimary ) { // Update cached ip address
//
HRESULT hr = ::GetLocalIPAddress (&m_dwIPAddress); if (hr != S_OK) return hr;
// Update the ip address string
//
::GetLongString (m_dwIPAddress, &m_UserInfo.szIPAddress[0]);
// Update ip address info on the server ONLY if primary
//
if (! fPrimary) return hr;
// Update IP address on the server
//
return ::IlsUpdateIPAddress ( GetServerInfo (), GetDN (), (TCHAR *) c_apszUserStdAttrNames[ENUM_USERATTR_IP_ADDRESS], &m_UserInfo.szIPAddress[0], ISBU_MODOP_MODIFY_USER, GetPrefixCount (), GetPrefixString ()); }
/* ---------- protected methods ----------- */
HRESULT UlsLdap_CLocalUser:: SendRefreshMsg ( VOID ) { if (m_pszRefreshFilter == NULL) return ULS_E_POINTER;
// Get local ip address
//
DWORD dwIPAddress = 0; HRESULT hr = ::GetLocalIPAddress (&dwIPAddress); if (hr != S_OK) { MyDebugMsg ((ZONE_KA, "KA: cannot get my ip address\r\n")); return hr; }
// If dwIPAddress is 0, then we are not on the network any more
// start relogon process
//
if (dwIPAddress == 0) { MyDebugMsg ((ZONE_KA, "KA: my ip address is null\r\n"));
// Indicate that I am not connected to the server anymore
//
SetRegLocally ();
// Second, notify this app of the network being down
//
PostMessage (g_hWndHidden, WM_ULS_NETWORK_DOWN, TRUE, (LPARAM) this);
// Report error
//
return ULS_E_NETWORK_DOWN; ; } else // If dwIPAddress and m_dwIPAddress, alert
//
if (dwIPAddress != m_dwIPAddress) { // Notify the com to start changing ip address
// the actual change can happen later
//
PostMessage (g_hWndHidden, WM_ULS_IP_ADDRESS_CHANGED, TRUE, (LPARAM) this); }
// get the connection object
UlsLdap_CSession *pSession = NULL; hr = g_pSessionContainer->GetSession (&pSession, &m_ServerInfo); if (hr != S_OK) { MyDebugMsg ((ZONE_KA, "KA: network down, hr=0x%lX\r\n", hr));
// Indicate that I am not connected to the server anymore
//
SetRegLocally ();
// Second, notify the com of network down
//
PostMessage (g_hWndHidden, WM_ULS_NETWORK_DOWN, TRUE, (LPARAM) this);
// Report error
//
return ULS_E_NETWORK_DOWN; } MyAssert (pSession != NULL);
// get the ldap session
LDAP *ld = pSession->GetLd (); MyAssert (ld != NULL);
// Set attributes to return
//
TCHAR *apszAttrNames[3]; apszAttrNames[0] = STR_CN; apszAttrNames[1] = (TCHAR *) c_apszUserStdAttrNames[ENUM_USERATTR_TTL]; apszAttrNames[2] = 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, (TCHAR *) &c_szDefUserBaseDN[0], // base DN
LDAP_SCOPE_BASE, // scope
m_pszRefreshFilter, &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 = (m_ServerInfo.nTimeout != 0) ? m_ServerInfo.nTimeout : 90; LDAPMessage *pLdapMsg = NULL; INT ResultType = ::ldap_result (ld, uMsgID, 0, &TimeVal, &pLdapMsg);
// Deal with timeout or error
//
if (ResultType != LDAP_RES_SEARCH_ENTRY && ResultType != LDAP_RES_SEARCH_RESULT) { MyDebugMsg ((ZONE_KA, "KA: result type mismatches!\r\n")); hr = ULS_E_TIMEOUT; goto MyExit; }
if (pLdapMsg != NULL) { switch (pLdapMsg->lm_returncode) { case LDAP_NO_SUCH_OBJECT: MyDebugMsg ((ZONE_KA, "KA: no such object!\r\n"));
// Indicate that I am not connected to the server anymore
//
SetRegLocally ();
// Second, notify this app to relogon
//
PostMessage (g_hWndHidden, WM_ULS_NEED_RELOGON, TRUE, (LPARAM) this);
// Report error
//
hr = ULS_E_NEED_RELOGON; break;
case LDAP_SUCCESS: // Get the new refresh period
//
hr = ::IlsParseRefreshPeriod ( ld, pLdapMsg, c_apszUserStdAttrNames[ENUM_USERATTR_TTL], &m_uTTL); break;
default: MyDebugMsg ((ZONE_KA, "KA: unknown lm_returncode=%ld\r\n", pLdapMsg->lm_returncode)); MyAssert (FALSE); break; } }
MyExit:
// Free message
//
if (pLdapMsg != NULL) ldap_msgfree (pLdapMsg);
// Free up the session
//
pSession->Disconnect (); return hr; }
/* ---------- private methods ----------- */
HRESULT UlsLdap_CLocalUser:: CreateRegisterModArr ( LDAPMod ***pppMod ) { if (pppMod == NULL) return ULS_E_POINTER;
ULONG cAttrs = COUNT_ENUM_USERATTR; ULONG cbMod = ::IlsCalcModifyListSize (cAttrs); *pppMod = (LDAPMod **) MemAlloc (cbMod); if (*pppMod == NULL) return ULS_E_MEMORY;
LDAPMod *pMod; for (ULONG i = 0; i < cAttrs; i++) { pMod = ::IlsGetModifyListMod (pppMod, cAttrs, i); (*pppMod)[i] = pMod; pMod->mod_op = LDAP_MOD_ADD;
FillModArrAttr (pMod, i); }
// the following overwrote givenname attribute
// ::IlsFixUpModOp ((*pppMod)[0], LDAP_MOD_ADD);
(*pppMod)[cAttrs] = NULL; return S_OK; }
HRESULT UlsLdap_CLocalUser:: CreateSetStdAttrsModArr ( LDAPMod ***pppMod ) { MyAssert (pppMod != NULL); DWORD dwFlags = m_UserInfo.dwFlags;
HRESULT hr; ULONG cTotal = 0; hr = ::FillDefStdAttrsModArr ( pppMod, dwFlags, COUNT_ENUM_USERINFO, &cTotal, ISBU_MODOP_MODIFY_USER, GetPrefixCount (), GetPrefixString ()); if (hr != S_OK) return hr;
// Start indexing
//
ULONG i = GetPrefixCount ();
// Fill in standard attributes
//
if (dwFlags & USEROBJ_F_FIRST_NAME) FillModArrAttr ((*pppMod)[i++], ENUM_USERATTR_FIRST_NAME);
if (dwFlags & USEROBJ_F_LAST_NAME) FillModArrAttr ((*pppMod)[i++], ENUM_USERATTR_LAST_NAME);
if (dwFlags & USEROBJ_F_EMAIL_NAME) FillModArrAttr ((*pppMod)[i++], ENUM_USERATTR_EMAIL_NAME);
if (dwFlags & USEROBJ_F_CITY_NAME) FillModArrAttr ((*pppMod)[i++], ENUM_USERATTR_CITY_NAME);
if (dwFlags & USEROBJ_F_COUNTRY_NAME) FillModArrAttr ((*pppMod)[i++], ENUM_USERATTR_COUNTRY_NAME);
if (dwFlags & USEROBJ_F_COMMENT) FillModArrAttr ((*pppMod)[i++], ENUM_USERATTR_COMMENT);
if (dwFlags & USEROBJ_F_IP_ADDRESS) FillModArrAttr ((*pppMod)[i++], ENUM_USERATTR_IP_ADDRESS);
if (dwFlags & USEROBJ_F_FLAGS) FillModArrAttr ((*pppMod)[i++], ENUM_USERATTR_FLAGS);
MyAssert (i == cTotal);
return S_OK; }
VOID UlsLdap_CLocalUser:: FillModArrAttr ( LDAPMod *pMod, LONG AttrIdx ) { pMod->mod_type = (TCHAR *) c_apszUserStdAttrNames[AttrIdx];
// single valued attr
TCHAR **ppsz = (TCHAR **) (pMod + 1); pMod->mod_values = ppsz; *ppsz++ = (m_UserInfo.apszStdAttrValues[AttrIdx] != NULL) ? m_UserInfo.apszStdAttrValues[AttrIdx] : (TCHAR *) &c_szEmptyString[0];
*ppsz = NULL; }
HRESULT UlsLdap_CLocalUser:: CacheInfo ( VOID *pInfo ) { return CacheUserInfo ((LDAP_USERINFO *) pInfo); }
HRESULT UlsLdap_CLocalUser:: CacheUserInfo ( LDAP_USERINFO *pInfo ) { ZeroMemory (&m_UserInfo, sizeof (m_UserInfo)); TCHAR *pszName;
if (pInfo->uOffsetName != INVALID_OFFSET) { pszName = (TCHAR *) (((BYTE *) pInfo) + pInfo->uOffsetName); m_UserInfo.apszStdAttrValues[ENUM_USERATTR_CN] = pszName; // m_UserInfo.dwFlags |= USEROBJ_F_NAME;
}
if (pInfo->uOffsetFirstName != INVALID_OFFSET) { pszName = (TCHAR *) (((BYTE *) pInfo) + pInfo->uOffsetFirstName); m_UserInfo.apszStdAttrValues[ENUM_USERATTR_FIRST_NAME] = pszName; m_UserInfo.dwFlags |= USEROBJ_F_FIRST_NAME; }
if (pInfo->uOffsetLastName != INVALID_OFFSET) { pszName = (TCHAR *) (((BYTE *) pInfo) + pInfo->uOffsetLastName); m_UserInfo.apszStdAttrValues[ENUM_USERATTR_LAST_NAME] = pszName; m_UserInfo.dwFlags |= USEROBJ_F_LAST_NAME; }
if (pInfo->uOffsetEMailName != INVALID_OFFSET) { pszName = (TCHAR *) (((BYTE *) pInfo) + pInfo->uOffsetEMailName); m_UserInfo.apszStdAttrValues[ENUM_USERATTR_EMAIL_NAME] = pszName; m_UserInfo.dwFlags |= USEROBJ_F_EMAIL_NAME; }
if (pInfo->uOffsetCityName != INVALID_OFFSET) { pszName = (TCHAR *) (((BYTE *) pInfo) + pInfo->uOffsetCityName); m_UserInfo.apszStdAttrValues[ENUM_USERATTR_CITY_NAME] = pszName; m_UserInfo.dwFlags |= USEROBJ_F_CITY_NAME; }
if (pInfo->uOffsetCountryName != INVALID_OFFSET) { pszName = (TCHAR *) (((BYTE *) pInfo) + pInfo->uOffsetCountryName); m_UserInfo.apszStdAttrValues[ENUM_USERATTR_COUNTRY_NAME] = pszName; m_UserInfo.dwFlags |= USEROBJ_F_COUNTRY_NAME; }
if (pInfo->uOffsetComment != INVALID_OFFSET) { pszName = (TCHAR *) (((BYTE *) pInfo) + pInfo->uOffsetComment); m_UserInfo.apszStdAttrValues[ENUM_USERATTR_COMMENT] = pszName; m_UserInfo.dwFlags |= USEROBJ_F_COMMENT; }
if (pInfo->uOffsetIPAddress != INVALID_OFFSET) { pszName = (TCHAR *) (((BYTE *) pInfo) + pInfo->uOffsetIPAddress); m_UserInfo.apszStdAttrValues[ENUM_USERATTR_IP_ADDRESS] = pszName; m_UserInfo.dwFlags |= USEROBJ_F_IP_ADDRESS; }
if (pInfo->dwFlags != INVALID_USER_FLAGS) { ::GetLongString (pInfo->dwFlags, &m_UserInfo.szFlags[0]); m_UserInfo.apszStdAttrValues[ENUM_USERATTR_FLAGS] = &m_UserInfo.szFlags[0]; m_UserInfo.dwFlags |= USEROBJ_F_FLAGS; }
return S_OK; }
HRESULT UlsLdap_CLocalUser:: BuildDN ( VOID ) { MyAssert (m_UserInfo.apszStdAttrValues[ENUM_USERATTR_CN] != NULL);
TCHAR szDN[MAX_DN_LENGTH]; szDN[0] = TEXT ('\0');
TCHAR *pszDN = &szDN[0];
if (m_UserInfo.apszStdAttrValues[ENUM_USERATTR_CN] != NULL) { wsprintf (pszDN, TEXT ("%s=%s"), STR_CN, m_UserInfo.apszStdAttrValues[ENUM_USERATTR_CN]); pszDN += lstrlen (pszDN); }
if (m_UserInfo.apszStdAttrValues[ENUM_USERATTR_O] != NULL) { wsprintf (pszDN, TEXT (", %s=%s"), STR_O, m_UserInfo.apszStdAttrValues[ENUM_USERATTR_O]); pszDN += lstrlen (pszDN); }
if (m_UserInfo.apszStdAttrValues[ENUM_USERATTR_C] != NULL) { wsprintf (pszDN, TEXT (", %s=%s"), STR_C, m_UserInfo.apszStdAttrValues[ENUM_USERATTR_C]); pszDN += lstrlen (pszDN); }
wsprintf (pszDN, TEXT (", %s"), &c_szDefUserBaseDN[0]);
TCHAR *psz = My_strdup (&szDN[0]); if (psz == NULL) return ULS_E_MEMORY;
MemFree (m_pszOldDN); m_pszOldDN = m_pszDN; m_pszDN = psz; return S_OK; }
|