Ldap Search on the host server - active-directory

I developed a small C++ application to bind a user in a server using active directory then return the name of his group.
The probleme is when I run the application from a remote computer, it run with no probleme. When I try to run it at the host server, -the computer hosting the active directory- the binding process pass, but the searching function always return Operation error: this is a sample of my code.
if ((rc = ldap_simple_bind_s( ld, loginDN, password )) != LDAP_SUCCESS )
{
printf("ldap_simple_bind_s: %s\n", ldap_err2string( rc ));
ldap_unbind_s( ld );
return 10;
}
printf("Bind and authentication to the server successful\n");
string a="(&(objectclass=person)(cn="+prenom+" "+nom+"))";
rc = ldap_search_ext_s(
ld, /* LDAP session handle */
searchBase, /* container to search */
LDAP_SCOPE_ONELEVEL, /* search scope */
a.c_str(), /*search filter*/
NULL, /* return all attributes */
0, /* return attributes and values */
NULL, /* server controls */
NULL, /* client controls */
&timeOut, /* search timeout */
LDAP_NO_LIMIT, /* no size limit */
&searchResult ); /* returned results */
if ( rc != LDAP_SUCCESS )
{
cout<<rc<<endl;
printf("ldap_search_ext_s: %s\n", ldap_err2string( rc ));
ldap_msgfree( searchResult );
ldap_unbind_s( ld );
return 20 ;
}

I found the answer I must use the port 3268 instead of 389

Related

On linux, when performing a socket bind with port 0 (pick a random port) using C, I get errno 98, Address already in use. How is that possible?

So, we have a long standing commercial product, that is well established and I've never seen this type of issue before. We use a client program to send data to a server. Sometimes, because of firewalls in customer environments, we allow the end user to specify outbound port ranges to bind, however, in this particular issue i'm seeing, we're not doing that, and are using port 0 to perform a bind. From everything i've read, this means to pick a random port. But what I can't find out is, what does that mean to the kernel/OS. If i'm asking for a random port, how can that already be in use?
Strictly speaking, only the unique pairing of src ip/src port & dst ip/port make the connection unique. I believe the same port can be used, if talking to another destination ip, but maybe that's not relevant here.
Also, this doesn't happen on all the customer's systems, only some. So, this may be some form of load related issue. The systems are fairly busy i'm told.
Here is the code we're using. I left out some of the ifdef code for windows, and left out what we do after the bind for shortness.
_SocketCreateClient(Socket_pwtP sock, SocketInfoP sInfo )
{
int nRetries; /* number of times to try connect() */
unsigned short port;
BOOL success = FALSE;
BOOL gotaddr = FALSE;
char buf[INET6_ADDRSTRLEN] ="";
int connectsuccess =1;
int ipv6compat =0;
#ifdef SOCKET_SEND_TIMEOUT
struct timeval time;
#endif /* SOCKET_SEND_TIMEOUT */
nRetries = sInfo->si_nRetries;
sock->s_hostName = strdup(sInfo->si_hostName);
#ifdef DEBUG_SOCKET
LogWrite(LogF,LOG_WARNING,"Socket create client");
LogWrite(LogF,LOG_WARNING,"Number of retries = %d", nRetries);
#endif
ipv6compat = GetIPVer();
if (ipv6compat == -1) /* ipv6 not supported */
gotaddr = GetINAddr(sInfo->si_hostName, &sock->s_sAddr.sin_addr);
else
gotaddr = GetINAddr6(sInfo->si_hostName, &sock->s_sAddr6.sin6_addr);
/* translate supplied host name to an internet address */
if (!gotaddr) {
/* print this message only once */
if ( sInfo->si_logInfo && ( sInfo->si_nRetries == 1 ) )
{
LogWrite(LogF, LOG_ERR,
"unable to resolve ip address for host '%s'", sInfo->si_hostName);
}
sock = _SocketDestroy(sock);
}
else {
if (ipv6compat == 1) /* ipv6 supported */
{
/* try to print the address in sock->s_sAddr6.sin6_addr to make sure it's good. from call above */
LogWrite(LogF, LOG_DEBUG2, "Before call to inet_ntop");
inet_ntop(AF_INET6, &sock->s_sAddr6.sin6_addr, buf, sizeof(buf));
LogWrite (LogF, LOG_DEBUG2, "Value of sock->s_sAddr6.sin6_addr from GetINAddr6: %s", buf);
LogWrite (LogF, LOG_DEBUG2, "Value of sock->s_sAddr6.sin6_scope_id from if_nametoindex: %d", sock->s_sAddr6.sin6_scope_id);
LogWrite (LogF, LOG_DEBUG2, "Value of sock->s_type: %d", sock->s_type);
}
/* try to create the socket nRetries times */
while (sock && sock->s_id == INVALID_SOCKET) {
int socketsuccess = FALSE;
/* create the actual socket */
if (ipv6compat == -1) /* ipv6 not supported */
socketsuccess = sock->s_id = socket(AF_INET, sock->s_type, 0);
else
socketsuccess = sock->s_id = socket(AF_INET6, sock->s_type, 0);
if ((socketsuccess) == INVALID_SOCKET) {
GETLASTERROR;
LogWrite(LogF, LOG_ERR, "unable to create socket: Error %d: %s", errno,
strerror(errno) );
sock = _SocketDestroy(sock);
}
else
{
/* cycle through outbound port range for firewall support */
port = sInfo->si_startPortRange;
while ( !success && port <= sInfo->si_endPortRange ) {
int bindsuccess = 1;
/* bind to outbound port number */
if ( ipv6compat == -1) /* ipv6 not supported */
{
sock->s_sourceAddr.sin_port = htons(port);
bindsuccess = bind(sock->s_id, (struct sockaddr *) &sock->s_sourceAddr,
sizeof(sock->s_sourceAddr));
}
else {
sock->s_sourceAddr6.sin6_port = htons(port);
inet_ntop(AF_INET6, &sock->s_sourceAddr6.sin6_addr, buf, sizeof(buf));
LogWrite(LogF, LOG_DEBUG,
"attempting bind to s_sourceAddr6 %s ", buf);
bindsuccess = bind(sock->s_id, (struct sockaddr *) &sock->s_sourceAddr6,
sizeof(sock->s_sourceAddr6));
}
if (bindsuccess == -1) {
GETLASTERROR;
LogWrite(LogF, LOG_ERR,
"unable to bind port %d to socket: Error %d: %s. Will attempt next port if protomgr port rules configured(EAV_PORTS).", port, errno, strerror(errno) );
/* if port in use, try next port number */
port++;
}
else {
/* only log if outbound port was specified */
if (port != 0)
{
if ( sInfo->si_sourcehostName ) {
LogWrite(LogF, LOG_DEBUG,
"bound outbound address %s:%d to socket",
sInfo->si_sourcehostName, port);
}
else {
LogWrite(LogF, LOG_DEBUG,
"bound outbound port %d to socket", port);
}
}
success = TRUE;
}
}
}
}
}
return(sock);
}
The errors we're seeing in our log file look like this. It's making 2 tries and both fail:
protomgr[628453] : ERROR: unable to bind port 0 to socket: Error 98: Address already in use. Will attempt next port if protomgr port rules configured(EAV_PORTS).
protomgr[628453] : ERROR: unable to bind port(s) to socket: Error 98: Address already in use. Consider increase the number of EAV_PORTS if this msg is from protomgr.
protomgr[628453] : ERROR: unable to bind port 0 to socket: Error 98: Address already in use. Will attempt next port if protomgr port rules configured(EAV_PORTS).
protomgr[628453] : ERROR: unable to bind port(s) to socket: Error 98: Address already in use. Consider increase the number of EAV_PORTS if this msg is from protomgr.
So, it looks like this was related to the system running out of available ports, and it being configured to only have about 9000 port available.
This setting, in /etc/sysctl.conf controls the available ports:
net.ipv4.ip_local_port_range = 9000 65500
the first number is the starting port, and the second is the max. This example was pulled from a unaltered Suse Enterprise linux server 11.0.
The customer of ours who reported this problem had their configured in such a way it only had around 9000 ports available in the range they defined, and all were used on the system.
Hopefully, this helps someone else in the future.

Linphone registration and placing call using C API (Windows)

Could you please help me with next question.
I'm trying to make registration and place call with Linphone thru C API (Windows).
I can separately successfully register with local SIP server using this tutorial
Basic registration , but I don't know how to place a call after registration using this tutorial Basic call.
The problem is that Basic registration code contains eternal loop executing while application is running:
while (running){
linphone_core_iterate(lc); /* first iterate initiates registration */
ms_usleep(50000);
}
and Basic call code also contains eternal loop executing while application is running:
while(running){
linphone_core_iterate(lc);
ms_usleep(50000);
}
If to place Basic call code into first loop, program will try to place call again and again. How to make registration, and then place a call? Could you help me with that? Thanks.
My unworking code:
#ifdef IN_LINPHONE
#include "linphonecore.h"
#else
#include "linphone/linphonecore.h"
#endif
#include <signal.h>
static bool_t running = TRUE;
static void stop(int signum){
running = FALSE;
}
/*
* Call state notification callback
*/
static void call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate, const char *msg){
switch (cstate){
case LinphoneCallOutgoingRinging:
printf("It is now ringing remotely !\n");
break;
case LinphoneCallOutgoingEarlyMedia:
printf("Receiving some early media\n");
break;
case LinphoneCallConnected:
printf("We are connected !\n");
break;
case LinphoneCallStreamsRunning:
printf("Media streams established !\n");
break;
case LinphoneCallEnd:
printf("Call is terminated.\n");
break;
case LinphoneCallError:
printf("Call failure !");
break;
default:
printf("Unhandled notification %i\n", cstate);
}
}
static void registration_state_changed(struct _LinphoneCore *lc, LinphoneProxyConfig *cfg, LinphoneRegistrationState cstate, const char *message){
printf("New registration state %s for user id [%s] at proxy [%s]\n"
, linphone_registration_state_to_string(cstate)
, linphone_proxy_config_get_identity(cfg)
, linphone_proxy_config_get_addr(cfg));
}
LinphoneCore *lc;
int main(int argc, char *argv[]){
LinphoneCoreVTable vtable = { 0 };
LinphoneCore *lc;
LinphoneCall *call = NULL;
const char *dest = "sip:sip2#officesip.local";
LinphoneProxyConfig* proxy_cfg;
LinphoneAddress *from;
LinphoneAuthInfo *info;
char* identity = "sip:sip#officesip.local";
char* password = "sip";
const char* server_addr;
/* takes sip uri identity from the command line arguments */
/*if (argc>1){
identity = argv[1];
}
/* takes password from the command line arguments */
/*if (argc>2){
password = argv[2];
}
*/
//signal(SIGINT, stop);
#ifdef DEBUG
linphone_core_enable_logs(NULL); /*enable liblinphone logs.*/
#endif
/*
Fill the LinphoneCoreVTable with application callbacks.
All are optional. Here we only use the registration_state_changed callbacks
in order to get notifications about the progress of the registration.
*/
vtable.registration_state_changed = registration_state_changed;
vtable.call_state_changed = call_state_changed;
/*
Instanciate a LinphoneCore object given the LinphoneCoreVTable
*/
lc = linphone_core_new(&vtable, NULL, NULL, NULL);
/*create proxy config*/
proxy_cfg = linphone_proxy_config_new();
/*parse identity*/
from = linphone_address_new(identity);
if (from == NULL){
printf("%s not a valid sip uri, must be like sip:toto#sip.linphone.org \n", identity);
goto end;
}
if (password != NULL){
info = linphone_auth_info_new(linphone_address_get_username(from), NULL, password, NULL, NULL, NULL); /*create authentication structure from identity*/
linphone_core_add_auth_info(lc, info); /*add authentication info to LinphoneCore*/
}
// configure proxy entries
linphone_proxy_config_set_identity(proxy_cfg, identity); /*set identity with user name and domain*/
server_addr = linphone_address_get_domain(from); /*extract domain address from identity*/
//linphone_proxy_config_set_server_addr(proxy_cfg, server_addr); /* we assume domain = proxy server address*/
linphone_proxy_config_set_server_addr(proxy_cfg, "localhost");
linphone_proxy_config_enable_register(proxy_cfg, TRUE); /*activate registration for this proxy config*/
linphone_address_destroy(from); /*release resource*/
linphone_core_add_proxy_config(lc, proxy_cfg); /*add proxy config to linphone core*/
linphone_core_set_default_proxy(lc, proxy_cfg); /*set to default proxy*/
/* main loop for receiving notifications and doing background linphonecore work: */
while (running){
linphone_core_iterate(lc); /* first iterate initiates registration */
ms_usleep(50000);
//------------------------------------------------------------------------------------------------------
//HERE I'M TRYING TO PLACE A CALL INSIDE LOOP
//------------------------------------------------------------------------------------------------------
if (dest){
/*
Place an outgoing call
*/
call = linphone_core_invite(lc, dest);
if (call == NULL){
printf("Could not place call to %s\n", dest);
goto end;
}
else printf("Call to %s is in progress...", dest);
linphone_call_ref(call);
}
//------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
}
linphone_core_get_default_proxy(lc, &proxy_cfg); /* get default proxy config*/
linphone_proxy_config_edit(proxy_cfg); /*start editing proxy configuration*/
linphone_proxy_config_enable_register(proxy_cfg, FALSE); /*de-activate registration for this proxy config*/
linphone_proxy_config_done(proxy_cfg); /*initiate REGISTER with expire = 0*/
while (linphone_proxy_config_get_state(proxy_cfg) != LinphoneRegistrationCleared){
linphone_core_iterate(lc); /*to make sure we receive call backs before shutting down*/
ms_usleep(50000);
}
end:
printf("Shutting down...\n");
linphone_core_destroy(lc);
printf("Exited\n");
return 0;
}
Here is the solution from this example, use:
/* Loop until registration is OK */
do {
linphone_core_iterate(lc); /* first iterate initiates registration */
ms_usleep(100000);
} while (running && linphone_proxy_config_get_state(proxy_cfg) == LinphoneRegistrationProgress);
instead of:
while (running){
linphone_core_iterate(lc); /* first iterate initiates registration */
ms_usleep(50000);
}
After that I can call and send\receive text messages.

openLDAP c client protocol error (ldap_simple_bind_s: Protocol error)

I am trying to connect to openLDAP server using c program, I found openLDAP client library and I implement the following program. and I try to connect to this ldap server as well as my local ldap server.
I compile the program with no error using this command
gcc ldapClient.c -o ldapClient -lldap
and I try to run the program using this command
./ldapClient euler password
then it says
ldap_simple_bind_s: Protocol error
I googled and found some answers like this ,they say this error come with protocol version miss match e.i: LDAPv2 and LDAPv3 , but I couldn't able to fine how to solve this problem
#include <stdio.h>
#include <ldap.h>
/* LDAP Server settings */
#define LDAP_SERVER "ldap://ldap.forumsys.com:389"
int
main( int argc, char **argv )
{
LDAP *ld;
int rc;
char bind_dn[100];
/* Get username and password */
if( argc != 3 )
{
perror( "invalid args, required: username password" );
return( 1 );
}
sprintf( bind_dn, "cn=%s,ou=mathematicians,dc=example,dc=com", argv[1] );
printf( "Connecting as %s...\n", bind_dn );
/* Open LDAP Connection */
if( ldap_initialize( &ld, LDAP_SERVER ) )
{
perror( "ldap_initialize" );
return( 1 );
}
/* User authentication (bind) */
rc = ldap_simple_bind_s( ld, bind_dn, argv[2] );
if( rc != LDAP_SUCCESS )
{
fprintf(stderr, "ldap_simple_bind_s: %s\n", ldap_err2string(rc) );
return( 1 );
}
printf( "Successful authentication\n" );
ldap_unbind( ld );
return( 0 );
}
After calling ldap_initialize you need to set the protocol type, using:
int protocol_version = LDAP_VERSION3;
rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &protocol_version);
if (rc != LDAP_SUCCESS) {
fprintf(stderr, "ldap_simple_bind_s: %s\n", ldap_err2string(rc));
return(1);
}

How to set connection timeout and operation timeout in OpenSSL

libcurl has timeout options like these:
CURLOPT_CONNECTTIMEOUT - maximum time in seconds that you allow the connection to the server to take.
CURLOPT_TIMEOUT - maximum time in seconds that you allow the libcurl transfer operation to take.
I'd like to implement a similar timeout mechanism in OpenSSL.
What changes would be required in the code below so that a timeout value is applied to BIO_do_connect(), BIO_write() and BIO_read()?
I'm connecting to a server and sending/receiving data to/from the server using BIO_write()/BIO_read() that OpenSSL provides. My code is based on the following sample code available from here.
int main()
{
BIO * bio;
SSL * ssl;
SSL_CTX * ctx;
int p;
char * request = "GET / HTTP/1.1\x0D\x0AHost: www.verisign.com\x0D\x0A\x43onnection: Close\x0D\x0A\x0D\x0A";
char r[1024];
/* Set up the library */
ERR_load_BIO_strings();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
/* Set up the SSL context */
ctx = SSL_CTX_new(SSLv23_client_method());
/* Load the trust store */
if(! SSL_CTX_load_verify_locations(ctx, "TrustStore.pem", NULL))
{
fprintf(stderr, "Error loading trust store\n");
ERR_print_errors_fp(stderr);
SSL_CTX_free(ctx);
return 0;
}
/* Setup the connection */
bio = BIO_new_ssl_connect(ctx);
/* Set the SSL_MODE_AUTO_RETRY flag */
BIO_get_ssl(bio, & ssl);
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
/* Create and setup the connection */
BIO_set_conn_hostname(bio, "www.verisign.com:https");
if(BIO_do_connect(bio) <= 0)
{
fprintf(stderr, "Error attempting to connect\n");
ERR_print_errors_fp(stderr);
BIO_free_all(bio);
SSL_CTX_free(ctx);
return 0;
}
/* Check the certificate */
if(SSL_get_verify_result(ssl) != X509_V_OK)
{
fprintf(stderr, "Certificate verification error: %i\n", SSL_get_verify_result(ssl));
BIO_free_all(bio);
SSL_CTX_free(ctx);
return 0;
}
/* Send the request */
BIO_write(bio, request, strlen(request));
/* Read in the response */
for(;;)
{
p = BIO_read(bio, r, 1023);
if(p <= 0) break;
r[p] = 0;
printf("%s", r);
}
/* Close the connection and free the context */
BIO_free_all(bio);
SSL_CTX_free(ctx);
return 0;
}
I'm cross-compiling for ARM on Ubuntu (Eclipse with CodeSourcery Lite).
I ended up doing something like the following (pseudocode):
int nRet;
int fdSocket;
fd_set connectionfds;
struct timeval timeout;
BIO_set_nbio(pBio, 1);
nRet = BIO_do_connect(pBio);
if ((nRet <= 0) && !BIO_should_retry(pBio))
// failed to establish connection.
if (BIO_get_fd(pBio, &fdSocket) < 0)
// failed to get fd.
if (nRet <= 0)
{
FD_ZERO(&connectionfds);
FD_SET(fdSocket, &connectionfds);
timeout.tv_usec = 0;
timeout.tv_sec = 10;
nRet = select(fdSocket + 1, NULL, &connectionfds, NULL, &timeout);
if (nRet == 0)
// timeout has occurred.
}
You can use the same approach for BIO_read() too.
You might find this link useful.
For connecting, #jpen gave the best answer there. You have to mark the BIO as non-blocking and use select for determining whether it connected and/or timed out.
Reads are a little different. Because OpenSSL may buffer decrypted data (depending on the TLS cipher suite used), select may timeout when you are trying to read - even if data actually is available. The proper way to handle read timeouts is to first check SSL_pending or BIO_pending. If the pending function returns zero, then use select to set a timeout. If the pending function returns greater than zero, then just call SSL_read or BIO_read or any other read function.
Take a look at SSL_CTX_set_timeout () function, which does similar to libcurl's CURLOPT_TIMEOUT variable:
From http://www.openssl.org/docs/ssl/SSL_CTX_set_timeout.html :
SSL_CTX_set_timeout() sets the timeout for newly created sessions for ctx to t. The timeout value t must be given in seconds.
In your case you could add the following line after you create ctx object:
SSL_CTX_set_timeout (ctx, 60);
Hope it helps !

