Skip to content

Instantly share code, notes, and snippets.

@mbohun
Created September 3, 2012 05:02
Show Gist options
  • Save mbohun/3606810 to your computer and use it in GitHub Desktop.
Save mbohun/3606810 to your computer and use it in GitHub Desktop.
test_ldap_threads-synchronous.cpp
#ifdef _WIN32
#include <windows.h>
#endif //WIN32
#include <iostream>
#include <sstream>
#include <stdio.h>
#include <time.h>
#include <ctype.h>
#define LDAP_DEPRECATED 1 //AAA needs this
#include <ldap.h>
#include <lber.h> //for LDAP_CALL LDAP_CALLBACK (only mozilla SDK?)
#define TEST_LDAP_HOST "192.168.1.179"
#define TEST_LDAP_PORT LDAP_PORT //default 389
#define TEST_LDAP_BASE_DN "dc=aaa,dc=test,dc=mbohun"
#define TEST_LDAP_USER_DN "cn=Administrator,cn=Users,dc=aaa,dc=test,dc=mbohun"
#define TEST_LDAP_USER_PASSWORD "abcABC666"
#define TEST_LDAP_FILTER "(sAMAccountName=tim)"
#define TEST_LDAP_TCP_TIMEOUT 12 //seconds
#define TEST_LDAP_REFERRAL_FILTER "ldap://ref.aaa.test.mbohun/DC=ref,DC=aaa,DC=test,DC=mbohun"
int dummy = 0;
/*
suggestions:
* add referrals filter (easy) (a set of referral URL to follow, ignore rest)
*/
//simple filter for now, of course this is just a concept, we will have a proper set of URLs
static int is_valid_referral_url(const char* url) {
return (0 == strncmp(TEST_LDAP_REFERRAL_FILTER, url, sizeof(TEST_LDAP_REFERRAL_FILTER)));
}
static int rebind_callback (LDAP* h,
const char* url,
ber_tag_t req,
ber_int_t msgid,
void *args) { //use args instead of global vars!!!
/*
//check referral url against filter
if (!is_valid_referral_url(url)) {
std::cout << "rebind_callback, skipping:" << url << std::endl;
return LDAP_SUCCESS;
} else {
std::cout << "rebind_callback, match:" << url << std::endl;
}
*/
//NOTE: synchronous bind
const int r = ldap_simple_bind_s(h,
TEST_LDAP_USER_DN,
TEST_LDAP_USER_PASSWORD);
/*
std::cout << "rebind_callback:" << r
<< ", (LDAP_SUCCESS=" << LDAP_SUCCESS << ")"
<< std::endl;
*/
//TODO: handle error
return r;
}
int get_device_serial_number (void* args);
//DWORD WINAPI get_device_serial_number (LPVOID args);
int main(int argc, char* argv[]) {
//spawn 100 threads and search for device id for a given user
char* users[] = {"billy", "bob", "cal", "danny", "elm", "matt",
"tammy", "ted", "tim", "tom", "tony", "trevor"
};
const int i = (int)(11.0*rand()/(RAND_MAX+1.0));
get_device_serial_number(users[i]);
/*
HANDLE threads[100];
DWORD thread_id[100];
memset(threads, 0, sizeof(threads)/sizeof(threads[0]));
for (int t = 0; t < 100; t++ ) {
const int i = (int)(11.0*rand()/(RAND_MAX+1.0));
threads[t] = CreateThread(NULL,
0,
get_device_serial_number,
users[i],
0,
&thread_id[t]);
}
WaitForMultipleObjects(100, threads, TRUE, INFINITE);
*/
return 0;
}
// char* result = 0;
// get_device_serial_number(argv[1], &result);
// if (0 == result) {
// return -1;
// }
// std::cout << argv[1] << ":" << result << std::endl;
// free (result);
int get_device_serial_number (void* args) {
//DWORD WINAPI get_device_serial_number (LPVOID args) {
char* username = (char*)args;
std::stringstream ss;
ss << "(sAMAccountName=";
ss << username;
ss << ")";
std::string s = ss.str();
const char* search_filter = s.c_str();
//std::cout << "using search filter:" << search_filter << std::endl;
LDAP* h = ldap_init(TEST_LDAP_HOST, TEST_LDAP_PORT);
if (NULL == h) {
perror("ldap_init");
return -1;
}
int v = LDAP_VERSION3;
ldap_set_option(h, LDAP_OPT_PROTOCOL_VERSION, &v);
struct timeval t = {TEST_LDAP_TCP_TIMEOUT, 0};
ldap_set_option(h, LDAP_OPT_NETWORK_TIMEOUT, &t);
//Question: How does automatic following of referrals mix with synchronous search?
ldap_set_option(h, LDAP_OPT_REFERRALS, LDAP_OPT_ON); //LDAP_OPT_ON (default?) / LDAP_OPT_OFF
ldap_set_rebind_proc(h, rebind_callback, &dummy); //OpenLDAP SDK
if (ldap_simple_bind_s(h, TEST_LDAP_USER_DN, TEST_LDAP_USER_PASSWORD) != LDAP_SUCCESS ) {
ldap_perror(h, "ldap_simple_bind_s" );
return -1;
}
LDAPMessage* res =0;
char* attribute_filter[] = {"sAMAccountType", NULL };
int rc;
for (int retry = 0; retry < 3; retry++) {
// unfortunatelly this is returning sometimes
// "ldap_search_ext_s: Operations error"
rc = ldap_search_ext_s(h,
TEST_LDAP_BASE_DN,
LDAP_SCOPE_SUBTREE, //scope: LDAP_SCOPE_BASE, LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE
search_filter,
attribute_filter, //NOTE: for now return all attributes (NULL), later fix m_ppLdapQueryAttribName,
0,
NULL,
NULL,
&t,// LDAP_NO_LIMIT,
0, // LDAP_NO_LIMIT,
&res);
if (LDAP_SUCCESS != rc) {
if (retry < 2) {
std::cerr << "ldap_search_ext_s:" << ldap_err2string(rc)
<< ", attempt:" << retry
<< std::endl;
continue;
}
std::cerr << "ldap_search_ext_s:" << ldap_err2string(rc)
<< std::endl;
ldap_unbind_s(h);
return -1;
} else {
break;
}
}
int done = 0;
for (LDAPMessage* msg = ldap_first_message(h, res);
((0 == done) && (NULL!= msg));
msg = ldap_next_message(h, msg) ) {
char* dn = 0;
int msgtype = ldap_msgtype(msg);
switch (msgtype) {
case LDAP_RES_SEARCH_ENTRY:
//std::cout << "LDAP_RES_SEARCH_ENTRY" << std::endl;
BerElement* ber;
LDAPMessage* entry;
entry = ldap_first_entry(h, res);
for (char* a = ldap_first_attribute(h, entry, &ber);
a != NULL;
a = ldap_next_attribute(h, entry, ber) ) {
char** vals;
if (NULL != (vals = ldap_get_values(h, entry, a))) {
for (int i = 0; vals[i] != NULL; i++ ) {
std::cout << username;
std::cout << ":" << vals[i] << std::endl; //fix this
}
ldap_value_free(vals);
}
ldap_memfree(a);
}
if (ber != NULL) {
ber_free(ber, 0);
}
done = 1;
break;
case LDAP_RES_SEARCH_REFERENCE:
// we are not using manual processing of referrals
//std::cout << "LDAP_RES_SEARCH_REFERENCE (ignored)" << std::endl;
break;
case LDAP_RES_SEARCH_RESULT:
//std::cout << "LDAP_RES_SEARCH_RESULT" << std::endl;
char* matched_msg;
char* error_msg;
char** referrals;
LDAPControl** serverctrls;
int parse_result_rc;
parse_result_rc = ldap_parse_result(h,
msg,
&rc,
&matched_msg,
&error_msg,
&referrals, //
&serverctrls,
1); //freeit: 0=don't free, 1=free
if (LDAP_SUCCESS != parse_result_rc) {
std::cerr << "ldap_parse_result:"
<< ldap_err2string(parse_result_rc)
<< std::endl;
ldap_unbind(h);
return -1;
}
/*
// Check the results of the LDAP search operation.
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_search_ext: %s\n", ldap_err2string( rc ) );
if ( error_msg != NULL & *error_msg != '\0' ) {
fprintf( stderr, "%s\n", error_msg );
}
if ( matched_msg != NULL && *matched_msg != '\0' ) {
fprintf( stderr, "Part of the DN that matches an existing entry: %s\n", matched_msg );
}
} else {
printf( "Search completed successfully.\n"
"Entries found: %d\n"
"Search references returned: %d\n",
num_entries, num_refs );
}
*/
//it should finish anyway because we are at the end of a for loop
done = 1;
break;
default: //well?
std::cout << "default?" << std::endl;
break;
}
}
ldap_unbind_s(h);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment