/* ---------------------------------------------------------------------- Module: ULS.DLL (Service Provider) File: spanyatt.cpp Content: This file contains the arbitrary-attribute object. History: 10/15/96 Chu, Lon-Chan [lonchanc] Created. Copyright (c) Microsoft Corporation 1996-1997 ---------------------------------------------------------------------- */ #include "ulsp.h" #include "spinc.h" /* ---------- public methods ----------- */ UlsLdap_CAnyAttrs::UlsLdap_CAnyAttrs ( VOID ) { m_cAttrs = 0; m_AttrList = NULL; } UlsLdap_CAnyAttrs::~UlsLdap_CAnyAttrs ( VOID ) { FreeAttrList (m_AttrList); } /* ---------- protected methods ----------- */ HRESULT UlsLdap_CAnyAttrs::SetAnyAttrs ( ULONG *puRespID, ULONG *puMsgID, ULONG uNotifyMsg, ULONG cAttrs, TCHAR *pszAttrs, ULONG cPrefix, TCHAR *pszPrefix, LONG ModOp, SERVER_INFO *pServerInfo, TCHAR *pszDN ) { MyAssert (puRespID != NULL || puMsgID != NULL); MyAssert (cAttrs != 0); MyAssert (pszAttrs != NULL); MyAssert (cPrefix != 0); MyAssert (pszPrefix != NULL); MyAssert (pServerInfo != NULL); MyAssert (pszDN != NULL); MyAssert (ModOp == LDAP_MOD_REPLACE || ModOp == LDAP_MOD_ADD); // create a prefix for each attr name in the following pair pszAttrs = PrefixNameValueArray (TRUE, cAttrs, pszAttrs); if (pszAttrs == NULL) return ULS_E_MEMORY; // build modify array for ldap_modify() LDAPMod **ppMod = NULL; HRESULT hr = SetAttrsAux (cAttrs, pszAttrs, cPrefix, pszPrefix, ModOp, &ppMod); if (hr != S_OK) { MemFree (pszAttrs); 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, pServerInfo); if (hr != S_OK) { MemFree (pszAttrs); 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_modify (ld, pszDN, ppMod); MemFree (pszAttrs); MemFree (ppMod); if (uMsgID == -1) { hr = ::LdapError2Hresult (ld->ld_errno); pSession->Disconnect (); return hr; } // if the caller does not ask for notify id // then do not queue a pending info if (puRespID != NULL) { PENDING_INFO PendingInfo; ::FillDefPendingInfo (&PendingInfo, ld, uMsgID, INVALID_MSG_ID); PendingInfo.uLdapResType = LDAP_RES_MODIFY; PendingInfo.uNotifyMsg = uNotifyMsg; // queue it hr = g_pPendingQueue->EnterRequest (pSession, &PendingInfo); if (hr != S_OK) { ldap_abandon (ld, uMsgID); pSession->Disconnect (); MyAssert (FALSE); } *puRespID = PendingInfo.uRespID; } if (puMsgID) *puMsgID = uMsgID; return hr; } HRESULT UlsLdap_CAnyAttrs::RemoveAllAnyAttrs ( ULONG *puMsgID, ULONG cPrefix, TCHAR *pszPrefix, SERVER_INFO *pServerInfo, TCHAR *pszDN ) { ULONG cbAttrs = 0; ULONG cAttrs = 0; for (ANY_ATTR *p = m_AttrList; p != NULL; p = p->next) { cAttrs++; if (p->pszAttrName != NULL) cbAttrs += (lstrlen (p->pszAttrName) + 1) * sizeof (TCHAR); } MyAssert (cAttrs == m_cAttrs); TCHAR *pszAttrs = (TCHAR *) MemAlloc (cbAttrs); if (pszAttrs == NULL) return ULS_E_MEMORY; TCHAR *psz = pszAttrs; for (p = m_AttrList; p != NULL; p = p->next) { if (p->pszAttrName != NULL) { lstrcpy (psz, p->pszAttrName); psz += lstrlen (psz) + 1; } } HRESULT hr = RemoveAnyAttrsEx ( NULL, puMsgID, 0, cAttrs, pszAttrs, cPrefix, pszPrefix, pServerInfo, pszDN); MemFree (pszAttrs); return hr; } HRESULT UlsLdap_CAnyAttrs::RemoveAnyAttrs ( ULONG *puRespID, ULONG *puMsgID, ULONG uNotifyMsg, ULONG cAttrs, TCHAR *pszAttrs, ULONG cPrefix, TCHAR *pszPrefix, SERVER_INFO *pServerInfo, TCHAR *pszDN) { MyAssert (puRespID != NULL || puMsgID != NULL); MyAssert (cAttrs != 0); MyAssert (pszAttrs != NULL); MyAssert (cPrefix != 0); MyAssert (pszPrefix != NULL); MyAssert (pServerInfo != NULL); MyAssert (pszDN != NULL); pszAttrs = PrefixNameValueArray (FALSE, cAttrs, pszAttrs); if (pszAttrs == NULL) return ULS_E_MEMORY; HRESULT hr = RemoveAnyAttrsEx ( puRespID, puMsgID, uNotifyMsg, cAttrs, pszAttrs, cPrefix, pszPrefix, pServerInfo, pszDN); MemFree (pszAttrs); return hr; } HRESULT UlsLdap_CAnyAttrs::RemoveAnyAttrsEx ( ULONG *puRespID, ULONG *puMsgID, ULONG uNotifyMsg, ULONG cAttrs, TCHAR *pszAttrs, ULONG cPrefix, TCHAR *pszPrefix, SERVER_INFO *pServerInfo, TCHAR *pszDN) { MyAssert (puRespID != NULL || puMsgID != NULL); MyAssert (cAttrs != 0); MyAssert (pszAttrs != NULL); MyAssert (cPrefix != 0); MyAssert (pszPrefix != NULL); MyAssert (pServerInfo != NULL); MyAssert (pszDN != NULL); // build modify array for ldap_modify() LDAPMod **ppMod = NULL; HRESULT hr = RemoveAttrsAux (cAttrs, pszAttrs, cPrefix, pszPrefix, &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, pServerInfo); 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_modify (ld, pszDN, ppMod); MemFree (ppMod); if (uMsgID == -1) { hr = ::LdapError2Hresult (ld->ld_errno); pSession->Disconnect (); return hr; } // if the caller does not ask for notify id // then do not queue a pending info if (puRespID != NULL) { PENDING_INFO PendingInfo; ::FillDefPendingInfo (&PendingInfo, ld, uMsgID, INVALID_MSG_ID); PendingInfo.uLdapResType = LDAP_RES_MODIFY; PendingInfo.uNotifyMsg = uNotifyMsg; hr = g_pPendingQueue->EnterRequest (pSession, &PendingInfo); if (hr != S_OK) { ldap_abandon (ld, uMsgID); pSession->Disconnect (); MyAssert (FALSE); } *puRespID = PendingInfo.uRespID; } else { if (puMsgID != NULL) *puMsgID = uMsgID; } return hr; } /* ---------- private methods ----------- */ HRESULT UlsLdap_CAnyAttrs::SetAttrsAux ( ULONG cAttrs, TCHAR *pszAttrs, ULONG cPrefix, TCHAR *pszPrefix, LONG ModOp, LDAPMod ***pppMod ) { MyAssert (cAttrs != 0); MyAssert (pszAttrs != NULL); MyAssert (cPrefix != 0); MyAssert (pszPrefix != NULL); MyAssert (ModOp == LDAP_MOD_REPLACE || ModOp == LDAP_MOD_ADD); MyAssert (pppMod != NULL); // create modify list ULONG cTotal = cPrefix + cAttrs; ULONG cbMod = ::IlsCalcModifyListSize (cTotal); *pppMod = (LDAPMod **) MemAlloc (cbMod); if (*pppMod == NULL) { return ULS_E_MEMORY; } LDAPMod *pMod; for (ULONG 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; } else { pMod->mod_op = ModOp; if (LocateAttr (pszAttrs) == NULL) { pMod->mod_op = LDAP_MOD_ADD; m_cAttrs++; } if (pMod->mod_op == LDAP_MOD_ADD) { ULONG cbAttrSize = sizeof (ANY_ATTR) + sizeof (TCHAR) * (lstrlen (pszAttrs) + 1); ANY_ATTR *pNew = (ANY_ATTR *) MemAlloc (cbAttrSize); if (pNew == NULL) { return ULS_E_MEMORY; } // fill in attr name pNew->pszAttrName = (TCHAR *) (pNew + 1); lstrcpy (pNew->pszAttrName, pszAttrs); // link to the list pNew->prev = NULL; pNew->next = m_AttrList; m_AttrList = pNew; } pMod->mod_type = pszAttrs; pszAttrs += lstrlen (pszAttrs) + 1; *(pMod->mod_values) = pszAttrs; pszAttrs += lstrlen (pszAttrs) + 1; } } (*pppMod)[cTotal] = NULL; ::IlsFixUpModOp ((*pppMod)[0], ModOp, ISBU_MODOP_MODIFY_APP); return S_OK; } HRESULT UlsLdap_CAnyAttrs::RemoveAttrsAux ( ULONG cAttrs, TCHAR *pszAttrs, ULONG cPrefix, TCHAR *pszPrefix, LDAPMod ***pppMod ) { MyAssert (cAttrs != 0); MyAssert (pszAttrs != NULL); MyAssert (cPrefix != 0); MyAssert (pszPrefix != NULL); MyAssert (pppMod != NULL); // create modify list ULONG cTotal = cPrefix + cAttrs; ULONG cbMod = ::IlsCalcModifyListSize (cTotal); *pppMod = (LDAPMod **) MemAlloc (cbMod); if (*pppMod == NULL) { return ULS_E_MEMORY; } LDAPMod *pMod; for (ULONG i = 0; i < cTotal; i++) { pMod = ::IlsGetModifyListMod (pppMod, cTotal, i); (*pppMod)[i] = pMod; if (i < cPrefix) { pMod->mod_op = LDAP_MOD_REPLACE; pMod->mod_type = pszPrefix; pszPrefix += lstrlen (pszPrefix) + 1; pMod->mod_values = (TCHAR **) (pMod + 1); *(pMod->mod_values) = pszPrefix; pszPrefix += lstrlen (pszPrefix) + 1; } else { pMod->mod_op = LDAP_MOD_DELETE; RemoveAttrFromList (pszAttrs); pMod->mod_type = pszAttrs; pszAttrs += lstrlen (pszAttrs) + 1; } } (*pppMod)[cTotal] = NULL; ::IlsFixUpModOp ((*pppMod)[0], LDAP_MOD_REPLACE, ISBU_MODOP_MODIFY_APP); return S_OK; } VOID UlsLdap_CAnyAttrs::RemoveAttrFromList ( TCHAR *pszAttrName ) { ANY_ATTR *pOld = LocateAttr (pszAttrName); if (pOld != NULL) { // remove it if (pOld->prev != NULL) { pOld->prev->next = pOld->next; } else { m_AttrList = pOld->next; } if (pOld->next != NULL) { pOld->next->prev = pOld->prev; } MyAssert (m_cAttrs != 0); m_cAttrs--; } } VOID UlsLdap_CAnyAttrs::FreeAttrList ( ANY_ATTR *AttrList ) { ANY_ATTR *pCurr, *pNext; for (pCurr = AttrList; pCurr != NULL; pCurr = pNext) { pNext = pCurr->next; MemFree (pCurr); } } ANY_ATTR *UlsLdap_CAnyAttrs::LocateAttr ( TCHAR *pszAttrName ) { ANY_ATTR *pAttr; for (pAttr = m_AttrList; pAttr != NULL; pAttr = pAttr->next) { if (! My_lstrcmpi (pszAttrName, pAttr->pszAttrName)) { break; } } return pAttr; } // const TCHAR c_szAnyAttrPrefix[] = TEXT ("ulsaan_"); const TCHAR c_szAnyAttrPrefix[] = TEXT ("ILSA"); #define SIZE_ANY_ATTR_PREFIX (sizeof (c_szAnyAttrPrefix) / sizeof (TCHAR)) const TCHAR *SkipAnyAttrNamePrefix ( const TCHAR *pszAttrName ) { MyAssert (pszAttrName != NULL); const TCHAR *psz = IsAnyAttrName (pszAttrName); if (psz == NULL) { MyAssert (FALSE); psz = pszAttrName; } return psz; } const TCHAR *IsAnyAttrName ( 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 *PrefixNameValueArray ( 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; }