Verifying self-signed/expired certificate with openssl library does not return error

I am trying to write a certificate validation function in C using the openssl library. Since the certificate I am validating is self-signed and expired, I expect the X509_verify_cert() to return error (the return value is 1 and the store_ctx->error is set to X509_V_OK instead). 'openssl verify my_pem_cert_file' outputs:
error 18 at 0 depth lookup:self signed certificate
error 10 at 0 depth lookup:certificate has expired
What I am doing wrong? Here is my code:
static int cert_verify_callback(int ok, X509_STORE_CTX *ctx)
{
/* Tolerate self-signed certificate */
if (X509_STORE_CTX_get_error(ctx) == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) {
return 1;
}
/* Otherwise don't override */
return ok;
}
int cert_validate(const char* certFileName)
{
BIO *pBio = NULL;
X509 *pX509 = NULL;
X509 *CA = NULL;
X509_STORE *cert_store = NULL;
X509_STORE_CTX *store_ctx = NULL;
STACK_OF(X509) *stack_of_x509 = NULL;
time_t check_time;
int store_ctx_error;
int store_ctx_error_depth;
pBio = BIO_new( BIO_s_file_internal() );
if(pBio == NULL)
/* error handling */
if(BIO_read_filename(pBio, certFileName) <= 0)
/* error handling */
pX509 = PEM_read_bio_X509(pBio, NULL, NULL, NULL);
if (pX509 == NULL)
/* error handling */
if( (cert_store= X509_STORE_new()) == NULL)
/* error handling */
if( (store_ctx= X509_STORE_CTX_new()) == NULL)
/* error handling */
/* edit1: this was wrong: don't add the certificate being verified to the trusted cert list */
/* if( !X509_STORE_add_cert(cert_store, pX509) ) */
/* error handling */
if( !X509_STORE_CTX_init(store_ctx, cert_store, CA, stack_of_x509) )
/* error handling */
X509_STORE_CTX_set_cert(store_ctx, pX509);
/* edit1: this was missing: set the verify time in order to check the certificate for expiry */
time(&check_time);
X509_STORE_CTX_set_time(store_ctx, 0, check_time);
X509_STORE_CTX_set_flags(store_ctx, X509_V_FLAG_USE_CHECK_TIME);
/* edit1: add callback function for ignoring self-signed error
* now, I'd like the validation to fail because of the expiry */
X509_STORE_set_verify_cb_func(store_ctx, cert_verify_callback);
switch( X509_verify_cert(store_ctx) ) {
/* the certificate is valid */
case 1:
printf("The certificate is valid\n");
break;
/* the certificate cannot be validated */
case -1:
case 0:
printf("The certificate is not valid\n");
store_ctx_error= X509_STORE_CTX_get_error(store_ctx);
store_ctx_error_depth= X509_STORE_CTX_get_error_depth(store_ctx);
printf("Error %d at %d depth: %s\n", store_ctx_error, store_ctx_error_depth, X509_verify_cert_error_string(store_ctx->error));
default:
break;
}
/* free data ... */
}
When validating the self-signed and expired certificate, my function prints:
Error 0 at 0 depth: ok
The function X509_STORE_add_cert() adds the corresponding certificate as a trusted certificate for verification, so this line:
X509_STORE_add_cert(cert_store, pX509)
says that your pX509 certificate is trusted for verification - but that's the certificate you want to test, so that's why a self-signed certificate is passing verification.
You also aren't setting a verification time - that's why an expired certificate is not being detected. Set the verification time with X509_STORE_CTX_set_time().

Resources