Skip to content

Instantly share code, notes, and snippets.

@sarahhodne
Created May 12, 2009 16:58
Show Gist options
  • Save sarahhodne/110595 to your computer and use it in GitHub Desktop.
Save sarahhodne/110595 to your computer and use it in GitHub Desktop.
/*
* conn.c
* $Id: conn.c,v 1.51 2006/08/01 00:07:53 ianmacd Exp $
*/
#include "ruby.h"
#include "rbldap.h"
#if defined(HAVE_SYS_TIME_H)
# include <sys/time.h>
#endif
#if defined(HAVE_UNISTD_H)
# include <unistd.h>
#endif
/* RDoc needs the following bogus code to find the parent module:
*
* rb_mLDAP = rb_define_module ("LDAP");
*/
static VALUE rb_ldap_sort_obj = Qnil;
extern VALUE rb_ldap_control_new2 (LDAPControl * ctl);
extern VALUE rb_ldap_sslconn_initialize (int argc, VALUE argv[], VALUE self);
extern VALUE rb_ldap_conn_rebind (VALUE self);
VALUE rb_cLDAP_Conn;
static void
rb_ldap_conn_free (RB_LDAP_DATA * ldapdata)
{
if (ldapdata->ldap && ldapdata->bind)
{
ldap_unbind (ldapdata->ldap);
};
};
static void
rb_ldap_conn_mark (RB_LDAP_DATA * ldapdata)
{
/* empty */
};
VALUE
rb_ldap_conn_new (VALUE klass, LDAP * cldap)
{
VALUE conn;
RB_LDAP_DATA *ldapdata;
conn = Data_Make_Struct (klass, RB_LDAP_DATA,
rb_ldap_conn_mark, rb_ldap_conn_free, ldapdata);
ldapdata->ldap = cldap;
ldapdata->err = 0;
ldapdata->bind = 0;
return conn;
};
VALUE
rb_ldap_conn_s_allocate (VALUE klass)
{
return rb_ldap_conn_new (klass, (LDAP *) 0);
}
/*
* call-seq:
* LDAP::Conn.new(host='localhost', port=LDAP_PORT) => LDAP::Conn
*
* Return a new LDAP::Conn connection to the server, +host+, on port +port+.
*/
VALUE
rb_ldap_conn_initialize (int argc, VALUE argv[], VALUE self)
{
LDAP *cldap;
char *chost;
int cport;
int was_verbose = Qfalse;
RB_LDAP_DATA *ldapdata;
VALUE host, port;
Data_Get_Struct (self, RB_LDAP_DATA, ldapdata);
if (ldapdata->ldap)
{
return Qnil;
}
switch (rb_scan_args (argc, argv, "02", &host, &port))
{
case 0:
chost = ALLOCA_N (char, strlen ("localhost") + 1);
strcpy (chost, "localhost");
cport = LDAP_PORT;
break;
case 1:
chost = StringValueCStr (host);
cport = LDAP_PORT;
break;
case 2:
chost = StringValueCStr (host);
cport = NUM2INT (port);
break;
default:
rb_bug ("rb_ldap_conn_new");
};
cldap = ldap_init (chost, cport);
if (!cldap)
rb_raise (rb_eLDAP_ResultError, "can't initialise an LDAP session");
ldapdata->ldap = cldap;
rb_iv_set (self, "@args", rb_ary_new4 (argc, argv));
/* Silence warning that next rb_iv_get produces. */
if (ruby_verbose == Qtrue)
{
was_verbose = Qtrue;
ruby_verbose = Qfalse;
}
if (rb_iv_get (self, "@sasl_quiet") != Qtrue)
rb_iv_set (self, "@sasl_quiet", Qfalse);
if (was_verbose == Qtrue)
ruby_verbose = Qtrue;
return Qnil;
};
/*
* call-seq:
* LDAP::Conn.open(host='localhost', port=LDAP_PORT) => LDAP::Conn
*
* Return a new LDAP::Conn connection to the server, +host+, on port +port+.
*/
VALUE
rb_ldap_conn_s_open (int argc, VALUE argv[], VALUE klass)
{
LDAP *cldap;
char *chost;
int cport;
VALUE host, port;
VALUE conn;
switch (rb_scan_args (argc, argv, "02", &host, &port))
{
case 0:
chost = ALLOCA_N (char, strlen ("localhost") + 1);
strcpy (chost, "localhost");
cport = LDAP_PORT;
break;
case 1:
chost = StringValueCStr (host);
cport = LDAP_PORT;
break;
case 2:
chost = StringValueCStr (host);
cport = NUM2INT (port);
break;
default:
rb_bug ("rb_ldap_conn_new");
};
cldap = ldap_open (chost, cport);
if (!cldap)
rb_raise (rb_eLDAP_ResultError, "can't open an LDAP session");
conn = rb_ldap_conn_new (klass, cldap);
return conn;
};
/*
* call-seq:
* conn.start_tls => nil
*
* Initiate START_TLS for the connection, +conn+.
*/
VALUE
rb_ldap_conn_start_tls_s (int argc, VALUE argv[], VALUE self)
{
#ifdef HAVE_LDAP_START_TLS_S
VALUE arg1, arg2;
RB_LDAP_DATA *ldapdata;
LDAPControl **serverctrls;
LDAPControl **clientctrls;
switch (rb_scan_args (argc, argv, "02", &arg1, &arg2))
{
case 0:
serverctrls = NULL;
clientctrls = NULL;
break;
case 1:
case 2:
rb_notimplement ();
default:
rb_bug ("rb_ldap_conn_start_tls_s");
};
GET_LDAP_DATA (self, ldapdata);
ldapdata->err = ldap_start_tls_s (ldapdata->ldap, serverctrls, clientctrls);
Check_LDAP_Result (ldapdata->err);
#else
rb_notimplement ();
#endif
return Qnil;
};
VALUE
rb_ldap_conn_rebind (VALUE self)
{
VALUE ary = rb_iv_get (self, "@args");
if (rb_obj_is_kind_of (self, rb_cLDAP_SSLConn) == Qtrue)
return rb_ldap_sslconn_initialize (RARRAY_LEN (ary), RARRAY_PTR (ary),
self);
else
return rb_ldap_conn_initialize (RARRAY_LEN (ary), RARRAY_PTR (ary),
self);
}
/*
* call-seq:
* conn.simple_bind(dn=nil, password=nil) => self
* conn.simple_bind(dn=nil, password=nil) { |conn| } => nil
*
* Bind an LDAP connection, using the DN, +dn+, and the credential, +password+.
* If a block is given, +self+ is yielded to the block.
*/
VALUE
rb_ldap_conn_simple_bind_s (int argc, VALUE argv[], VALUE self)
{
RB_LDAP_DATA *ldapdata;
VALUE arg1, arg2;
char *dn = NULL;
char *passwd = NULL;
Data_Get_Struct (self, RB_LDAP_DATA, ldapdata);
if (!ldapdata->ldap)
{
if (rb_iv_get (self, "@args") != Qnil)
{
rb_ldap_conn_rebind (self);
GET_LDAP_DATA (self, ldapdata);
}
else
{
rb_raise (rb_eLDAP_InvalidDataError,
"The LDAP handler has already unbound.");
}
}
if (ldapdata->bind)
{
rb_raise (rb_eLDAP_Error, "already bound.");
};
switch (rb_scan_args (argc, argv, "02", &arg1, &arg2))
{
case 0:
break;
case 1:
if (arg1 == Qnil)
{
dn = NULL;
}
else
{
dn = StringValueCStr (arg1);
}
break;
case 2:
if (arg1 == Qnil)
{
dn = NULL;
}
else
{
dn = StringValueCStr (arg1);
}
if (arg2 == Qnil)
{
passwd = NULL;
}
else
{
passwd = StringValueCStr (arg2);
}
break;
default:
rb_bug ("rb_ldap_conn_simple_bind_s");
}
ldapdata->err = ldap_simple_bind_s (ldapdata->ldap, dn, passwd);
Check_LDAP_Result (ldapdata->err);
ldapdata->bind = 1;
if (rb_block_given_p ())
{
rb_ensure (rb_yield, self, rb_ldap_conn_unbind, self);
return Qnil;
}
else
{
return self;
};
};
/*
* call-seq:
* conn.bind(dn=nil, password=nil, method=LDAP::LDAP_AUTH_SIMPLE)
* => self
* conn.bind(dn=nil, password=nil, method=LDAP::LDAP_AUTH_SIMPLE)
* { |conn| } => nil
*
* Bind an LDAP connection, using the DN, +dn+, the credential, +password+,
* and the bind method, +method+. If a block is given, +self+ is yielded to
* the block.
*/
VALUE
rb_ldap_conn_bind_s (int argc, VALUE argv[], VALUE self)
{
RB_LDAP_DATA *ldapdata;
VALUE arg1, arg2, arg3;
char *dn = NULL;
char *passwd = NULL;
int method = LDAP_AUTH_SIMPLE;
Data_Get_Struct (self, RB_LDAP_DATA, ldapdata);
if (!ldapdata->ldap)
{
if (rb_iv_get (self, "@args") != Qnil)
{
rb_ldap_conn_rebind (self);
GET_LDAP_DATA (self, ldapdata);
}
else
{
rb_raise (rb_eLDAP_InvalidDataError,
"The LDAP handler has already unbound.");
}
}
if (ldapdata->bind)
{
rb_raise (rb_eLDAP_Error, "already bound.");
};
switch (rb_scan_args (argc, argv, "03", &arg1, &arg2, &arg3))
{
case 0:
break;
case 1:
dn = StringValueCStr (arg1);
break;
case 2:
dn = StringValueCStr (arg1);
passwd = StringValueCStr (arg2);
break;
case 3:
dn = StringValueCStr (arg1);
passwd = StringValueCStr (arg2);
method = NUM2INT (arg3);
break;
default:
rb_bug ("rb_ldap_conn_bind_s");
}
ldapdata->err = ldap_bind_s (ldapdata->ldap, dn, passwd, method);
Check_LDAP_Result (ldapdata->err);
ldapdata->bind = 1;
if (rb_block_given_p ())
{
rb_ensure (rb_yield, self, rb_ldap_conn_unbind, self);
return Qnil;
}
else
{
return self;
};
};
/*
* call-seq:
* conn.unbind => nil
*
* Unbind the LDAP connection from the server.
*/
VALUE
rb_ldap_conn_unbind (VALUE self)
{
RB_LDAP_DATA *ldapdata;
GET_LDAP_DATA (self, ldapdata);
ldapdata->err = ldap_unbind (ldapdata->ldap);
ldapdata->bind = 0;
ldapdata->ldap = NULL;
Check_LDAP_Result (ldapdata->err);
return Qnil;
};
/*
* call-seq:
* conn.bound? => true or false
*
* Return *true* if the LDAP connection is still bound.
*/
VALUE
rb_ldap_conn_bound (VALUE self)
{
RB_LDAP_DATA *ldapdata;
Data_Get_Struct (self, RB_LDAP_DATA, ldapdata);
return ldapdata->bind == 0 ? Qfalse : Qtrue;
};
/*
* call-seq:
* conn.set_option(option, data) => self
*
* Set a session-wide option for this LDAP connection.
*
* For example:
*
* <code>conn.set_option( LDAP::LDAP_OPT_PROTOCOL_VERSION, 3 )</code>
*
* would set the protocol of this connection to LDAPv3.
*/
VALUE
rb_ldap_conn_set_option (VALUE self, VALUE opt, VALUE data)
{
/* ldap_set_option() is defined in IETF draft */
#ifdef HAVE_LDAP_SET_OPTION
RB_LDAP_DATA *ldapdata;
RB_LDAP_DATA dummy;
int idata;
void *optdata;
int copt;
if (NIL_P (self))
{
dummy.ldap = NULL;
dummy.err = dummy.bind = 0;
ldapdata = &dummy;
}
else
GET_LDAP_DATA (self, ldapdata);
copt = NUM2INT (opt);
switch (copt)
{
case LDAP_OPT_REFERRALS:
optdata = (void *) NUM2INT (data);
break;
case LDAP_OPT_DEREF:
case LDAP_OPT_SIZELIMIT:
case LDAP_OPT_TIMELIMIT:
case LDAP_OPT_RESTART:
case LDAP_OPT_PROTOCOL_VERSION:
if (ldapdata->bind != 0)
rb_raise (rb_eLDAP_ResultError,
"can't set LDAP protocol version after bind");
case LDAP_OPT_ERROR_NUMBER:
#ifdef LDAP_OPT_SSL
case LDAP_OPT_SSL:
#endif
#ifdef USE_OPENLDAP2
#ifdef LDAP_OPT_X_TLS
case LDAP_OPT_X_TLS:
#endif
#ifdef LDAP_OPT_X_TLS_REQUIRE_CERT
case LDAP_OPT_X_TLS_REQUIRE_CERT:
#endif
#endif
idata = NUM2INT (data);
optdata = &idata;
break;
case LDAP_OPT_HOST_NAME:
case LDAP_OPT_ERROR_STRING:
#ifdef LDAP_OPT_MATCHED_DN
case LDAP_OPT_MATCHED_DN:
#endif
#ifdef USE_OPENLDAP2
#ifdef LDAP_OPT_X_TLS_CACERTFILE
case LDAP_OPT_X_TLS_CACERTFILE:
#endif
#ifdef LDAP_OPT_X_TLS_CACERTDIR
case LDAP_OPT_X_TLS_CACERTDIR:
#endif
#ifdef LDAP_OPT_X_TLS_CERT
case LDAP_OPT_X_TLS_CERT:
#endif
#ifdef LDAP_OPT_X_TLS_CERTFILE
case LDAP_OPT_X_TLS_CERTFILE:
#endif
#ifdef LDAP_OPT_X_TLS_KEYFILE
case LDAP_OPT_X_TLS_KEYFILE:
#endif
#ifdef LDAP_OPT_X_TLS_PROTOCOL
case LDAP_OPT_X_TLS_PROTOCOL:
#endif
#ifdef LDAP_OPT_X_TLS_CIPHER_SUITE
case LDAP_OPT_X_TLS_CIPHER_SUITE:
#endif
#ifdef LDAP_OPT_X_TLS_RANDOM_FILE
case LDAP_OPT_X_TLS_RANDOM_FILE:
#endif
#endif
optdata = NIL_P (data) ? NULL : StringValueCStr (data);
break;
#ifdef LDAP_OPT_API_INFO
case LDAP_OPT_API_INFO:
rb_raise (rb_eLDAP_Error, "option is read-only");
/* optdata = (void*)rb_ldap_get_apiinfo(data); */
break;
#endif
#ifdef LDAP_OPT_SERVER_CONTROLS
case LDAP_OPT_SERVER_CONTROLS:
optdata = rb_ldap_get_controls (data);
break;
#endif
default:
rb_notimplement ();
}
ldapdata->err = ldap_set_option (ldapdata->ldap, copt, optdata);
Check_LDAP_OPT_Result (ldapdata->err);
return self;
#else
rb_notimplement ();
#endif
};
static VALUE
rb_ldap_conn_s_set_option (VALUE klass, VALUE opt, VALUE data)
{
return rb_ldap_conn_set_option (Qnil, opt, data);
}
/* call-seq:
* conn.get_option(opt) => String
*
* Return the value associated with the option, +opt+.
*/
VALUE
rb_ldap_conn_get_option (VALUE self, VALUE opt)
{
#ifdef HAVE_LDAP_GET_OPTION
RB_LDAP_DATA *ldapdata;
static RB_LDAP_DATA dummy = { NULL, 0, 0 };
long *data;
int copt;
VALUE val;
if (NIL_P (self))
{
if (dummy.ldap == NULL)
dummy.ldap = ldap_init ("", 0);
ldapdata = &dummy;
}
else
GET_LDAP_DATA (self, ldapdata);
copt = NUM2INT (opt);
#if defined(LDAP_OPT_API_INFO) && defined(LDAP_API_INFO_VERSION)
if (copt == LDAP_OPT_API_INFO)
{
LDAPAPIInfo *info;
info = ALLOCA_N (LDAPAPIInfo, 1);
/* This is from the Netscape SDK docs for 4.1* */
info->ldapai_info_version = LDAP_API_INFO_VERSION;
ldapdata->err = ldap_get_option (NULL, copt, (void *) info);
data = (long *) info;
}
else
{
data = (void *) ALLOCA_N (char, LDAP_GET_OPT_MAX_BUFFER_SIZE);
ldapdata->err = ldap_get_option (ldapdata->ldap, copt, (void *) data);
}
#else
data = (void *) ALLOCA_N (char, LDAP_GET_OPT_MAX_BUFFER_SIZE);
ldapdata->err = ldap_get_option (ldapdata->ldap, copt, (void *) data);
#endif
if (ldapdata->err == LDAP_OPT_SUCCESS)
{
switch (copt)
{
case LDAP_OPT_DEREF:
case LDAP_OPT_SIZELIMIT:
case LDAP_OPT_TIMELIMIT:
case LDAP_OPT_REFERRALS:
case LDAP_OPT_RESTART:
case LDAP_OPT_PROTOCOL_VERSION:
case LDAP_OPT_ERROR_NUMBER:
#ifdef USE_OPENLDAP2
#ifdef LDAP_OPT_X_TLS
case LDAP_OPT_X_TLS:
#endif
#ifdef LDAP_OPT_X_TLS_REQUIRE_CERT
case LDAP_OPT_X_TLS_REQUIRE_CERT:
#endif
#endif
val = INT2NUM ((int) (*data));
break;
case LDAP_OPT_HOST_NAME:
case LDAP_OPT_ERROR_STRING:
#ifdef LDAP_OPT_MATCHED_DN
case LDAP_OPT_MATCHED_DN:
#endif
#ifdef USE_OPENLDAP2
#ifdef LDAP_OPT_X_TLS_CACERTFILE
case LDAP_OPT_X_TLS_CACERTFILE:
#endif
#ifdef LDAP_OPT_X_TLS_CACERTDIR
case LDAP_OPT_X_TLS_CACERTDIR:
#endif
#ifdef LDAP_OPT_X_TLS_CERT
case LDAP_OPT_X_TLS_CERT:
#endif
#ifdef LDAP_OPT_X_TLS_CERTFILE
case LDAP_OPT_X_TLS_CERTFILE:
#endif
#ifdef LDAP_OPT_X_TLS_KEYFILE
case LDAP_OPT_X_TLS_KEYFILE:
#endif
#ifdef LDAP_OPT_X_TLS_PROTOCOL
case LDAP_OPT_X_TLS_PROTOCOL:
#endif
#ifdef LDAP_OPT_X_TLS_CIPHER_SUITE
case LDAP_OPT_X_TLS_CIPHER_SUITE:
#endif
#ifdef LDAP_OPT_X_TLS_RANDOM_FILE
case LDAP_OPT_X_TLS_RANDOM_FILE:
#endif
#endif
val = (data
&& *data) ? rb_tainted_str_new2 ((char *) (*data)) : Qnil;
break;
#ifdef LDAP_OPT_API_INFO
case LDAP_OPT_API_INFO:
val = rb_ldap_apiinfo_new ((LDAPAPIInfo *) data);
break;
#endif
default:
rb_notimplement ();
};
return val;
}
else
{
rb_raise (rb_eLDAP_Error, ldap_err2string (ldapdata->err));
};
#else
rb_notimplement ();
#endif
};
static VALUE
rb_ldap_conn_s_get_option (VALUE klass, VALUE opt)
{
return rb_ldap_conn_get_option (Qnil, opt);
}
/*
* call-seq:
* conn.perror(msg) => nil
*
* Print the text string associated with the error code of the last LDAP
* operation. +msg+ is used to prefix the error.
*/
VALUE
rb_ldap_conn_perror (VALUE self, VALUE msg)
{
RB_LDAP_DATA *ldapdata;
char *cmsg;
#if (! defined(HAVE_LDAP_PERROR)) || defined(USE_NETSCAPE_SDK)
char *str;
#endif
GET_LDAP_DATA (self, ldapdata);
cmsg = StringValueCStr (msg);
#if defined(HAVE_LDAP_PERROR) && (! defined(USE_NETSCAPE_SDK))
ldap_perror (ldapdata->ldap, cmsg);
#else
str = ldap_err2string (ldapdata->err);
fprintf (stderr, "%s: %s\n", cmsg, str);
#endif
return Qnil;
};
/*
* call-seq:
* conn.result2error(msg) => Fixnum
*
* Return the error code associated with the LDAP message, +msg+.
*/
VALUE
rb_ldap_conn_result2error (VALUE self, VALUE msg)
{
RB_LDAP_DATA *ldapdata;
RB_LDAPENTRY_DATA *edata;
int cdofree = 0;
GET_LDAP_DATA (self, ldapdata);
Check_Kind (msg, rb_cLDAP_Entry);
GET_LDAPENTRY_DATA (msg, edata);
ldapdata->err = ldap_result2error (ldapdata->ldap, edata->msg, cdofree);
return INT2NUM (ldapdata->err);
};
/*
* call-seq:
* conn.err2string(err) => String
*
* Return the text string associated with the LDAP error, +err+.
*/
VALUE
rb_ldap_conn_err2string (VALUE self, VALUE err)
{
RB_LDAP_DATA *ldapdata;
int c_err = NUM2INT (err);
char *str;
GET_LDAP_DATA (self, ldapdata);
str = ldap_err2string (c_err);
return (str ? rb_tainted_str_new2 (str) : Qnil);
};
VALUE
rb_ldap_conn_get_errno (VALUE self)
{
RB_LDAP_DATA *ldapdata;
VALUE err;
GET_LDAP_DATA (self, ldapdata);
#ifdef USE_NETSCAPE_SDK
cerr = ldap_get_lderrno (ldapdata->ldap, NULL, NULL);
err = INT2NUM (cerr);
#else
# ifdef USE_OPENLDAP1
cerr = NUM2INT (ldapdata->ldap->ld_errno);
err = INT2NUM (cerr);
# else
rb_notimplement ();
# endif
#endif
return err;
};
static VALUE
rb_ldap_conn_invalidate_entry (VALUE msg)
{
RB_LDAPENTRY_DATA *edata;
GET_LDAPENTRY_DATA (msg, edata);
edata->ldap = NULL;
edata->msg = NULL;
return Qnil;
};
static int
rb_ldap_internal_strcmp (const char *left, const char *right)
{
VALUE res;
if (rb_ldap_sort_obj == Qtrue)
{
res = rb_funcall (rb_tainted_str_new2 (left), rb_intern ("<=>"), 1,
rb_tainted_str_new2 (right));
}
else if (rb_ldap_sort_obj != Qnil)
{
res = rb_funcall (rb_ldap_sort_obj, rb_intern ("call"), 2,
rb_tainted_str_new2 (left),
rb_tainted_str_new2 (right));
}
else
{
res = 0;
};
return INT2NUM (res);
};
static int
rb_ldap_conn_search_i (int argc, VALUE argv[], VALUE self,
RB_LDAP_DATA ** ldapdata, LDAPMessage ** cmsg)
{
VALUE base, scope, filter, attrs, attrsonly, sec, usec, s_attr, s_proc;
LDAP *cldap;
char *cbase;
int cscope;
char *cfilter;
char **cattrs;
char *sort_attr;
int cattrsonly;
int i;
struct timeval tv;
GET_LDAP_DATA (self, (*ldapdata));
cldap = (*ldapdata)->ldap;
cattrs = NULL;
cattrsonly = 0;
tv.tv_sec = 0;
tv.tv_usec = 0;
sort_attr = NULL;
rb_ldap_sort_obj = Qnil;
switch (rb_scan_args (argc, argv, "36",
&base, &scope, &filter, &attrs, &attrsonly, &sec,
&usec, &s_attr, &s_proc))
{
case 9:
rb_ldap_sort_obj = s_proc; /* Ruby's GC never starts in a C function */
case 8:
if (rb_ldap_sort_obj == Qnil)
{
rb_ldap_sort_obj = Qtrue;
}
sort_attr = StringValueCStr (s_attr);
case 7:
tv.tv_usec = NUM2INT (usec);
case 6:
tv.tv_sec = NUM2INT (sec);
case 5:
cattrsonly = (attrsonly == Qtrue) ? 1 : 0;
case 4:
if (TYPE (attrs) == T_NIL)
{
cattrs = NULL;
}
else
{
if (TYPE (attrs) == T_STRING)
attrs = rb_ary_to_ary (attrs);
else
Check_Type (attrs, T_ARRAY);
if (RARRAY_LEN (attrs) == 0)
{
cattrs = NULL;
}
else
{
cattrs = ALLOCA_N (char *, (RARRAY_LEN (attrs) + 1));
for (i = 0; i < RARRAY_LEN (attrs); i++)
{
cattrs[i] = StringValueCStr (RARRAY_PTR (attrs)[i]);
};
cattrs[RARRAY_LEN (attrs)] = NULL;
}
}
case 3:
cbase = StringValueCStr (base);
cscope = NUM2INT (scope);
cfilter = StringValueCStr (filter);
break;
default:
rb_bug ("rb_ldap_conn_search_s");
};
(*cmsg) = NULL;
if (tv.tv_sec == 0 && tv.tv_usec == 0)
{
(*ldapdata)->err = ldap_search_s (cldap, cbase, cscope, cfilter,
cattrs, cattrsonly, cmsg);
}
else
{
(*ldapdata)->err = ldap_search_st (cldap, cbase, cscope, cfilter,
cattrs, cattrsonly, &tv, cmsg);
}
if (!(cmsg && (*cmsg)))
{
rb_raise (rb_eRuntimeError, "no result returned by search");
}
Check_LDAP_Result ((*ldapdata)->err);
#ifdef HAVE_LDAP_SORT_ENTRIES
if (rb_ldap_sort_obj != Qnil)
{
ldap_sort_entries ((*ldapdata)->ldap, cmsg,
sort_attr, rb_ldap_internal_strcmp);
};
#endif
rb_ldap_sort_obj = Qnil;
return (*ldapdata)->err;
}
static VALUE
rb_ldap_conn_search_b (VALUE rdata)
{
void **data = (void **) rdata;
LDAP *cldap = (LDAP *) data[0];
LDAPMessage *cmsg = (LDAPMessage *) data[1];
LDAPMessage *e;
VALUE m;
for (e = ldap_first_entry (cldap, cmsg); e != NULL;
e = ldap_next_entry (cldap, e))
{
m = rb_ldap_entry_new (cldap, e);
rb_ensure (rb_yield, m, rb_ldap_conn_invalidate_entry, m);
}
return Qnil;
}
static VALUE
rb_ldap_conn_search2_b (VALUE rdata)
{
void **data = (void *) rdata;
LDAP *cldap = (LDAP *) data[0];
LDAPMessage *cmsg = (LDAPMessage *) data[1];
VALUE ary = (VALUE) data[2];
LDAPMessage *e;
VALUE m;
VALUE hash;
for (e = ldap_first_entry (cldap, cmsg); e != NULL;
e = ldap_next_entry (cldap, e))
{
m = rb_ldap_entry_new (cldap, e);
hash = rb_ldap_entry_to_hash (m);
rb_ary_push (ary, hash);
if (rb_block_given_p ())
{
rb_ensure (rb_yield, hash, rb_ldap_conn_invalidate_entry, m);
}
}
return Qnil;
}
static VALUE
rb_ldap_msgfree (VALUE data)
{
LDAPMessage *cmsg = (LDAPMessage *) data;
ldap_msgfree (cmsg);
return Qnil;
}
VALUE
rb_ldap_parse_result (LDAP * cldap, LDAPMessage * cmsg)
{
int rc, err, i;
char **referrals;
LDAPControl **serverctrls;
VALUE refs, ctls, ary;
refs = rb_ary_new ();
ctls = rb_ary_new ();
ary = rb_ary_new ();
rc = ldap_parse_result (cldap, cmsg, &err, NULL, NULL,
&referrals, &serverctrls, 0);
Check_LDAP_Result (rc);
Check_LDAP_Result (err);
if (referrals)
{
for (i = 0; referrals[i]; i++)
{
rb_ary_push (refs, rb_str_new2 (referrals[i]));
}
}
if (serverctrls)
{
for (i = 0; serverctrls[i]; i++)
{
rb_ary_push (ctls, rb_ldap_control_new2 (serverctrls[i]));
}
}
rb_ary_push (ary, refs);
rb_ary_push (ary, ctls);
return ary;
}
/*
* call-seq:
* conn.search(base_dn, scope, filter, attrs=nil, attrsonly=false,
* sec=0, usec=0, s_attr=nil, s_proc=nil) { |entry| } => self
*
* Perform a search, with the base DN +base_dn+, a scope of +scope+ and a
* search filter of +filter+.
*
* If +attrs+ is present, it should be an array of the attributes that the
* search should return. By default, all attributes are returned, which is the
* same as specifying an empty array or *nil*. Alternatively, +attrs+ may be a
* single string, in which case it will be treated as a single element array.
*
* If +attrsonly+ is *true*, attributes will be returned, but not their values.
*
* If +sec+ and/or +usec+ are given, they define the time-out for the search in
* seconds and microseconds, respectively.
*
* If +s_attr+ is given, it specifies the attribute on which to sort the
* entries returned by the server. If +s_proc+ is given, it specifies a Proc
* object that will be used to sort the entries returned by the server.
*
* Note that not all results may be returned by this method. If a
* size limit has been set for the number of results to be returned and this
* limit is exceeded, the results set will be truncated. You can check for
* this by calling LDAP::Conn#err immediately after this method and comparing
* the result to LDAP::LDAP_SIZELIMIT_EXCEEDED.
*/
VALUE
rb_ldap_conn_search_s (int argc, VALUE argv[], VALUE self)
{
RB_LDAP_DATA *ldapdata;
LDAPMessage *cmsg;
LDAP *cldap;
VALUE rc_ary = Qnil;
rb_ldap_conn_search_i (argc, argv, self, &ldapdata, &cmsg);
cldap = ldapdata->ldap;
if (ldapdata->err == LDAP_SUCCESS
|| ldapdata->err == LDAP_SIZELIMIT_EXCEEDED)
{
void *pass_data[] = { (void *) cldap, (void *) cmsg };
rc_ary = rb_ldap_parse_result (cldap, cmsg);
rb_iv_set (self, "@referrals", rb_ary_shift (rc_ary));
rb_iv_set (self, "@controls", rb_ary_shift (rc_ary));
rb_ensure (rb_ldap_conn_search_b, (VALUE) pass_data,
rb_ldap_msgfree, (VALUE) cmsg);
};
return self;
}
/*
* call-seq:
* conn.search2(base_dn, scope, filter, attrs=nil, attrsonly=false,
* sec=0, usec=0, s_attr=nil, s_proc=nil) => array
* conn.search2(base_dn, scope, filter, attrs=nil, attrsonly=false,
* sec=0, usec=0, s_attr=nil, s_proc=nil) { |entry_as_hash| } => self
*
* Perform a search, with the base DN +base_dn+, a scope of +scope+ and a
* search filter of +filter+.
*
* If +attrs+ is present, it should be an array of the attributes that the
* search should return. By default, all attributes are returned, which is the
* same as specifying an empty array or *nil*. Alternatively, +attrs+ may be a
* single string, in which case it will be treated as a single element array.
*
* If +attrsonly+ is *true*, attributes will be returned, but not their values.
*
* If +sec+ and/or +usec+ are given, they define the time-out for the search in
* seconds and microseconds, respectively.
*
* If +s_attr+ is given, it specifies the attribute on which to sort the
* entries returned by the server. If +s_proc+ is given, it specifies a Proc
* object that will be used to sort the entries returned by the server.
*
* Note that not all results may be returned by this method. If a
* size limit has been set for the number of results to be returned and this
* limit is exceeded, the results set will be truncated. You can check for
* this by calling LDAP::Conn#err immediately after this method and comparing
* the result to LDAP::LDAP_SIZELIMIT_EXCEEDED.
*/
VALUE
rb_ldap_conn_search2_s (int argc, VALUE argv[], VALUE self)
{
RB_LDAP_DATA *ldapdata;
LDAPMessage *cmsg;
LDAP *cldap;
VALUE ary = Qnil;
VALUE rc_ary = Qnil;
rb_ldap_conn_search_i (argc, argv, self, &ldapdata, &cmsg);
cldap = ldapdata->ldap;
ary = rb_ary_new ();
if (ldapdata->err == LDAP_SUCCESS
|| ldapdata->err == LDAP_SIZELIMIT_EXCEEDED)
{
void *pass_data[] = { (void *) cldap, (void *) cmsg, (void *) ary };
rc_ary = rb_ldap_parse_result (cldap, cmsg);
rb_iv_set (self, "@referrals", rb_ary_shift (rc_ary));
rb_iv_set (self, "@controls", rb_ary_shift (rc_ary));
rb_ensure (rb_ldap_conn_search2_b, (VALUE) pass_data,
rb_ldap_msgfree, (VALUE) cmsg);
}
if (rb_block_given_p ())
{
return self;
}
else
{
return ary;
}
}
#if defined(HAVE_LDAPCONTROL) && defined(HAVE_LDAP_SEARCH_EXT_S)
static int
rb_ldap_conn_search_ext_i (int argc, VALUE argv[], VALUE self,
RB_LDAP_DATA ** ldapdata, LDAPMessage ** cmsg)
{
VALUE base, scope, filter, attrs, attrsonly;
VALUE serverctrls, clientctrls, sec, usec, limit, s_attr, s_proc;
LDAP *cldap;
char *cbase;
int cscope;
int climit;
char *cfilter;
char **cattrs;
char *sort_attr;
int cattrsonly;
int i;
struct timeval tv;
LDAPControl **sctrls, **cctrls;
GET_LDAP_DATA (self, (*ldapdata));
cldap = (*ldapdata)->ldap;
cattrs = NULL;
cattrsonly = 0;
cctrls = NULL;
sctrls = NULL;
tv.tv_sec = 0;
tv.tv_usec = 0;
sort_attr = NULL;
rb_ldap_sort_obj = Qnil;
climit = 0;
switch (rb_scan_args (argc, argv, "39",
&base, &scope, &filter, &attrs, &attrsonly,
&serverctrls, &clientctrls, &sec, &usec, &limit,
&s_attr, &s_proc))
{
case 12:
rb_ldap_sort_obj = s_proc; /* Ruby's GC never start in a C function */
case 11:
if (rb_ldap_sort_obj == Qnil)
{
rb_ldap_sort_obj = Qtrue;
}
sort_attr = StringValueCStr (s_attr);
case 10:
climit = NUM2INT (limit);
case 9:
tv.tv_usec = NUM2INT (usec);
case 8:
tv.tv_sec = NUM2INT (sec);
case 7:
cctrls = rb_ldap_get_controls (clientctrls);
case 6:
sctrls = rb_ldap_get_controls (serverctrls);
case 5:
cattrsonly = (attrsonly == Qtrue) ? 1 : 0;
case 4:
if (TYPE (attrs) == T_NIL)
{
cattrs = NULL;
}
else
{
if (TYPE (attrs) == T_STRING)
attrs = rb_ary_to_ary (attrs);
else
Check_Type (attrs, T_ARRAY);
if (RARRAY_LEN (attrs) == 0)
{
cattrs = NULL;
}
else
{
cattrs = ALLOCA_N (char *, (RARRAY_LEN (attrs) + 1));
for (i = 0; i < RARRAY_LEN (attrs); i++)
{
cattrs[i] = StringValueCStr (RARRAY_PTR (attrs)[i]);
};
cattrs[RARRAY_LEN (attrs)] = NULL;
}
}
case 3:
cbase = StringValueCStr (base);
cscope = NUM2INT (scope);
cfilter = StringValueCStr (filter);
break;
default:
rb_bug ("rb_ldap_conn_search_s");
};
(*cmsg) = NULL;
if (tv.tv_sec == 0 && tv.tv_usec == 0)
{
(*ldapdata)->err = ldap_search_ext_s (cldap, cbase, cscope, cfilter,
cattrs, cattrsonly,
sctrls, cctrls,
NULL, climit, cmsg);
}
else
{
(*ldapdata)->err = ldap_search_ext_s (cldap, cbase, cscope, cfilter,
cattrs, cattrsonly,
sctrls, cctrls,
&tv, climit, cmsg);
}
Check_LDAP_Result ((*ldapdata)->err);
#ifdef HAVE_LDAP_SORT_ENTRIES
if (rb_ldap_sort_obj != Qnil)
{
ldap_sort_entries ((*ldapdata)->ldap, cmsg,
sort_attr, rb_ldap_internal_strcmp);
};
#endif
rb_ldap_sort_obj = Qnil;
return (*ldapdata)->err;
};
/*
* call-seq:
* conn.search_ext(base_dn, scope, filter, attrs=nil, attrsonly=false,
* sctrls, cctrls, sec=0, usec=0, s_attr=nil, s_proc=nil)
* { |entry| } => self
*
* Perform a search, with the base DN +base_dn+, a scope of +scope+ and a
* search filter of +filter+.
*
* If +attrs+ is present, it should be an array of the attributes that the
* search should return. By default, all attributes are returned, which is the
* same as specifying an empty array or *nil*. Alternatively, +attrs+ may be a
* single string, in which case it will be treated as a single element array.
*
* If +attrsonly+ is *true*, attributes will be returned, but not their values.
*
* +sctrls+ is an array of server controls, whilst +cctrls+ is an array of
* client controls.
*
* If +sec+ and/or +usec+ are given, they define the time-out for the search in
* seconds and microseconds, respectively.
*
* If +s_attr+ is given, it specifies the attribute on which to sort the
* entries returned by the server. If +s_proc+ is given, it specifies a Proc
* object that will be used to sort the entries returned by the server.
*
* Note that not all results may be returned by this method. If a
* size limit has been set for the number of results to be returned and this
* limit is exceeded, the results set will be truncated. You can check for
* this by calling LDAP::Conn#err immediately after this method and comparing
* the result to LDAP::LDAP_SIZELIMIT_EXCEEDED.
*/
VALUE
rb_ldap_conn_search_ext_s (int argc, VALUE argv[], VALUE self)
{
RB_LDAP_DATA *ldapdata;
LDAPMessage *cmsg;
LDAP *cldap;
rb_ldap_conn_search_ext_i (argc, argv, self, &ldapdata, &cmsg);
cldap = ldapdata->ldap;
if (ldapdata->err == LDAP_SUCCESS
|| ldapdata->err == LDAP_SIZELIMIT_EXCEEDED)
{
void *pass_data[] = { (void *) cldap, (void *) cmsg };
rb_ensure (rb_ldap_conn_search_b, (VALUE) pass_data,
rb_ldap_msgfree, (VALUE) cmsg);
};
return self;
};
/*
* call-seq:
* conn.search_ext2(base_dn, scope, filter, attrs=nil,
* attrsonly=false, sctrls, cctrls, sec=0, usec=0,
* s_attr=nil, s_proc=nil) => array
* conn.search_ext2(base_dn, scope, filter, attrs=nil,
* attrsonly=false, sctrls, cctrls, sec=0, usec=0,
* s_attr=nil, s_proc=nil) { |entry_as_hash| } => self
*
* Perform a search, with the base DN +base_dn+, a scope of +scope+ and a
* search filter of +filter+.
*
* If +attrs+ is present, it should be an array of the attributes that the
* search should return. By default, all attributes are returned, which is the
* same as specifying an empty array or *nil*. Alternatively, +attrs+ may be a
* single string, in which case it will be treated as a single element array.
*
* If +attrsonly+ is *true*, attributes will be returned, but not their values.
*
* +sctrls+ is an array of server controls, whilst +cctrls+ is an array of
* client controls.
*
* If +sec+ and/or +usec+ are given, they define the time-out for the search in
* seconds and microseconds, respectively.
*
* If +s_attr+ is given, it specifies the attribute on which to sort the
* entries returned by the server. If +s_proc+ is given, it specifies a Proc
* object that will be used to sort the entries returned by the server.
*
* Note that not all results may be returned by this method. If a
* size limit has been set for the number of results to be returned and this
* limit is exceeded, the results set will be truncated. You can check for
* this by calling LDAP::Conn#err immediately after this method and comparing
* the result to LDAP::LDAP_SIZELIMIT_EXCEEDED.
*/
VALUE
rb_ldap_conn_search_ext2_s (int argc, VALUE argv[], VALUE self)
{
RB_LDAP_DATA *ldapdata;
LDAPMessage *cmsg;
LDAP *cldap;
VALUE ary;
rb_ldap_conn_search_ext_i (argc, argv, self, &ldapdata, &cmsg);
cldap = ldapdata->ldap;
ary = rb_ary_new ();
if (ldapdata->err == LDAP_SUCCESS
|| ldapdata->err == LDAP_SIZELIMIT_EXCEEDED)
{
void *pass_data[] = { (void *) cldap, (void *) cmsg, (void *) ary };
rb_ensure (rb_ldap_conn_search2_b, (VALUE) pass_data,
rb_ldap_msgfree, (VALUE) cmsg);
}
if (rb_block_given_p ())
{
return self;
}
else
{
return ary;
}
}
#endif
/*
* call-seq:
* conn.add(dn, attrs) => self
*
* Add an entry with the DN, +dn+, and the attributes, +attrs+. +attrs+
* should be either an array of LDAP#Mod objects or a hash of attribute/value
* array pairs.
*/
VALUE
rb_ldap_conn_add_s (VALUE self, VALUE dn, VALUE attrs)
{
RB_LDAP_DATA *ldapdata;
char *c_dn;
LDAPMod **c_attrs;
int i;
switch (TYPE (attrs))
{
case T_HASH:
attrs = rb_ldap_hash2mods (rb_mLDAP,
INT2NUM (LDAP_MOD_ADD | LDAP_MOD_BVALUES),
attrs);
break;
case T_ARRAY:
break;
default:
rb_raise (rb_eTypeError, "must be a hash or an array");
};
GET_LDAP_DATA (self, ldapdata);
c_dn = StringValueCStr (dn);
c_attrs = ALLOCA_N (LDAPMod *, (RARRAY_LEN (attrs) + 1));
for (i = 0; i < RARRAY_LEN (attrs); i++)
{
VALUE mod = RARRAY_PTR (attrs)[i];
RB_LDAPMOD_DATA *moddata;
Check_Kind (mod, rb_cLDAP_Mod);
GET_LDAPMOD_DATA (mod, moddata);
c_attrs[i] = moddata->mod;
};
c_attrs[i] = NULL;
ldapdata->err = ldap_add_s (ldapdata->ldap, c_dn, c_attrs);
Check_LDAP_Result (ldapdata->err);
return self;
};
#if defined(HAVE_LDAPCONTROL) && defined(HAVE_LDAP_ADD_EXT_S)
/*
* call-seq:
* conn.add_ext(dn, attrs, sctrls, cctrls) => self
*
* Add an entry with the DN, +dn+, and the attributes, +attrs+. +attrs+
* should be either an array of LDAP#Mod objects or a hash of attribute/value
* array pairs. +sctrls+ is an array of server controls, whilst +cctrls+ is
* an array of client controls.
*/
VALUE
rb_ldap_conn_add_ext_s (VALUE self, VALUE dn, VALUE attrs,
VALUE serverctrls, VALUE clientctrls)
{
RB_LDAP_DATA *ldapdata;
char *c_dn;
LDAPMod **c_attrs;
int i;
LDAPControl **sctrls, **cctrls;
switch (TYPE (attrs))
{
case T_HASH:
attrs = rb_ldap_hash2mods (rb_mLDAP,
INT2NUM (LDAP_MOD_ADD | LDAP_MOD_BVALUES),
attrs);
break;
case T_ARRAY:
break;
default:
rb_raise (rb_eTypeError, "must be a hash or an array");
};
GET_LDAP_DATA (self, ldapdata);
c_dn = StringValueCStr (dn);
c_attrs = ALLOCA_N (LDAPMod *, (RARRAY_LEN (attrs) + 1));
sctrls = rb_ldap_get_controls (serverctrls);
cctrls = rb_ldap_get_controls (clientctrls);
for (i = 0; i < RARRAY_LEN (attrs); i++)
{
VALUE mod = RARRAY_PTR (attrs)[i];
RB_LDAPMOD_DATA *moddata;
Check_Kind (mod, rb_cLDAP_Mod);
GET_LDAPMOD_DATA (mod, moddata);
c_attrs[i] = moddata->mod;
};
c_attrs[i] = NULL;
ldapdata->err =
ldap_add_ext_s (ldapdata->ldap, c_dn, c_attrs, sctrls, cctrls);
Check_LDAP_Result (ldapdata->err);
return self;
}
#endif
/*
* call-seq:
* conn.modify(dn, mods) => self
*
* Modify an entry with the DN, +dn+, and the attributes, +mods+. +mods+
* should be either an array of LDAP#Mod objects or a hash of attribute/value
* array pairs.
*/
VALUE
rb_ldap_conn_modify_s (VALUE self, VALUE dn, VALUE attrs)
{
RB_LDAP_DATA *ldapdata;
char *c_dn;
LDAPMod **c_attrs;
int i;
switch (TYPE (attrs))
{
case T_HASH:
attrs =
rb_ldap_hash2mods (rb_mLDAP,
INT2NUM (LDAP_MOD_REPLACE | LDAP_MOD_BVALUES),
attrs);
break;
case T_ARRAY:
break;
default:
rb_raise (rb_eTypeError, "must be a hash or an array");
};
GET_LDAP_DATA (self, ldapdata);
c_dn = StringValueCStr (dn);
c_attrs = ALLOC_N (LDAPMod *, RARRAY_LEN (attrs) + 1);
for (i = 0; i < RARRAY_LEN (attrs); i++)
{
VALUE mod = RARRAY_PTR (attrs)[i];
RB_LDAPMOD_DATA *moddata;
Check_Kind (mod, rb_cLDAP_Mod);
GET_LDAPMOD_DATA (mod, moddata);
c_attrs[i] = moddata->mod;
};
c_attrs[i] = NULL;
ldapdata->err = ldap_modify_s (ldapdata->ldap, c_dn, c_attrs);
Check_LDAP_Result (ldapdata->err);
return self;
};
#if defined(HAVE_LDAPCONTROL) && defined(HAVE_LDAP_MODIFY_EXT_S)
/*
* call-seq:
* conn.modify_ext(dn, mods, sctrls, cctrls) => self
*
* Modify an entry with the DN, +dn+, and the attributes, +mods+. +mods+
* should be either an array of LDAP#Mod objects or a hash of attribute/value
* array pairs. +sctrls+ is an array of server controls, whilst +cctrls+ is
* an array of client controls.
*/
VALUE
rb_ldap_conn_modify_ext_s (VALUE self, VALUE dn, VALUE attrs,
VALUE serverctrls, VALUE clientctrls)
{
RB_LDAP_DATA *ldapdata;
char *c_dn;
LDAPMod **c_attrs;
int i;
LDAPControl **sctrls, **cctrls;
switch (TYPE (attrs))
{
case T_HASH:
attrs =
rb_ldap_hash2mods (rb_mLDAP,
INT2NUM (LDAP_MOD_REPLACE | LDAP_MOD_BVALUES),
attrs);
break;
case T_ARRAY:
break;
default:
rb_raise (rb_eTypeError, "must be a hash or an array");
};
GET_LDAP_DATA (self, ldapdata);
c_dn = StringValueCStr (dn);
c_attrs = ALLOC_N (LDAPMod *, RARRAY_LEN (attrs) + 1);
sctrls = rb_ldap_get_controls (serverctrls);
cctrls = rb_ldap_get_controls (clientctrls);
for (i = 0; i < RARRAY_LEN (attrs); i++)
{
VALUE mod = RARRAY_PTR (attrs)[i];
RB_LDAPMOD_DATA *moddata;
Check_Kind (mod, rb_cLDAP_Mod);
GET_LDAPMOD_DATA (mod, moddata);
c_attrs[i] = moddata->mod;
};
c_attrs[i] = NULL;
ldapdata->err =
ldap_modify_ext_s (ldapdata->ldap, c_dn, c_attrs, sctrls, cctrls);
Check_LDAP_Result (ldapdata->err);
return self;
}
#endif
/*
* call-seq:
* conn.modrdn(dn, new_rdn, delete_old_rdn) => self
*
* Modify the RDN of the entry with DN, +dn+, giving it the new RDN,
* +new_rdn+. If +delete_old_rdn+ is *true*, the old RDN value will be deleted
* from the entry.
*/
VALUE
rb_ldap_conn_modrdn_s (VALUE self, VALUE dn, VALUE newrdn, VALUE delete_p)
{
RB_LDAP_DATA *ldapdata;
char *c_dn;
char *c_newrdn;
int c_delete_p;
GET_LDAP_DATA (self, ldapdata);
c_dn = StringValueCStr (dn);
c_newrdn = StringValueCStr (newrdn);
c_delete_p = (delete_p == Qtrue) ? 1 : 0;
ldapdata->err = ldap_modrdn2_s (ldapdata->ldap, c_dn, c_newrdn, c_delete_p);
Check_LDAP_Result (ldapdata->err);
return self;
};
/*
* call-seq:
* conn.delete(dn) => self
*
* Delete the entry with the DN, +dn+.
*/
VALUE
rb_ldap_conn_delete_s (VALUE self, VALUE dn)
{
RB_LDAP_DATA *ldapdata;
char *c_dn;
GET_LDAP_DATA (self, ldapdata);
c_dn = StringValueCStr (dn);
ldapdata->err = ldap_delete_s (ldapdata->ldap, c_dn);
Check_LDAP_Result (ldapdata->err);
return self;
};
#if defined(HAVE_LDAPCONTROL) && defined(HAVE_LDAP_DELETE_EXT_S)
/*
* call-seq:
* conn.delete_ext(dn, sctrls, cctrls) => self
*
* Delete the entry with the DN, +dn+. +sctrls+ is an array of server
* controls, whilst +cctrls+ is an array of client controls.
*/
VALUE
rb_ldap_conn_delete_ext_s (VALUE self, VALUE dn,
VALUE serverctrls, VALUE clientctrls)
{
RB_LDAP_DATA *ldapdata;
char *c_dn;
LDAPControl **sctrls, **cctrls;
GET_LDAP_DATA (self, ldapdata);
c_dn = StringValueCStr (dn);
sctrls = rb_ldap_get_controls (serverctrls);
cctrls = rb_ldap_get_controls (clientctrls);
ldapdata->err = ldap_delete_ext_s (ldapdata->ldap, c_dn, sctrls, cctrls);
Check_LDAP_Result (ldapdata->err);
return self;
}
#endif
#if defined(HAVE_LDAP_COMPARE_S)
/*
* call-seq:
* conn.compare(dn, attr, val) => true or false
*
* Compare the DN given as +dn+ to see whether it has the attribute +attr+
* with a value of +val+.
*/
VALUE
rb_ldap_conn_compare_s (VALUE self, VALUE dn, VALUE attr, VALUE val)
{
RB_LDAP_DATA *ldapdata;
char *c_dn, *c_attr, *c_val;
GET_LDAP_DATA (self, ldapdata);
c_dn = StringValueCStr (dn);
c_attr = StringValueCStr (attr);
c_val = StringValueCStr (val);
ldapdata->err = ldap_compare_s (ldapdata->ldap, c_dn, c_attr, c_val);
if ((ldapdata->err) == LDAP_COMPARE_TRUE)
return Qtrue;
else if ((ldapdata->err) == LDAP_COMPARE_FALSE)
return Qfalse;
Check_LDAP_Result (ldapdata->err);
fprintf (stderr, "rb_ldap_conn_compare_s() unexpectedly set no error.\n");
return self;
}
#endif
#if defined(HAVE_LDAPCONTROL) && defined(HAVE_LDAP_COMPARE_EXT_S)
/*
* call-seq:
* conn.compare_ext(dn, attr, val, sctrls, cctrls) => true or false
*
* Compare the DN given as +dn+ to see whether it has the attribute +attr+
* with a value of +val+. +sctrls+ is an array of server controls, whilst
* +cctrls+ is an array of client controls.
*/
VALUE
rb_ldap_conn_compare_ext_s (VALUE self, VALUE dn, VALUE attr, VALUE val,
VALUE serverctrls, VALUE clientctrls)
{
RB_LDAP_DATA *ldapdata;
char *c_dn, *c_attr;
#ifdef USE_WLDAP32
char *c_val;
#endif
struct berval bval;
LDAPControl **sctrls, **cctrls;
GET_LDAP_DATA (self, ldapdata);
c_dn = StringValueCStr (dn);
c_attr = StringValueCStr (attr);
#ifdef USE_WLDAP32
c_val = StringValueCStr (val);
#endif
bval.bv_val = StringValueCStr (val);
bval.bv_len = RSTRING_LEN (val);
sctrls = rb_ldap_get_controls (serverctrls);
cctrls = rb_ldap_get_controls (clientctrls);
ldapdata->err = ldap_compare_ext_s (ldapdata->ldap, c_dn, c_attr,
#ifdef USE_WLDAP32
c_val,
#endif
&bval, sctrls, cctrls);
if ((ldapdata->err) == LDAP_COMPARE_TRUE)
return Qtrue;
else if ((ldapdata->err) == LDAP_COMPARE_FALSE)
return Qfalse;
Check_LDAP_Result (ldapdata->err);
fprintf (stderr,
"rb_ldap_conn_compare_ext_s() unexpectedly set no error.\n");
return self;
}
#endif
/*
* call-seq:
* conn.err => Fixnum
*
* Return the error associated with the most recent LDAP operation.
*/
VALUE
rb_ldap_conn_err (VALUE self)
{
RB_LDAP_DATA *ldapdata;
GET_LDAP_DATA (self, ldapdata);
return INT2NUM (ldapdata->err);
};
/* Document-class: LDAP::Conn
*
* Create and manipulate unencrypted LDAP connections.
*/
void
Init_ldap_conn ()
{
rb_ldap_sort_obj = Qnil;
rb_cLDAP_Conn = rb_define_class_under (rb_mLDAP, "Conn", rb_cData);
rb_define_attr (rb_cLDAP_Conn, "referrals", 1, 0);
rb_define_attr (rb_cLDAP_Conn, "controls", 1, 0);
rb_define_attr (rb_cLDAP_Conn, "sasl_quiet", 1, 1);
#if RUBY_VERSION_CODE < 170
rb_define_singleton_method (rb_cLDAP_Conn, "new", rb_ldap_class_new, -1);
#endif
#if RUBY_VERSION_CODE >= 173
rb_define_alloc_func (rb_cLDAP_Conn, rb_ldap_conn_s_allocate);
#else
rb_define_singleton_method (rb_cLDAP_Conn, "allocate",
rb_ldap_conn_s_allocate, 0);
#endif
rb_define_singleton_method (rb_cLDAP_Conn, "open", rb_ldap_conn_s_open, -1);
rb_define_singleton_method (rb_cLDAP_Conn, "set_option",
rb_ldap_conn_s_set_option, 2);
rb_define_singleton_method (rb_cLDAP_Conn, "get_option",
rb_ldap_conn_s_get_option, 1);
rb_ldap_conn_define_method ("initialize", rb_ldap_conn_initialize, -1);
rb_ldap_conn_define_method ("start_tls", rb_ldap_conn_start_tls_s, -1);
rb_ldap_conn_define_method ("simple_bind", rb_ldap_conn_simple_bind_s, -1);
rb_ldap_conn_define_method ("bind", rb_ldap_conn_bind_s, -1);
rb_ldap_conn_define_method ("bound?", rb_ldap_conn_bound, 0);
rb_ldap_conn_define_method ("unbind", rb_ldap_conn_unbind, 0);
rb_ldap_conn_define_method ("set_option", rb_ldap_conn_set_option, 2);
rb_ldap_conn_define_method ("get_option", rb_ldap_conn_get_option, 1);
rb_ldap_conn_define_method ("search", rb_ldap_conn_search_s, -1);
rb_ldap_conn_define_method ("search2", rb_ldap_conn_search2_s, -1);
rb_ldap_conn_define_method ("add", rb_ldap_conn_add_s, 2);
rb_ldap_conn_define_method ("modify", rb_ldap_conn_modify_s, 2);
rb_ldap_conn_define_method ("modrdn", rb_ldap_conn_modrdn_s, 3);
rb_ldap_conn_define_method ("delete", rb_ldap_conn_delete_s, 1);
#if defined(HAVE_LDAP_COMPARE_S)
rb_ldap_conn_define_method ("compare", rb_ldap_conn_compare_s, 3);
#endif
rb_ldap_conn_define_method ("perror", rb_ldap_conn_perror, 1);
rb_ldap_conn_define_method ("err2string", rb_ldap_conn_err2string, 1);
rb_ldap_conn_define_method ("result2error", rb_ldap_conn_result2error, 1);
rb_ldap_conn_define_method ("err", rb_ldap_conn_err, 0);
#if defined(HAVE_LDAP_SEARCH_EXT_S)
rb_ldap_conn_define_method ("search_ext", rb_ldap_conn_search_ext_s, -1);
rb_ldap_conn_define_method ("search_ext2", rb_ldap_conn_search_ext2_s, -1);
#endif
#if defined(HAVE_LDAP_ADD_EXT_S)
rb_ldap_conn_define_method ("add_ext", rb_ldap_conn_add_ext_s, 4);
#endif
#if defined(HAVE_LDAP_MODIFY_EXT_S)
rb_ldap_conn_define_method ("modify_ext", rb_ldap_conn_modify_ext_s, 4);
#endif
#if defined(HAVE_LDAP_DELETE_EXT_S)
rb_ldap_conn_define_method ("delete_ext", rb_ldap_conn_delete_ext_s, 3);
#endif
#if defined(HAVE_LDAP_COMPARE_EXT_S)
rb_ldap_conn_define_method ("compare_ext", rb_ldap_conn_compare_ext_s, 5);
#endif
};
% make
cc -I. -I. -I/usr/lib/ruby/1.8/i486-linux -I. -DUSE_OPENLDAP2 -DUSE_OPENLDAP -DLDAP_DEPRECATED -D_REENTRANT -DHAVE_LDAP_H -DHAVE_LBER_H -DHAVE_OPENSSL_SSL_H -DHAVE_OPENSSL_CRYPTO_H -DHAVE_LDAP_INIT -DHAVE_LDAP_SET_OPTION -DHAVE_LDAP_GET_OPTION -DHAVE_LDAP_START_TLS_S -DHAVE_LDAP_MEMFREE -DHAVE_LDAP_PERROR -DHAVE_LDAP_SORT_ENTRIES -DHAVE_LDAP_SASL_BIND_S -DHAVE_LDAP_COMPARE_S -DHAVE_LDAP_ADD_EXT_S -DHAVE_LDAP_COMPARE_EXT_S -DHAVE_LDAP_DELETE_EXT_S -DHAVE_LDAP_MODIFY_EXT_S -DHAVE_LDAP_SEARCH_EXT_S -DHAVE_LDAP_UNBIND_EXT_S -DHAVE_LDAP_SASL_INTERACTIVE_BIND_S -DRUBY_VERSION_CODE=187 -D_FILE_OFFSET_BITS=64 -fPIC -fno-strict-aliasing -g -g -O2 -fPIC -c conn.c
conn.c: In function ‘rb_ldap_conn_set_option’:
conn.c:501: error: ‘LDAP_OPT_X_TLS_PROTOCOL’ undeclared (first use in this function)
conn.c:501: error: (Each undeclared identifier is reported only once
conn.c:501: error: for each function it appears in.)
conn.c: In function ‘rb_ldap_conn_get_option’:
conn.c:631: error: ‘LDAP_OPT_X_TLS_PROTOCOL’ undeclared (first use in this function)
make: *** [conn.o] Error 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment