LDAP Authentication, ldap_sasl_bind_s not working but ldap_simple_bind_s works - objective-c

I have a problem where in ldap_sasl_bind_s does not work, but ldap_simple_bind_s works.
The strange thing is, ldap_sasl_bind_s works even with wrong passwords and gives user the feeling that he has entered a correct password.
PFA code snippet of the problem and suggest me if anything is wrong with my approach.
{
int rc, aReturnVal = 0;
NSString *aUserDN = [NSString stringWithFormat:#"uid=%s,cn=users,dc=example,dc=com", username];
char* userDN = (char*)[aUserDN UTF8String];
rc = ldap_simple_bind_s (
ld,
userDN,
password
);
// TODO: ldap_simple_bind_s is a deprecated method and should not be used for long. ldap_sasl_bind_s is the right method, but is not working for now.
// Find the reason and get this code up and running.
// struct berval *servcred;
// struct berval cred;
// cred.bv_val = password; // my password
// cred.bv_len = strlen(password);
// rc = ldap_sasl_bind_s (
// ld,
// userDN,
// "DIGEST-MD5",
// &cred,
// NULL,
// NULL,
// &servcred
// );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_sasl_bind: %s\n", ldap_err2string( rc ) );
} else {
aReturnVal = 1;
}
return aReturnVal;
}
I have initialized the LDAP using following code SNIP:
rc = ldap_initialize(&ld, HOSTNAME);
version = LDAP_VERSION3;
ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
ldap_set_option( ld, LDAP_OPT_REFERRALS, 0 );
I need to be able to login with correct user name and when user tries to enter wrong user name, ldap should say so.
I have referred to following links and their related links to get to this conclusion:
LDAP - How to check a username/password combination?
How to do password authentication for a user using LDAP?

Digest-MD5 auth is more complicated than just sending a bind DN and password. You'll need to use ldap_sasl_interactive_bind_s and provide a callback so the SASL library can combine your credentials with the server-provided nonce.
This code (adapted from this blog post) works for me against an Active Directory server:
#include <stdio.h>
#include <stdlib.h>
#include <ldap.h>
#include <sasl/sasl.h>
typedef struct
{
char *username;
char *password;
} my_authdata;
int my_sasl_interact(LDAP *ld, unsigned flags, void *defaults, void *in)
{
my_authdata *auth = (my_authdata *)defaults;
sasl_interact_t *interact = (sasl_interact_t *)in;
if(ld == NULL) return LDAP_PARAM_ERROR;
while(interact->id != SASL_CB_LIST_END)
{
char *dflt = (char *)interact->defresult;
switch(interact->id)
{
case SASL_CB_GETREALM:
dflt = NULL;
break;
case SASL_CB_USER:
case SASL_CB_AUTHNAME:
dflt = auth->username;
break;
case SASL_CB_PASS:
dflt = auth->password;
break;
default:
printf("my_sasl_interact asked for unknown %ld\n",interact->id);
}
interact->result = (dflt && *dflt) ? dflt : (char *)"";
interact->len = strlen((char *)interact->result);
interact++;
}
return LDAP_SUCCESS;
}
int main(int argc, char *argv[])
{
if(argc < 3)
{
fprintf(stderr, "Usage: dmd5-bind [username] [password]\n");
return -1;
}
int rc;
LDAP *ld = NULL;
static my_authdata auth;
auth.username = argv[1];
auth.password = argv[2];
char *sasl_mech = ber_strdup("DIGEST-MD5");
char *ldapuri = ber_strdup("ldap://your.server.name.here");
int protocol = LDAP_VERSION3;
unsigned sasl_flags = LDAP_SASL_QUIET;
char *binddn = NULL;
rc = ldap_initialize(&ld, ldapuri);
if(rc != LDAP_SUCCESS)
{
fprintf(stderr, "ldap_initialize: %s\n", ldap_err2string(rc));
return rc;
}
if(ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &protocol) != LDAP_OPT_SUCCESS)
{
fprintf(stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n", protocol);
return -1;
}
rc = ldap_sasl_interactive_bind_s(ld,
binddn,
sasl_mech,
NULL,
NULL,
sasl_flags,
my_sasl_interact,
&auth);
if(rc != LDAP_SUCCESS)
{
ldap_perror(ld, "ldap_sasl_interactive_bind_s");
ldap_unbind_ext_s(ld, NULL, NULL);
return rc;
}
fprintf(stdout, "Authentication succeeded\n");
rc = ldap_unbind_ext_s(ld, NULL, NULL);
sasl_done();
sasl_client_init(NULL);
return rc;
}

Related

How to change this app to disable input from command line?

This is the Original code:
#include <stdio.h>
#include <string.h>
#include <assert.h>
#if defined(_WIN32) && !defined(__CYGWIN__)
#include <windows.h>
#else
#include <sys/select.h>
#endif
#include <sphinxbase/err.h>
#include <sphinxbase/ad.h>
#include "pocketsphinx.h"
static const arg_t cont_args_def[] = {
POCKETSPHINX_OPTIONS,
/* Argument file. */
{"-argfile",
ARG_STRING,
NULL,
"Argument file giving extra arguments."},
{"-adcdev",
ARG_STRING,
NULL,
"Name of audio device to use for input."},
{"-infile",
ARG_STRING,
NULL,
"Audio file to transcribe."},
{"-inmic",
ARG_BOOLEAN,
"no",
"Transcribe audio from microphone."},
{"-time",
ARG_BOOLEAN,
"no",
"Print word times in file transcription."},
CMDLN_EMPTY_OPTION
};
static ps_decoder_t *ps;
static cmd_ln_t *config;
static FILE *rawfd;
static void
print_word_times()
{
int frame_rate = cmd_ln_int32_r(config, "-frate");
ps_seg_t *iter = ps_seg_iter(ps);
while (iter != NULL) {
int32 sf, ef, pprob;
float conf;
ps_seg_frames(iter, &sf, &ef);
pprob = ps_seg_prob(iter, NULL, NULL, NULL);
conf = logmath_exp(ps_get_logmath(ps), pprob);
printf("%s %.3f %.3f %f\n", ps_seg_word(iter), ((float)sf / frame_rate),
((float) ef / frame_rate), conf);
iter = ps_seg_next(iter);
}
}
static int
check_wav_header(char *header, int expected_sr)
{
int sr;
if (header[34] != 0x10) {
E_ERROR("Input audio file has [%d] bits per sample instead of 16\n", header[34]);
return 0;
}
if (header[20] != 0x1) {
E_ERROR("Input audio file has compression [%d] and not required PCM\n", header[20]);
return 0;
}
if (header[22] != 0x1) {
E_ERROR("Input audio file has [%d] channels, expected single channel mono\n", header[22]);
return 0;
}
sr = ((header[24] & 0xFF) | ((header[25] & 0xFF) << 8) | ((header[26] & 0xFF) << 16) | ((header[27] & 0xFF) << 24));
if (sr != expected_sr) {
E_ERROR("Input audio file has sample rate [%d], but decoder expects [%d]\n", sr, expected_sr);
return 0;
}
return 1;
}
/*
* Continuous recognition from a file
*/
static void
recognize_from_file()
{
int16 adbuf[2048];
const char *fname;
const char *hyp;
int32 k;
uint8 utt_started, in_speech;
int32 print_times = cmd_ln_boolean_r(config, "-time");
fname = cmd_ln_str_r(config, "-infile");
if ((rawfd = fopen(fname, "rb")) == NULL) {
E_FATAL_SYSTEM("Failed to open file '%s' for reading",
fname);
}
if (strlen(fname) > 4 && strcmp(fname + strlen(fname) - 4, ".wav") == 0) {
char waveheader[44];
fread(waveheader, 1, 44, rawfd);
if (!check_wav_header(waveheader, (int)cmd_ln_float32_r(config, "-samprate")))
E_FATAL("Failed to process file '%s' due to format mismatch.\n", fname);
}
if (strlen(fname) > 4 && strcmp(fname + strlen(fname) - 4, ".mp3") == 0) {
E_FATAL("Can not decode mp3 files, convert input file to WAV 16kHz 16-bit mono before decoding.\n");
}
ps_start_utt(ps);
utt_started = FALSE;
while ((k = fread(adbuf, sizeof(int16), 2048, rawfd)) > 0) {
ps_process_raw(ps, adbuf, k, FALSE, FALSE);
in_speech = ps_get_in_speech(ps);
if (in_speech && !utt_started) {
utt_started = TRUE;
}
if (!in_speech && utt_started) {
ps_end_utt(ps);
hyp = ps_get_hyp(ps, NULL);
if (hyp != NULL)
printf("%s\n", hyp);
if (print_times)
print_word_times();
fflush(stdout);
ps_start_utt(ps);
utt_started = FALSE;
}
}
ps_end_utt(ps);
if (utt_started) {
hyp = ps_get_hyp(ps, NULL);
if (hyp != NULL) {
printf("%s\n", hyp);
if (print_times) {
print_word_times();
}
}
}
fclose(rawfd);
}
/* Sleep for specified msec */
static void
sleep_msec(int32 ms)
{
#if (defined(_WIN32) && !defined(GNUWINCE)) || defined(_WIN32_WCE)
Sleep(ms);
#else
/* ------------------- Unix ------------------ */
struct timeval tmo;
tmo.tv_sec = 0;
tmo.tv_usec = ms * 1000;
select(0, NULL, NULL, NULL, &tmo);
#endif
}
/*
* Main utterance processing loop:
* for (;;) {
* start utterance and wait for speech to process
* decoding till end-of-utterance silence will be detected
* print utterance result;
* }
*/
static void
recognize_from_microphone()
{
ad_rec_t *ad;
int16 adbuf[2048];
uint8 utt_started, in_speech;
int32 k;
char const *hyp;
if ((ad = ad_open_dev(cmd_ln_str_r(config, "-adcdev"),
(int) cmd_ln_float32_r(config,
"-samprate"))) == NULL)
E_FATAL("Failed to open audio device\n");
if (ad_start_rec(ad) < 0)
E_FATAL("Failed to start recording\n");
if (ps_start_utt(ps) < 0)
E_FATAL("Failed to start utterance\n");
utt_started = FALSE;
E_INFO("Ready....\n");
for (;;) {
if ((k = ad_read(ad, adbuf, 2048)) < 0)
E_FATAL("Failed to read audio\n");
ps_process_raw(ps, adbuf, k, FALSE, FALSE);
in_speech = ps_get_in_speech(ps);
if (in_speech && !utt_started) {
utt_started = TRUE;
E_INFO("Listening...\n");
}
if (!in_speech && utt_started) {
/* speech -> silence transition, time to start new utterance */
ps_end_utt(ps);
hyp = ps_get_hyp(ps, NULL );
if (hyp != NULL) {
printf("%s\n", hyp);
fflush(stdout);
}
if (ps_start_utt(ps) < 0)
E_FATAL("Failed to start utterance\n");
utt_started = FALSE;
E_INFO("Ready....\n");
}
sleep_msec(100);
}
ad_close(ad);
}
int
main(int argc, char *argv[])
{
char const *cfg;
config = cmd_ln_parse_r(NULL, cont_args_def, argc, argv, TRUE);
/* Handle argument file as -argfile. */
if (config && (cfg = cmd_ln_str_r(config, "-argfile")) != NULL) {
config = cmd_ln_parse_file_r(config, cont_args_def, cfg, FALSE);
}
if (config == NULL || (cmd_ln_str_r(config, "-infile") == NULL && cmd_ln_boolean_r(config, "-inmic") == FALSE)) {
E_INFO("Specify '-infile <file.wav>' to recognize from file or '-inmic yes' to recognize from microphone.\n");
cmd_ln_free_r(config);
return 1;
}
ps_default_search_args(config);
ps = ps_init(config);
if (ps == NULL) {
cmd_ln_free_r(config);
return 1;
}
E_INFO("%s COMPILED ON: %s, AT: %s\n\n", argv[0], __DATE__, __TIME__);
if (cmd_ln_str_r(config, "-infile") != NULL) {
recognize_from_file();
} else if (cmd_ln_boolean_r(config, "-inmic")) {
recognize_from_microphone();
}
ps_free(ps);
cmd_ln_free_r(config);
return 0;
}
#if defined(_WIN32_WCE)
#pragma comment(linker,"/entry:mainWCRTStartup")
#include <windows.h>
//Windows Mobile has the Unicode main only
int
wmain(int32 argc, wchar_t * wargv[])
{
char **argv;
size_t wlen;
size_t len;
int i;
argv = malloc(argc * sizeof(char *));
for (i = 0; i < argc; i++) {
wlen = lstrlenW(wargv[i]);
len = wcstombs(NULL, wargv[i], wlen);
argv[i] = malloc(len + 1);
wcstombs(argv[i], wargv[i], wlen);
}
//assuming ASCII parameters
return main(argc, argv);
}
#endif
I can compile it by this command:
g++ -o output continuous.cpp -DMODELDIR=\"`pkg-config --variable=modeldir pocketsphinx`\" `pkg-config --cflags --libs pocketsphinx sphinxbase`
And run it by this command : output -inmic yes .
But I like to convert the code as it has no need to get inmic yes and it automatically starts the program from microphone. But I got segmentation fault(core dumped) error when I changed these parts:
static const arg_t cont_args_def= {"-inmic",
ARG_BOOLEAN,
"no",
"Transcribe audio from microphone."};
int main(int argc, char *argv[])
{
config = cmd_ln_parse_r(NULL, cont_args_def, argc, argv, TRUE);
if (cmd_ln_boolean_r(config, "-inmic")) {
recognize_from_microphone();
}
// recognize_from_microphone();
ps_free(ps);
cmd_ln_free_r(config);
return 0;
}
I searched a lot and red the documentation but couldn't understand what's the problem?
Change the last argument passed to cmd_ln_parse_r from TRUE to FALSE.
It has something to do with strict checking.
I figured this out by reading the source code for cmd_ln.c in the sphinxbase code.
I also changed the boolean value for -inmic in cont_args_def from "no" to "yes".

OpenLDAP - Enabling CRL check for LDAP TLS connections

I have a client that connects to LDAP server using TLS. For this connection, I want to enable CRL check and reject the connection only if any server/client certificates are revoked.
In special cases (like CRL missing, CRL expired) I want to ignore the error and establish the connection.
So I though to overwrite the default SSL verify call back to ignore the specific errors.
But the call back is not called at all. Always only default call-back is called.
Here is my call back:
static int verify_callback(int ok, X509_STORE_CTX *ctx)
{
X509* cert = X509_STORE_CTX_get_current_cert(ctx);
if (ok)
return ok;
int sslRet = X509_STORE_CTX_get_error(ctx);
const char* err = NULL;
switch (sslRet)
{
case X509_V_ERR_UNABLE_TO_GET_CRL:
case X509_V_ERR_CRL_HAS_EXPIRED:
case X509_V_ERR_CRL_NOT_YET_VALID:
printf( "CRL: Verification failed... but ignored : %d\n", sslRet);
return 1;
default:
err = X509_verify_cert_error_string(sslRet);
if (err)
printf( "CRL: Failed to verify : %s\n",err);
return 0;
}
return sslRet;
}
Default verify call-back is overwritten using the ldap call-back set option:
void ldap_tls_cb(LDAP * ld, SSL * ssl, SSL_CTX * ctx, void * arg)
{
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER , verify_callback);
printf("verify call back is set...\n");
return;
}
Main Program:
int main( int argc, char **argv )
{
LDAP *ldap;
int auth_method = LDAP_AUTH_SIMPLE; //LDAP_AUTH_SASL
int ldap_version = LDAP_VERSION3;
char *ldap_host = "10.104.40.35";
int ldap_port = 389;
if ( (ldap = ldap_init(ldap_host, ldap_port)) == NULL ) {
perror( "ldap_init failed" );
return( EXIT_FAILURE );
}
int result = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ldap_version);
if (result != LDAP_OPT_SUCCESS ) {
ldap_perror(ldap, "ldap_set_option failed!");
return(EXIT_FAILURE);
}
int requireCert = LDAP_OPT_X_TLS_DEMAND;
result = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &requireCert);
if (result != LDAP_OPT_SUCCESS ) {
ldap_perror(ldap, "ldap_set_option - req cert -failed!");
return(EXIT_FAILURE);
}
result = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, "/etc/certs/Cert.pem");
if (result != LDAP_OPT_SUCCESS ) {
ldap_perror(ldap, "ldap_set_option - cert file - failed!");
return(EXIT_FAILURE);
}
int crlvalue = LDAP_OPT_X_TLS_CRL_ALL;
result =ldap_set_option(NULL, LDAP_OPT_X_TLS_CRLCHECK, &crlvalue);
if (result != LDAP_OPT_SUCCESS ) {
ldap_perror(ldap, "ldap_set_option failed!");
return(EXIT_FAILURE);
}
int debug = 7;
ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &debug);
result = ldap_set_option(ldap, LDAP_OPT_X_TLS_CONNECT_CB, (void *)ldap_tls_cb);
if (result != LDAP_SUCCESS) {
fprintf(stderr, "ldap_set_option(LDAP_OPT_X_TLS_CONNECT_CB): %s\n", ldap_err2string(result));
return(1);
}
int msgidp = 0;
result = ldap_start_tls(ldap,NULL,NULL,&msgidp);
if (result != LDAP_OPT_SUCCESS ) {
ldap_perror(ldap, "start tls failed!");
return result;
} else {
printf("Start tls success.\n");
}
LDAPMessage *resultm;
struct timeval timeout;
result = ldap_result(ldap, msgidp, 0, &timeout, &resultm );
if ( result == -1 || result == 0 ) {
printf("ldap_result failed;retC=%d \n", result);
return result;
}
result = ldap_parse_extended_result(ldap, resultm, NULL, NULL, 0 );
if ( result == LDAP_SUCCESS ) {
result = ldap_install_tls (ldap);
printf("installing tls... %s\n", ldap_err2string(result));
}
int request_id = 0;
result = ldap_sasl_bind(ldap, "", LDAP_SASL_SIMPLE, NULL, 0, 0, &request_id);
if ( result != LDAP_SUCCESS ) {
fprintf(stderr, "ldap_x_bind_s: %s\n", ldap_err2string(result));
printf("LDAP bind error .. %d\n", result);
return(EXIT_FAILURE);
} else {
printf("LDAP connection successful.\n");
}
ldap_unbind(ldap);
return(EXIT_SUCCESS);
}
can someone help to check why my verify call-back is not called?
I think you need to set the callback on the SSL object directly instead of the context, so
void ldap_tls_cb(LDAP * ld, SSL * ssl, SSL_CTX * ctx, void * arg)
{
SSL_set_verify(ssl, SSL_VERIFY_PEER, verify_callback);
printf("verify call back is set...\n");
return;
}
The reason for this is that the SSL handle has already been initialised by the time your connect callback is called (see the OpenLDAP code), and
it's too late to set this callback through the context at that point:
If no special callback was set before, the default callback for the underlying ctx is used, that was valid at the time ssl was created with SSL_new(3).
OpenLDAP can be built with GnuTLS, so you may need to check that it's using OpenSSL before setting the callback. The LDAP_OPT_X_TLS_PACKAGE option could be used for this (note that I haven't tested this code):
char* package = NULL;
int result = ldap_get_option(NULL, LDAP_OPT_X_TLS_PACKAGE, (void *)&package);
if (result != LDAP_OPT_SUCCESS) {
ldap_perror(ldap, "ldap_get_option failed!");
return(EXIT_FAILURE);
} else {
if (strcmp(package, "OpenSSL") == 0) {
// Set your callback
}
ldap_memfree(package);
}

calling Objective C and C from Swift passing callback function

I am trying to call the HappyTime onvif library from Swift.
I have the library linked in to my project and I am able to call some simple functions, but I am having trouble getting the syntax right in my call which passes my callback function.
Here is the Swift code:
func discoverCameras()
{
HappyInterface.sharedInstance().startProb()
//this line gives syntax error
HappyInterface.sharedInstance().setProbeCB(cameraDiscovered)
}
func cameraDiscovered(cameraFound:UnsafeMutablePointer<DEVICE_BINFO>)
{
table.reloadData()
}
my setProbeCB call gives this error:
Cannot convert value of type '(UnsafeMutablePointer) -> ()' to expected argument type 'UnsafeMutablePointer' (aka 'UnsafeMutablePointer, UnsafeMutablePointer<()>) -> ()>>')
Here is the Obj C implementation:
- (void) setProbeCB:(onvif_probe_cb *)cb {
set_probe_cb(*cb, 0);
}
This is the Obj C header:
- (void) setProbeCB:(onvif_probe_cb *)cb;
This is the C header:
#ifndef __H_ONVIF_PROBE_H__
#define __H_ONVIF_PROBE_H__
#include "onvif.h"
typedef void (* onvif_probe_cb)(DEVICE_BINFO * p_res, void * pdata);
#ifdef __cplusplus
extern "C" {
#endif
ONVIF_API void set_probe_cb(onvif_probe_cb cb, void * pdata);
ONVIF_API void set_probe_interval(int interval);
ONVIF_API int start_probe(int interval);
ONVIF_API void stop_probe();
ONVIF_API void send_probe_req();
#ifdef __cplusplus
}
#endif
#endif // __H_ONVIF_PROBE_H__
This is the C code:
/***************************************************************************************/
#define MAX_PROBE_FD 8
/***************************************************************************************/
onvif_probe_cb g_probe_cb = 0;
void * g_probe_cb_data = 0;
pthread_t g_probe_thread = 0;
int g_probe_fd[MAX_PROBE_FD];
int g_probe_interval = 30;
BOOL g_probe_running = FALSE;
/***************************************************************************************/
int onvif_probe_init(unsigned int ip)
{
int opt = 1;
SOCKET fd;
struct sockaddr_in addr;
struct ip_mreq mcast;
fd = socket(AF_INET, SOCK_DGRAM, 0);
if(fd < 0)
{
log_print(LOG_ERR, "socket SOCK_DGRAM error!\n");
return -1;
}
addr.sin_family = AF_INET;
addr.sin_port = htons(3702);
addr.sin_addr.s_addr = ip;
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
{
// if port 3702 already occupied, only receive unicast message
addr.sin_port = 0;
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
{
closesocket(fd);
log_print(LOG_ERR, "bind error! %s\n", sys_os_get_socket_error());
return -1;
}
}
/* reuse socket addr */
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt)))
{
log_print(LOG_WARN, "setsockopt SO_REUSEADDR error!\n");
}
memset(&mcast, 0, sizeof(mcast));
mcast.imr_multiaddr.s_addr = inet_addr("239.255.255.250");
mcast.imr_interface.s_addr = ip;
if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mcast, sizeof(mcast)) < 0)
{
#if __WIN32_OS__
if(setsockopt(fd, IPPROTO_IP, 5, (char*)&mcast, sizeof(mcast)) < 0)
#endif
{
closesocket(fd);
log_print(LOG_ERR, "setsockopt IP_ADD_MEMBERSHIP error! %s\n", sys_os_get_socket_error());
return -1;
}
}
return fd;
}
char probe_req1[] =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
"<Envelope xmlns:tds=\"http://www.onvif.org/ver10/device/wsdl\" xmlns=\"http://www.w3.org/2003/05/soap-envelope\">"
"<Header>"
"<wsa:MessageID xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\">uuid:%s</wsa:MessageID>"
"<wsa:To xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\">urn:schemas-xmlsoap-org:ws:2005:04:discovery</wsa:To>"
"<wsa:Action xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\">http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe</wsa:Action>"
"</Header>"
"<Body>"
"<Probe xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns=\"http://schemas.xmlsoap.org/ws/2005/04/discovery\">"
"<Types>tds:Device</Types>"
"<Scopes />"
"</Probe>"
"</Body>"
"</Envelope>";
char probe_req2[] =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
"<Envelope xmlns:dn=\"http://www.onvif.org/ver10/network/wsdl\" xmlns=\"http://www.w3.org/2003/05/soap-envelope\">"
"<Header>"
"<wsa:MessageID xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\">uuid:%s</wsa:MessageID>"
"<wsa:To xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\">urn:schemas-xmlsoap-org:ws:2005:04:discovery</wsa:To>"
"<wsa:Action xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\">http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe</wsa:Action>"
"</Header>"
"<Body>"
"<Probe xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns=\"http://schemas.xmlsoap.org/ws/2005/04/discovery\">"
"<Types>dn:NetworkVideoTransmitter</Types>"
"<Scopes />"
"</Probe>"
"</Body>"
"</Envelope>";
int onvif_probe_req_tx(int fd)
{
int len;
int rlen;
char * p_bufs = NULL;
struct sockaddr_in addr;
int buflen = 10*1024;
p_bufs = (char *)malloc(buflen);
if (NULL == p_bufs)
{
return -1;
}
memset(p_bufs, 0, buflen);
sprintf(p_bufs, probe_req1, onvif_uuid_create());
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("239.255.255.250");
addr.sin_port = htons(3702);
len = strlen(p_bufs);
rlen = sendto(fd, p_bufs, len, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
if (rlen != len)
{
log_print(LOG_ERR, "onvif_probe_req_tx::rlen = %d,slen = %d\r\n", rlen, len);
}
usleep(1000);
memset(p_bufs, 0, buflen);
sprintf(p_bufs, probe_req2, onvif_uuid_create());
len = strlen(p_bufs);
rlen = sendto(fd, p_bufs, len, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
if (rlen != len)
{
log_print(LOG_ERR, "onvif_probe_req_tx::rlen = %d,slen = %d\r\n", rlen, len);
}
free(p_bufs);
return rlen;
}
BOOL onvif_parse_device_binfo(XMLN * p_node, DEVICE_BINFO * p_res)
{
XMLN * p_EndpointReference;
XMLN * p_Types;
XMLN * p_XAddrs;
p_EndpointReference = xml_node_soap_get(p_node, "EndpointReference");
if (p_EndpointReference)
{
XMLN * p_Address = xml_node_soap_get(p_EndpointReference, "Address");
if (p_Address && p_Address->data)
{
strncpy(p_res->EndpointReference, p_Address->data, sizeof(p_res->EndpointReference)-1);
}
}
p_Types = xml_node_soap_get(p_node, "Types");
if (p_Types && p_Types->data)
{
p_res->type = parse_DeviceType(p_Types->data);
}
p_XAddrs = xml_node_soap_get(p_node, "XAddrs");
if (p_XAddrs && p_XAddrs->data)
{
parse_XAddr(p_XAddrs->data, &p_res->XAddr);
if (p_res->XAddr.host[0] == '\0' || p_res->XAddr.port == 0)
{
return FALSE;
}
}
else
{
return FALSE;
}
return TRUE;
}
BOOL onvif_probe_res(XMLN * p_node, DEVICE_BINFO * p_res)
{
XMLN * p_body = xml_node_soap_get(p_node, "Body");
if (p_body)
{
XMLN * p_ProbeMatches = xml_node_soap_get(p_body, "ProbeMatches");
if (p_ProbeMatches)
{
XMLN * p_ProbeMatch = xml_node_soap_get(p_ProbeMatches, "ProbeMatch");
while (p_ProbeMatch && soap_strcmp(p_ProbeMatch->name, "ProbeMatch") == 0)
{
if (onvif_parse_device_binfo(p_ProbeMatch, p_res))
{
if (g_probe_cb)
{
g_probe_cb(p_res, g_probe_cb_data);
}
}
p_ProbeMatch = p_ProbeMatch->next;
}
}
else
{
XMLN * p_Hello = xml_node_soap_get(p_body, "Hello");
if (p_Hello)
{
if (onvif_parse_device_binfo(p_Hello, p_res))
{
if (g_probe_cb)
{
g_probe_cb(p_res, g_probe_cb_data);
}
}
}
}
}
return TRUE;
}
int onvif_probe_net_rx()
{
int i;
int ret;
int maxfd = 0;
int fd = 0;
char rbuf[10*1024];
fd_set fdread;
struct timeval tv = {1, 0};
FD_ZERO(&fdread);
for (i = 0; i < MAX_PROBE_FD; i++)
{
if (g_probe_fd[i] > 0)
{
FD_SET(g_probe_fd[i], &fdread);
if (g_probe_fd[i] > maxfd)
{
maxfd = g_probe_fd[i];
}
}
}
ret = select(maxfd+1, &fdread, NULL, NULL, &tv);
if (ret == 0) // Time expired
{
return 0;
}
for (i = 0; i < MAX_PROBE_FD; i++)
{
if (g_probe_fd[i] > 0 && FD_ISSET(g_probe_fd[i], &fdread))
{
int rlen;
int addr_len;
struct sockaddr_in addr;
unsigned int src_ip;
unsigned int src_port;
XMLN * p_node;
fd = g_probe_fd[i];
addr_len = sizeof(struct sockaddr_in);
rlen = recvfrom(fd, rbuf, sizeof(rbuf), 0, (struct sockaddr *)&addr, (socklen_t*)&addr_len);
if (rlen <= 0)
{
log_print(LOG_ERR, "onvif_probe_net_rx::rlen = %d, fd = %d\r\n", rlen, fd);
continue;
}
src_ip = addr.sin_addr.s_addr;
src_port = addr.sin_port;
p_node = xxx_hxml_parse(rbuf, rlen);
if (p_node == NULL)
{
log_print(LOG_ERR, "onvif_probe_net_rx::hxml parse err!!!\r\n");
}
else
{
DEVICE_BINFO res;
memset(&res, 0, sizeof(DEVICE_BINFO));
onvif_probe_res(p_node, &res);
}
xml_node_del(p_node);
}
}
return 1;
}
void * onvif_probe_thread(void * argv)
{
int count = 0;
int i = 0;
int j = 0;
for (; i < get_if_nums() && j < MAX_PROBE_FD; i++, j++)
{
unsigned int ip = get_if_ip(i);
if (ip != 0 && ip != inet_addr("127.0.0.1"))
{
g_probe_fd[j] = onvif_probe_init(ip);
}
}
for (i = 0; i < MAX_PROBE_FD; i++)
{
if (g_probe_fd[i] > 0)
{
onvif_probe_req_tx(g_probe_fd[i]);
}
}
while (g_probe_running)
{
if (onvif_probe_net_rx() == 0)
{
count++;
}
if (count >= g_probe_interval)
{
count = 0;
for (i = 0; i < MAX_PROBE_FD; i++)
{
if (g_probe_fd[i] > 0)
{
onvif_probe_req_tx(g_probe_fd[i]);
}
}
}
usleep(1000);
}
g_probe_thread = 0;
return NULL;
}
ONVIF_API void set_probe_cb(onvif_probe_cb cb, void * pdata)
{
g_probe_cb = cb;
g_probe_cb_data = pdata;
}
ONVIF_API void send_probe_req()
{
int i;
for (i = 0; i < MAX_PROBE_FD; i++)
{
if (g_probe_fd[i] > 0)
{
onvif_probe_req_tx(g_probe_fd[i]);
}
}
}
ONVIF_API void set_probe_interval(int interval)
{
g_probe_interval = interval;
if (g_probe_interval < 10)
{
g_probe_interval = 30;
}
}
ONVIF_API int start_probe(int interval)
{
g_probe_running = TRUE;
set_probe_interval(interval);
g_probe_thread = sys_os_create_thread((void *)onvif_probe_thread, NULL);
if (g_probe_thread)
{
return 0;
}
return -1;
}
ONVIF_API void stop_probe()
{
int i;
g_probe_running = FALSE;
while (g_probe_thread)
{
usleep(1000);
}
for (i = 0; i < MAX_PROBE_FD; i++)
{
if (g_probe_fd[i] > 0)
{
closesocket(g_probe_fd[i]);
g_probe_fd[i] = 0;
}
}
}
Here is what the DEVICE_BINFO struct looks like:
typedef struct
{
int type; // device type
char EndpointReference[100];
onvif_XAddr XAddr; // xaddr, include port host, url
} DEVICE_BINFO;
One thing that should be fixed is a mismatch in the number of arguments to the callback. Swift calls the Objective-C setProbeCB() method, giving it a pointer to the cameraDiscovered() function, which takes a single argument. Then setProbeCB() gives the function pointer to the C set_probe_cb() function, which expects a pointer to a function that takes two arguments.
Another observation is that setProbeCB() could just take onvif_probe_cb instead of onvif_probe_cb* and then call C code simply as set_probe_cb(cb, 0). However, I don't think it makes much difference.
Also, I think the question could have been distilled to a smaller size.
The following is a simplified example based on your original code. It shows how to implement a callback in Swift and have C code call it, but the real fun starts when passing data via callback parameters and return values. It gets very tricky very fast, and that's why the example doesn't show how to deal with DEVICE_BINFO in Swift code. It's a topic in its own right.
The clue to using (Objective-)C functions and types in Swift is figuring out how they are imported into Swift. For example, to find out how onvif_probe_cb is imported, type it on a line in the Swift code, place the cursor in it, and Quick Help will show you this:
Declaration: typealias onvif_probe_cb = (UnsafeMutablePointer<DEVICE_BINFO>, UnsafeMutablePointer<Void>) -> Void
Declared in: clib.h
That tells us the parameter and return types to use in our Swift implementation of the callback.
The example is by no means production quality: there are all kinds of things that can go haywire in terms of memory management etc. Please see the code comments for additional info.
First, here is the C code header (clib.h):
#ifndef clib_h
#define clib_h
#include <stdio.h>
typedef struct {
char hostname[50];
int32_t port;
char url[200];
} onvif_XAddr;
typedef struct
{
int type; // device type
char EndpointReference[100];
onvif_XAddr XAddr; // xaddr, include port host, url
} DEVICE_BINFO;
/**
* This is the typedef of the function pointer to be used for our callback.
* The function takes a pointer to DEVICE_BINFO and a pointer to some arbitrary
* data meaningful to the code that provides the callback implementation. It will
* be NULL in this example.
*/
typedef void (* onvif_probe_cb)(DEVICE_BINFO * p_res, void * pdata);
/**
* A function to set the callback.
*/
void set_probe_cb(onvif_probe_cb cb, void * pdata);
/**
* This is a function that calls the callback.
*/
void find_device();
#endif /* clib_h */
Here is the rest of our C source (clib.c):
#include "clib.h"
#include <string.h>
onvif_probe_cb gCB = 0; // global variable to store the callback pointer
void * gUserData = 0; // global variable to store pointer to user data
DEVICE_BINFO gDeviceInfo; // global variable to store device info struct
void find_device() {
// Set up gDeviceInfo
gDeviceInfo.XAddr.port = 1234;
strcpy( gDeviceInfo.XAddr.hostname, "myhost");
strcpy( gDeviceInfo.XAddr.url, "http://junk.com");
gDeviceInfo.type = 777;
// ... and, if a callback is available, call it with the device info
if (gCB) gCB(&gDeviceInfo, gUserData);
else puts("No callback available");
}
void set_probe_cb(onvif_probe_cb cb, void * pdata) {
gCB = cb;
gUserData = pdata;
}
Here is the Objective-C wrapper header (oclib.h):
#ifndef oclib_h
#define oclib_h
#import "clib.h"
#import <Foundation/Foundation.h>
/**
* Interface of an Objective-C wrapper around C code in clib.*. We could have
* gone straight to C from Swift, but I'm trying to keep the example close to the
* code in the question. Also, this extra Objective C layer could be helpful in
* translating data structures, such as DEVICE_BINFO, between C and Swift, since
* Objective-C plays much nicer with C data types. This is no surprise: any C code
* is valid Objective-C (Objective-C is a strict superset of C).
*/
#interface MyWrapper : NSObject
-(id)init;
// Please note: this one takes a single argument, while the C function it wraps
// takes 2; see the implementation.
-(void) setProbeCB:(onvif_probe_cb) cb;
-(void) findDevice;
#end
#endif /* oclib_h */
And the wrapper implementation (oclib.m):
#import "oclib.h"
/**
* Implementation of our Objective-C wrapper.
*/
#implementation MyWrapper
-(id)init { return self; }
-(void) setProbeCB:(onvif_probe_cb) cb {
// We don't want anything other than device info to be passed back and
// forth via the callback, so this wrapper function takes a single argument
// and passes 0 as the 2nd argument to the wrapped C function.
set_probe_cb(cb, 0);
}
-(void) findDevice {
find_device();
}
#end
Finally, here is the Swift code that implements the callback (main.swift):
var w : MyWrapper = MyWrapper()
/**
* This is the callback implementation in Swift. We don't use the 2nd argument, userData, but it still
* has to be present to satisfy the way the callback function pointer is specified in C code.
*/
func cameraDiscovered( info : UnsafeMutablePointer<DEVICE_BINFO>, userData : UnsafeMutablePointer<Void>) {
print("Called the Swift callback!")
let devInfo : DEVICE_BINFO = info.memory;
print( "The device type is \(devInfo.type)")
print( "The device port is \(devInfo.XAddr.port)")
}
// Provide the callback to C code via Objective-C
w.setProbeCB(cameraDiscovered)
// ... and call a function that will cause the C code to invoke the callback.
w.findDevice()
The bridging header just has #import oclib.h, thus exposing the contents of both C and Objective-C headers to Swift.
The expected output:
Called the Swift callback!
The device type is 777
The device port is 1234

can t connect my ssh client to the remote machine

I've downloaded and compiled libssh 0.6.1 from libSSH and linked the ssh.lib,ssh.dll to a visual c++ project .
The code below compiles and run fine , but when calling ssh_connect() , it return -1 : Failed to connect : No error.
Also, I used putty to connect to my remote machine and it works fine.
here is my code:
// sshClient.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <stdlib.h>
#include <libssh/libssh.h>
int _tmain(int argc, _TCHAR* argv[])
{
ssh_session my_ssh_session;
int verbosity = SSH_LOG_PROTOCOL;
int port = 22;
char* host="127.0.0.1";
ssh_channel channel;
int rc;
//I create a session
my_ssh_session = ssh_new();
if (my_ssh_session == NULL)
exit(-1);
ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, host);
ssh_options_set(my_ssh_session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
ssh_options_set(my_ssh_session, SSH_OPTIONS_PORT, &port);
ssh_options_set(my_ssh_session, SSH_OPTIONS_USER,"true");
rc = ssh_connect(my_ssh_session);
if (rc != SSH_OK) {
fprintf(stderr, "Error connecting to 192.168.78.131 : %s\n", ssh_get_error(my_ssh_session));
exit(-1);
}
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
//Here I create a channel
channel = ssh_channel_new(my_ssh_session);
if (channel == NULL)
return SSH_ERROR;
if (SSH_OK != ssh_channel_open_session(channel)) {
printf("ssh_channel_open_session");
ssh_channel_free(channel);
return rc;
}
//My remote command ls -l under true Folder
rc = ssh_channel_request_exec(channel, "ls -l");
if (rc != SSH_OK){ ssh_channel_close(channel);
ssh_channel_free(channel);
return rc;
}
char buffer[256];
unsigned int nbytes;
nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
while (nbytes > 0){
if (fwrite(buffer, 1, nbytes, stdout) != nbytes)
{ ssh_channel_close(channel);
ssh_channel_free(channel);
return SSH_ERROR;
}
nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
}
if (nbytes < 0){
ssh_channel_close(channel);
ssh_channel_free(channel);
return SSH_ERROR;
}
ssh_channel_send_eof(channel);
ssh_channel_close(channel);
ssh_channel_free(channel);
ssh_free(my_ssh_session);
system("pause");
return 0;
}
Check your host IP address. I guess you forgot to change the IP address in the example source file.

openssl BIO_do_connect returns 0 for ssl

Here's my simple openssl client test case trying to connect to google.com:443.
According to the manual, BIO_do_connect should return 1, 0 or -1.
Google didn't find me anyone for whom it returns 0, which it does for me.
#include <stdio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
int main()
{
SSL_load_error_strings();
SSL_library_init();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();
SSL_CTX *p_ssl_ctx = NULL;
SSL *p_ssl = NULL;
BIO * bio = NULL;
int r = 0;
// init ssl context
p_ssl_ctx = SSL_CTX_new(SSLv2_client_method()); /* Create new context */
if (p_ssl_ctx == NULL)
{
ERR_print_errors_fp(stderr);
return 3;
}
const char *store_path = "/etc/ssl/certs/ca-certificates.crt";
r = SSL_CTX_load_verify_locations(p_ssl_ctx, store_path, NULL);
if (r == 0) {
fprintf(stderr, "Unable to load the trust store from %s.\n", store_path);
return 4;
}
bio = BIO_new_ssl_connect(p_ssl_ctx);
if (!bio) {
fprintf(stderr, "no bio \n");
return 5;
}
BIO_get_ssl(bio, &p_ssl);
if (!(p_ssl)) {
fprintf(stderr, "no ssl\n");
return 6;
}
SSL_set_mode(p_ssl, SSL_MODE_AUTO_RETRY);
BIO_set_conn_hostname(bio, "www.google.com:443");
r = BIO_do_connect(bio);
if (r < 1) {
fprintf(stderr, "BIO_new_ssl_connect failed: %lu (0x%lx)\n", r, r);
fprintf(stderr, "Error: %s\n", ERR_reason_error_string(ERR_get_error()));
fprintf(stderr, "%s\n", ERR_error_string(ERR_get_error(), NULL));
ERR_print_errors_fp(stderr);
perror("bio");
return 7;
}
if (SSL_get_verify_result(p_ssl) != X509_V_OK) {
fprintf(stderr, "Unable to verify connection result.\n");
return 8;
}
return 0;
}
returns:
BIO_new_ssl_connect failed: 0 (0x0)
Error: (null)
error:00000000:lib(0):func(0):reason(0)
bio: Success
so how do i get the actual error out of this?
For getting the last state of your SSL connection in your code you can add something like fprintf(stderr,"p_ssl state: %s\n",SSL_state_string_long(p_ssl));.
More generally I suggest you to add an info callback like this : http://www.openssl.org/docs/ssl/SSL_CTX_set_info_callback.html
For your case, you must replace SSLv2_client_method() by something like TLSv1_client_method().