📄 ldap_net.cpp
字号:
/**************************************************************************
THIS CODE AND INFORMATION IS PROVIDED 'AS IS' WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Author: Leon Finker 9/2002
**************************************************************************/
#include "common.h"
#include "ldap_net.h"
#include "helpers.h"
#include <stdio.h>
namespace ldap_net
{
////////////////////////////////////////////////////////////////////////
// LdapAttribute
String* LdapAttribute::get_StringValues()[]
{
CIntPtrStringAnsi ptrAttribname(m_attribname);
char** vals = ::ldap_get_values(m_ldap, m_start, ptrAttribname);
ptrAttribname.Free();
Collections::Specialized::StringCollection* sc = new Collections::Specialized::StringCollection();
for(int i=0; vals[i] != 0; ++i)
sc->Add(new String(vals[i]));
ldap_value_free(vals);
String* sa[] = new String*[sc->Count];
sc->CopyTo(sa, 0);
sc->Clear();
return sa;
}
/* get_BinaryValues */
Array* LdapAttribute::get_BinaryValues()
{
CIntPtrStringAnsi ptrAttribname(m_attribname);
berval** vals = ldap_get_values_len(m_ldap, m_start, ptrAttribname);
ptrAttribname.Free();
Array* arr[] = new Array*[ldap_count_values_len(vals)];
for(int i=0; vals[i] != 0; ++i)
{
Byte ba[] = new Byte[vals[i]->bv_len];
Marshal::Copy(IntPtr(vals[i]->bv_val), ba, 0, ba->Length);
arr[i]=ba;
}
ldap_value_free_len(vals);
return arr;
}
/* MoveNext */
bool LdapAttribute::MoveNext()
{
char* attrn;
if(m_current == 0)
{
BerElement* temp;
attrn = ldap_first_attribute(m_ldap, m_start, &temp);
m_current = temp;
}
else
{
attrn = ldap_next_attribute(m_ldap, m_start, m_current);
}
if(attrn != 0)
{
m_attribname = Marshal::PtrToStringAnsi(attrn);
ldap_memfree(attrn);
}
else
{
if(m_current != 0)
ber_free(m_current, 0);
m_current = 0;
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////////
// LdapEntry
bool LdapEntry::MoveNext()
{
if(m_current == 0)
m_current = ldap_first_entry(m_ldap, m_start);
else
m_current = ldap_next_entry(m_ldap,m_current);
if(m_current != 0)
{
char* dn = ldap_get_dn(m_ldap, m_current);
if(dn != 0)
{
m_dn = Marshal::PtrToStringAnsi(dn);
ldap_memfree(dn);
}
return true;
}
else
return false;
}
///////////////////////////////////////////////////////////////////////////////
// LDAPModify
// WHAT a f MESS this is!!!
//might have a bug, be carefull
LDAPModify::LDAPModify(const char* dn, ListDictionary * attrvals, long op)
{
Collections::IDictionaryEnumerator* dicenum = attrvals->GetEnumerator();
IntPtr ptrMods = Marshal::AllocCoTaskMem((attrvals->Count+1) * sizeof(::LDAPMod*)); //+1 for null
/*1*/ppMods = (LDAPMod**)ptrMods.ToPointer();
for(int i=0; i< attrvals->Count; ++i)
/*2*/ppMods[i] = (::LDAPMod*)Marshal::AllocCoTaskMem(sizeof(::LDAPMod)).ToPointer();
for(int i=0; dicenum->MoveNext(); ++i)
{
String* skey=dynamic_cast<String*>(dicenum->Key);
if(skey == 0)
throw new InvalidCastException(S"Invalid type for attribute name, String expected");
ppMods[i]->mod_op = op;
bool binary=false;
String* svalarr[]= dynamic_cast<String*[]>(dicenum->Value);
Object* barr[] = dynamic_cast<Object*[]>(dicenum->Value);
Byte ba[] = dynamic_cast<Byte[]>(dicenum->Value);
String* sval = dynamic_cast<String*>(dicenum->Value);
int nValsCount = 0;
if(svalarr != 0)
{
binary = false;
nValsCount = svalarr->Count;
}
else if(barr != 0) //check has to be after svalarr
{
binary = true;
nValsCount = barr->Count;
}
else if(sval != 0)
{
binary = false;
nValsCount = 1;
}
else if(ba != 0)
{
binary = true;
nValsCount = 1;
}
else
{
if(dicenum->Value != 0)
throw new InvalidCastException(String::Concat("Expected String, String[], Array of Byte[], or Byte[] for values but got ", dicenum->Value->GetType()->ToString()));
}
ppMods[i]->mod_op |= LDAP_MOD_BVALUES;
/*3*/ppMods[i]->mod_type=(char*)Marshal::StringToCoTaskMemAnsi(skey).ToPointer();
/*4*/ppMods[i]->mod_vals.modv_bvals = (berval**)Marshal::AllocCoTaskMem((nValsCount+1) * sizeof(berval*)).ToPointer(); //+1 for null;
for(int j=0; j < nValsCount; ++j)
{
/*5*/ppMods[i]->mod_vals.modv_bvals[j]=(berval*)Marshal::AllocCoTaskMem(sizeof(berval)).ToPointer();
char* pTemp=0;
int nLen = 0;
if(!binary)
{
if(sval)
pTemp = (char*)Marshal::StringToCoTaskMemAnsi(sval).ToPointer();
else
pTemp = (char*)Marshal::StringToCoTaskMemAnsi(svalarr[j]).ToPointer();
nLen = strlen(pTemp);
}
else
{
Byte baTemp[];
if(ba != 0)
{
baTemp = ba;
nLen = baTemp->Count;
pTemp = (char*)Marshal::AllocCoTaskMem(nLen).ToPointer();
Marshal::Copy(baTemp, 0, IntPtr(pTemp), nLen);
}
else
{
if(dynamic_cast<Byte[]>(barr[j]) == 0)
throw new InvalidCastException(String::Concat("Expected Byte[] for values but got ", dicenum->Value->GetType()->ToString()));
baTemp = (Byte[])barr[j];
nLen = baTemp->Count;
pTemp = (char*)Marshal::AllocCoTaskMem(nLen).ToPointer();
Marshal::Copy(baTemp, 0, IntPtr(pTemp), nLen);
}
}
/*6*/ppMods[i]->mod_vals.modv_bvals[j]->bv_val=pTemp;
ppMods[i]->mod_vals.modv_bvals[j]->bv_len = nLen;
}
ppMods[i]->mod_vals.modv_bvals[nValsCount]=0;//must null terminate for ldap
}
ppMods[attrvals->Count] = 0; //need to null terminate for ldap
}
/* ~LDAPModify */
LDAPModify::~LDAPModify()
{
for(int i=0; ppMods[i] != 0; ++i)
{
for(int j=0; ppMods[i]->mod_vals.modv_bvals[j] != 0; ++j)
{
/*6*/Marshal::FreeCoTaskMem(IntPtr(ppMods[i]->mod_vals.modv_bvals[j]->bv_val));
/*5*/Marshal::FreeCoTaskMem(IntPtr(ppMods[i]->mod_vals.modv_bvals[j]));
}
/*4*/Marshal::FreeCoTaskMem(IntPtr(ppMods[i]->mod_vals.modv_bvals));
/*3*/Marshal::FreeCoTaskMem(IntPtr(ppMods[i]->mod_type));
/*2*/Marshal::FreeCoTaskMem(IntPtr(ppMods[i]));
}
/*1*/Marshal::FreeCoTaskMem(ppMods);
}
/////////////////////////////////////////////////////////////////////////////////
// LdapClient
LdapClient::LdapClient(String* HostName, UInt32 port, bool prot_ver3, bool ssl)
{
CIntPtrStringAnsi ptrHost(HostName);
#ifdef OPENLDAP_NET
m_ldap = ::ldap_init(ptrHost, port);
//LDAP* temp; //this code is needed for connecting with ssl to AD, because ldap_start_tls_s won't work on win2k
//but ldap_start_tls_s should work with windows 2003 and AD
//ldap_initialize(&temp, (char*)ptr.ToPointer()); //for uri based hostname i.e. ldaps://localhost (ssl)
//m_ldap = ldap;
#else
m_ldap = ::ldap_sslinit(ptrHost, port, ssl);
#endif
ptrHost.Free();
if(m_ldap == 0)
GetLDAPErrorThrow(0);
if(prot_ver3)
{
LDAPINT ver = LDAP_VERSION3;
LDAPINT nRet = ::ldap_set_option(m_ldap, LDAP_OPT_PROTOCOL_VERSION, &ver);
//MS specific: nRet = ::ldap_set_option(m_ldap, LDAP_OPT_SERVER_CERTIFICATE, &ServerCertCallback);
if(nRet != LDAP_SUCCESS)
GetLDAPErrorThrow(nRet);
}
#ifdef OPENLDAP_NET
if(ssl)
{
//when using winldap this function is only available on winxp+
LDAPINT nRet = ::ldap_start_tls_s(m_ldap,0,0);
if(nRet != LDAP_SUCCESS)
GetLDAPErrorThrow(nRet);
}
#endif
}
/* get_DefaultSSLPort */
UInt32 LdapClient::get_DefaultSSLPort()
{
#ifdef OPENLDAP_NET
return LDAPS_PORT;
#else
return LDAP_SSL_PORT;
#endif
}
/* ldap_search_s */
Int32 LdapClient::ldap_search_ext_s(String* base, Misc::LDAPSearchScope scope, String* filter, String* attrs[], bool attrsonly, int timeoutsecs, int sizelimit, [Out] LdapResult** res)
{
CIntPtrStringAnsi ptrBase(base);
CIntPtrStringAnsi ptrFilter(filter);
LDAPMessage *msg=0;
char** pAttrs = 0;
if(attrs->Count > 0)
{
pAttrs = (char**)(Marshal::AllocCoTaskMem((attrs->Count+1) * sizeof(char*)).ToPointer());
for(int i=0; i<attrs->Count; ++i)
{
IntPtr ptr = Marshal::StringToCoTaskMemAnsi(attrs[i]);
pAttrs[i] = (char*)ptr.ToPointer();
}
pAttrs[attrs->Count] = 0;
}
//LDAPINT nRet = ::ldap_search_s(m_ldap, ptrBase, scope, ptrFilter, pAttrs, attrsonly, &msg);
#ifdef WINLDAP_NET
l_timeval time={0};
#elif OPENLDAP_NET
timeval time={0};
#endif
time.tv_sec = timeoutsecs;
LDAPINT nRet = ::ldap_search_ext_s(m_ldap, ptrBase, scope, ptrFilter, pAttrs, attrsonly, 0, 0, &time, sizelimit, &msg);
ptrBase.Free();
ptrFilter.Free();
if(attrs->Count > 0)
{
for(int i=0; i < attrs->Count; ++i)
{
char* p = pAttrs[i];
Marshal::FreeCoTaskMem(IntPtr(p));
pAttrs[i]=0;
}
Marshal::FreeCoTaskMem(pAttrs);
}
if(nRet != LDAP_SUCCESS && nRet != LDAP_PARTIAL_RESULTS && nRet != LDAP_SIZELIMIT_EXCEEDED)
{
if(msg)
ldap_msgfree(msg);
GetLDAPErrorThrow(nRet);
}
LDAPINT nCount = ldap_count_entries(m_ldap, msg);
*res = new LdapResult(m_ldap, msg);
if(nRet == LDAP_PARTIAL_RESULTS || nRet == LDAP_SIZELIMIT_EXCEEDED)
throw new Exceptions::LDAPExceptionPartialResult(nCount);
return nCount;
}
/* ldap_add_s */
void LdapClient::ldap_add_s(String* dn, ListDictionary * attrvals)
{
#ifdef _DEBUG
Diagnostics::Debug::Assert(attrvals->Count > 0,"Nothing to add.");
#endif
CIntPtrStringAnsi ptrDN(dn);
LDAPModify mod(ptrDN, attrvals, LDAP_MOD_ADD);
LDAPINT nRet = ::ldap_add_s(m_ldap, ptrDN, mod.ppMods);
ptrDN.Free();
if(nRet != LDAP_SUCCESS)
GetLDAPErrorThrow(nRet);
}
/* ldap_compare_s */
bool LdapClient::ldap_compare_s(String* dn, String* attr, String* val)
{
CIntPtrStringAnsi ptrDN(dn);
CIntPtrStringAnsi ptrAttr(attr);
CIntPtrStringAnsi ptrVal(val);
LDAPINT nRet = ::ldap_compare_s(m_ldap, ptrDN, ptrAttr, ptrVal);
ptrDN.Free();
ptrAttr.Free();
ptrVal.Free();
if(nRet != LDAP_COMPARE_TRUE && nRet != LDAP_COMPARE_FALSE)
GetLDAPErrorThrow(nRet);
return nRet == LDAP_COMPARE_TRUE;
}
/* ldap_delete_s */
void LdapClient::ldap_delete_s(String* dn)
{
CIntPtrStringAnsi ptrDN(dn);
LDAPINT nRet = ::ldap_delete_s(m_ldap, ptrDN);
ptrDN.Free();
if(nRet != LDAP_SUCCESS)
GetLDAPErrorThrow(nRet);
}
/* ldap_modify_passwd */
void LdapClient::ldap_modify_pwd(String* dn, String* newpasswd)
{
//printf("==========> Begin Modify user`s password! \n");
struct berval newpw = { 0, NULL };
BerElement *ber = NULL;
PBERVAL bv = NULL;
int rc = LDAP_SUCCESS;
LDAPMessage* res;
ULONG id, code = LDAP_OTHER;
/*
* Check input parameter
*/
if ( dn == NULL )
GetLDAPErrorThrow(LDAP_PARAM_ERROR);
if ( newpasswd == NULL )
GetLDAPErrorThrow(LDAP_PARAM_ERROR);
//Data type Conversion (From String to PCHAR)
CIntPtrStringAnsi ptrDN(dn);
//CIntPtrStringAnsi ptrNewpasswd(newpasswd);
CIntPtrStringAnsi ptrPWD(newpasswd);
//newpw.bv_val = ptrNewpasswd;
//newpw.bv_len = strlen( newpw.bv_val );
/*
* Allocate a BerElement for stuffing in the function IN parameters
*/
//The LBER_USE_DER flag (0x01) should always be specified, which causes the element lengths to be encoded in the minimum number of octets.
ber = ber_alloc_t(LBER_USE_DER);
if(ber == NULL)
GetLDAPErrorThrow(LDAP_NO_MEMORY);
//#ifdef _DEBUG
//printf("==========> Step 01\n");
//#endif
/*
* Build the flow for modify the uses`s password and transfer to ldap server
*/
rc = ber_printf( ber,"{");
if (rc == LBER_ERROR)
GetLDAPErrorThrow(LDAP_ENCODING_ERROR);
rc = ber_printf( ber, "ts",LDAP_TAG_EXOP_MODIFY_PASSWD_ID, ptrDN);
if (rc == LBER_ERROR)
GetLDAPErrorThrow(LDAP_ENCODING_ERROR);
rc = ber_printf( ber, "ts",LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, ptrPWD );
if (rc == LBER_ERROR)
GetLDAPErrorThrow(LDAP_ENCODING_ERROR);
rc = ber_printf( ber,"}" );
if (rc == LBER_ERROR)
GetLDAPErrorThrow(LDAP_ENCODING_ERROR);
rc = ber_flatten(ber,&bv);
if (rc == LBER_ERROR)
GetLDAPErrorThrow(LDAP_NO_MEMORY);
/*
* Call ldap extended operation RFC3062
*/
rc = ldap_extended_operation( m_ldap,LDAP_EXOP_MODIFY_PASSWD,bv,NULL,NULL,&id);
if( rc != LDAP_SUCCESS )
GetLDAPErrorThrow(LDAP_OTHER);
rc = ldap_result( m_ldap, LDAP_RES_ANY, LDAP_MSG_ALL, NULL, &res );
if( rc < 0 )
GetLDAPErrorThrow(LDAP_NO_RESULTS_RETURNED);
//printf("The result message is %s\n",res);
rc = ldap_parse_result( m_ldap,res,&code,NULL,NULL,NULL,NULL, 0 );
if( rc != LDAP_SUCCESS )
GetLDAPErrorThrow(LDAP_NO_RESULTS_RETURNED);
if( code != LDAP_SUCCESS )
GetLDAPErrorThrow(LDAP_NO_SUCH_OBJECT);
/*
* Realease the resource . Do not make memory leak.
*/
ber_free( ber, 1 );
ber_bvfree(bv);
ptrPWD.Free();
ptrDN.Free();
ldap_msgfree(res);
//printf("Result: %s | (%d)\n", ldap_err2string( code ), code );
//printf("==========> End Modify user`s password! \n");
}
/* ldap_simple_bind_s */
void LdapClient::ldap_simple_bind_s(String* who, String* passwd)
{
CIntPtrStringAnsi ptrWho(who);
CIntPtrStringAnsi ptrPasswd(passwd);
LDAPINT nRet = ::ldap_simple_bind_s(m_ldap, ptrWho, ptrPasswd);
ptrWho.Free();
ptrPasswd.Free();
if(nRet != LDAP_SUCCESS)
GetLDAPErrorThrow(nRet);
}
/*ldap_modify_s*/
void LdapClient::ldap_bind_s(String* who, String* passwd, Misc::AuthMethod method)
{
CIntPtrStringAnsi ptrWho(who);
CIntPtrStringAnsi ptrPasswd(passwd);
LDAPINT nRet = ::ldap_bind_s(m_ldap, ptrWho, ptrPasswd, method);
ptrWho.Free();
ptrPasswd.Free();
if(nRet != LDAP_SUCCESS)
GetLDAPErrorThrow(nRet);
}
/*ldap_modify_s*/
void LdapClient::ldap_modify_s(String* dn, ListDictionary * attrvals, long op)
{
#ifdef _DEBUG
Diagnostics::Debug::Assert(attrvals->Count > 0,"Nothing to modify.");
#endif
CIntPtrStringAnsi ptrDN(dn);
LDAPModify mod(ptrDN, attrvals, op);
LDAPINT nRet = ::ldap_modify_s(m_ldap, ptrDN, mod.ppMods);
ptrDN.Free();
if(nRet != LDAP_SUCCESS)
GetLDAPErrorThrow(nRet);
}
/*GetLDAPErrorThrow*/
void LdapClient::GetLDAPErrorThrow(LDAPINT nErr)
{
if(nErr == 0)
::ldap_get_option(m_ldap, LDAP_OPT_ERROR_NUMBER, &nErr);
char* pError = ::ldap_err2string(nErr);
if(pError == 0)
pError = "unknown error";
throw new Exceptions::LDAPException(pError);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -