Commits

Michael Granger  committed 8ad7ee7

Prep for resuming work.

  • Participants
  • Parent commits a16c62d

Comments (0)

Files changed (20)

 \.conf$
 ^doc/
 ^pkg/
+^ChangeLog$
+# .rvm.gems generated gem export file. Note that any env variable settings will be missing. Append these after using a ';' field separator
+hoe-deveiate -v0.2.0
+loggability -v0.5.0
+rake-compiler -v0.8.3
-rvm use 1.9.2
+#!/usr/bin/env bash
+
+# This is an RVM Project .rvmrc file, used to automatically load the ruby
+# development environment upon cd'ing into the directory
+
+environment_id="2.0.0@openldap"
+
+if [[ -d "${rvm_path:-$HOME/.rvm}/environments" \
+	&& -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]; then
+	echo "Using ${environment_id}"
+	. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
+
+	if [[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]]; then
+		. "${rvm_path:-$HOME/.rvm}/hooks/after_use"
+	fi
+else
+	# If the environment file has not yet been created, use the RVM CLI to select.
+	if ! rvm --create use  "$environment_id"
+		then
+		echo "Failed to create RVM environment '${environment_id}'."
+		exit 1
+	fi
+fi
+
+filename=".rvm.gems"
+if [[ -s "$filename" ]]; then
+	rvm gemset import "$filename"
+fi
+
+echo "LDAP: It's not as scary as you think!"
+echo
+

File Manifest.txt

+.autotest
 .gemtest
+ChangeLog
 History.md
 Manifest.txt
 README.md
 Rakefile
 Roadmap.md
-ext/connection.c
-ext/openldap.c
-ext/openldap.h
+ext/openldap_ext/connection.c
+ext/openldap_ext/extconf.rb
+ext/openldap_ext/openldap.c
+ext/openldap_ext/openldap.h
 lib/openldap.rb
 lib/openldap/connection.rb
 lib/openldap/exceptions.rb
 lib/openldap/mixins.rb
-lib/openldap/utils.rb
+slapd.conf
+spec/data/slapd.conf
 spec/lib/constants.rb
 spec/lib/helpers.rb
 spec/openldap/connection_spec.rb
 spec/openldap/exceptions_spec.rb
 spec/openldap_spec.rb
+test.conf
 test.conf-example
 LIBDIR  = BASEDIR + 'lib'
 EXTDIR  = BASEDIR + 'ext'
 
-EXTCONF = EXTDIR + 'extconf.rb'
-
-DLEXT   = Config::CONFIG['DLEXT']
+DLEXT   = RbConfig::CONFIG['DLEXT']
 EXT     = LIBDIR + "bluecloth_ext.#{DLEXT}"
+RUBY    = RbConfig.expand( "$(prefix)/$(ruby_install_name)" )
 
 VALGRIND_OPTIONS = [
 	"--num-callers=50",
 	self.developer 'Michael Granger', 'ged@FaerieMUD.org'
 
 	self.dependency 'rake-compiler', '~> 0.7', :developer
-	self.dependency 'rspec',         '~> 2.6', :developer
+	self.dependency 'hoe-deveiate',  '~> 0.2', :developer
 
 	self.spec_extras[:licenses] = ["BSD"]
-	self.spec_extras[:signing_key] = '/Volumes/Keys/ged-private_gem_key.pem'
-	self.spec_extras[:extensions] = [ EXTCONF.to_s ]
-	self.extra_rdoc_files += ['ext/connection.c', 'ext/openldap.c']
+	# self.spec_extras[:extensions] = [ 'lib/openldap' ]
 
 	self.require_ruby_version( '>= 1.9.2' )
 
 	ENV['MAINTAINER_MODE'] = 'yes'
 end
 
-ENV['RUBY_CC_VERSION'] = '1.8.7:1.9.2'
-
 # Rake-compiler task
-Rake::ExtensionTask.new do |ext|
-	ext.name           = 'openldap_ext'
-	ext.gem_spec       = hoespec.spec
-	ext.ext_dir        = 'ext'
-	ext.source_pattern = "*.{c,h}"
-	ext.cross_compile  = true
-	ext.cross_platform = %w[i386-mswin32 i386-mingw32]
-end
+Rake::ExtensionTask.new( 'openldap_ext' )
 
 
 namespace :spec do
 
 end
 
-### Make the ChangeLog update if the repo has changed since it was last built
-file '.hg/branch'
-file 'ChangeLog' => '.hg/branch' do |task|
-	$stderr.puts "Updating the changelog..."
-	content = nil
-
-	begin
-		content = make_changelog()
-	rescue NoMethodError
-		abort "Releasing requires the hoe-mercurial plugin (gem install hoe-mercurial)"
-	end
-
-	File.open( task.name, 'w', 0644 ) do |fh|
-		fh.print( content )
-	end
-end
-
 # Rebuild the ChangeLog immediately before release
 task :prerelease => 'ChangeLog'
 

File ext/connection.c

-/*
- * Ruby-OpenLDAP -- a Ruby binding to OpenLDAP's libldap
- * $Id$
- *
- * Authors
- *
- * - Michael Granger <ged@FaerieMUD.org>
- *
- * Copyright (c) 2011 Michael Granger
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are
- * permitted provided that the following conditions are met:
- *
- *  * Redistributions of source code must retain the above copyright notice, this
- *    list of conditions and the following disclaimer.
- *
- *  * Redistributions in binary form must reproduce the above copyright notice, this
- *    list of conditions and the following disclaimer in the documentation and/or
- *    other materials provided with the distribution.
- *
- *  * Neither the name of the authors, nor the names of its contributors may be used to
- *    endorse or promote products derived from this software without specific prior
- *    written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *
- */
-
-#include "openldap.h"
-
-
-#define MILLION_F 1000000.0
-
-
-/* --------------------------------------------------------------
- * Declarations
- * -------------------------------------------------------------- */
-VALUE ropenldap_cOpenLDAPConnection;
-
-
-/* --------------------------------------------------
- *	Memory-management functions
- * -------------------------------------------------- */
-
-/*
- * Allocation function
- */
-static struct ropenldap_connection *
-ropenldap_conn_alloc( LDAP *ldp )
-{
-	struct ropenldap_connection *ptr = ALLOC( struct ropenldap_connection );
-
-	ptr->ldap = ldp;
-
-	return ptr;
-}
-
-
-/*
- * GC Mark function
- */
-static void
-ropenldap_conn_gc_mark( struct ropenldap_connection *ptr )
-{
-	/* No-op */
-}
-
-
-
-/*
- * GC Free function
- */
-static void
-ropenldap_conn_gc_free( struct ropenldap_connection *ptr )
-{
-	if ( ptr ) {
-		ptr->ldap = NULL;
-
-		xfree( ptr );
-		ptr = NULL;
-	}
-}
-
-
-/*
- * Object validity checker. Returns the data pointer.
- */
-static struct ropenldap_connection *
-check_conn( VALUE self )
-{
-	Check_Type( self, T_DATA );
-
-    if ( !IsConnection(self) ) {
-		rb_raise( rb_eTypeError, "wrong argument type %s (expected an OpenLDAP::Connection)",
-				  rb_obj_classname( self ) );
-    }
-
-	return DATA_PTR( self );
-}
-
-
-/*
- * Fetch the data pointer and check it for sanity.
- */
-static struct ropenldap_connection *
-ropenldap_get_conn( VALUE self )
-{
-	struct ropenldap_connection *conn = check_conn( self );
-
-	if ( !conn ) rb_fatal( "Use of uninitialized OpenLDAP::Connection" );
-
-	return conn;
-}
-
-
-
-/* --------------------------------------------------------------
- * Class methods
- * -------------------------------------------------------------- */
-
-/*
- * call-seq:
- *    OpenLDAP::Connection.allocate   -> store
- *
- * Allocate a new OpenLDAP::Connection object.
- *
- */
-static VALUE
-ropenldap_conn_s_allocate( VALUE klass )
-{
-	return Data_Wrap_Struct( klass, ropenldap_conn_gc_mark, ropenldap_conn_gc_free, 0 );
-}
-
-
-/* --------------------------------------------------------------
- * Instance methods
- * -------------------------------------------------------------- */
-
-/*
- * call-seq:
- *    OpenLDAP::Connection.new( *uris )           -> conn
- *
- * Create a new OpenLDAP::Connection object using the given +uris+.
- *
- */
-static VALUE
-ropenldap_conn_initialize( VALUE self, VALUE urls )
-{
-	ropenldap_log_obj( self, "debug", "Initializing 0x%x", self );
-
-	if ( !check_conn(self) ) {
-		VALUE urlstring;
-		LDAP *ldp = NULL;
-		char *url = NULL;
-		struct ropenldap_connection *conn;
-		int result = 0;
-		int proto_ver = 3;
-
-		urlstring = rb_funcall( urls, rb_intern("join"), 1, rb_str_new(" ", 1) );
-		url = RSTRING_PTR( rb_obj_as_string(urlstring) );
-
-		if ( !ldap_is_ldap_url(url) )
-			rb_raise( rb_eArgError, "'%s' is not an LDAP url", url );
-
-		ropenldap_log_obj( self, "info", "Creating a new %s (%s)", rb_obj_classname(self), url );
-		result = ldap_initialize( &ldp, url );
-		ropenldap_check_result( result, "ldap_initialize( \"%s\" )", url );
-
-		conn = DATA_PTR( self ) = ropenldap_conn_alloc( ldp );
-
-	} else {
-		rb_raise( ropenldap_eOpenLDAPError,
-				  "Cannot re-initialize a store once it's been created." );
-	}
-
-	return Qnil;
-}
-
-
-/*
- * call-seq:
- *    conn.protocol_version   -> fixnum
- *
- * Get the protocol version use by the connection.
- *
- *    conn.protocol_version
- *    # => 3
- */
-static VALUE
-ropenldap_conn_protocol_version( VALUE self )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	int version = 0;
-
-	if ( ldap_get_option(ptr->ldap, LDAP_OPT_PROTOCOL_VERSION, &version) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't get option: LDAP_OPT_PROTOCOL_VERSION" );
-
-	return INT2FIX( version );
-}
-
-
-/*
- * call-seq:
- *    conn.protocol_version = version
- *
- * Set the protocol version use by the connection to +version+.
- *
- *    conn.protocol_version = 3
- *    # => 3
- */
-static VALUE
-ropenldap_conn_protocol_version_eq( VALUE self, VALUE version )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	int v = NUM2INT( version );
-
-	if ( ldap_set_option(ptr->ldap, LDAP_OPT_PROTOCOL_VERSION, &v) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't set option: LDAP_OPT_PROTOCOL_VERSION" );
-
-	return version;
-}
-
-
-/*
- * call-seq:
- *    conn.async_connect?   -> boolean
- *
- * Returns +true+ if the connect(2) call made by the library will be made asynchronously.
- *
- *    conn.async_connect?
- *    # => true
- */
-static VALUE
-ropenldap_conn_async_connect_p( VALUE self )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	int enabled;
-
-	if ( ldap_get_option(ptr->ldap, LDAP_OPT_CONNECT_ASYNC, &enabled) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't get option: LDAP_OPT_CONNECT_ASYNC" );
-
-	return enabled ? Qtrue : Qfalse;
-}
-
-
-/*
- * call-seq:
- *    conn.async_connect = boolean
- *
- * If set to a +true+ value, the library will call connect(2) and return without waiting for
- * a response.
- *
- *    conn.async_connect = true
- */
-static VALUE
-ropenldap_conn_async_connect_eq( VALUE self, VALUE boolean )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	int rv = 0;
-
-	if ( RTEST(boolean) ) {
-		ropenldap_log_obj( self, "debug", "Enabling async connect." );
-		rv = ldap_set_option( ptr->ldap, LDAP_OPT_CONNECT_ASYNC, LDAP_OPT_ON );
-	} else {
-		ropenldap_log_obj( self, "debug", "Disabling async connect." );
-		rv = ldap_set_option( ptr->ldap, LDAP_OPT_CONNECT_ASYNC, LDAP_OPT_OFF );
-	}
-
-	if ( rv != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't set option: LDAP_OPT_CONNECT_ASYNC" );
-
-	return RTEST( boolean ) ? Qtrue : Qfalse;
-}
-
-
-/*
- * call-seq:
- *    conn.network_timeout   -> float or nil
- *
- * Returns the network timeout value (if it is set).
- *
- *    conn.network_timeout
- *    # => 2.5
- */
-static VALUE
-ropenldap_conn_network_timeout( VALUE self )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	struct timeval *timeout;
-	double seconds = 0;
-
-	if ( ldap_get_option(ptr->ldap, LDAP_OPT_NETWORK_TIMEOUT, &timeout) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't get option: LDAP_OPT_NETWORK_TIMEOUT" );
-
-	if ( timeout ) {
-		ropenldap_log_obj( self, "debug", "Got network timeout: %d/%d",
-		                   timeout->tv_sec, timeout->tv_usec );
-		seconds = ((double) timeout->tv_sec) + timeout->tv_usec / MILLION_F;
-		ldap_memfree( timeout );
-		return rb_float_new( seconds );
-	} else {
-		ropenldap_log_obj( self, "debug", "No network timeout." );
-		return Qnil;
-	}
-}
-
-
-/*
- * call-seq:
- *    conn.network_timeout = float or nil
- *
- * Set the network timeout value; the network timeout value is the number of seconds after which
- * poll(2)/select(2) following a connect(2) returns in case of no activity. Setting this to nil
- * or -1 disables it.
- *
- *    conn.network_timeout = 1.0
- */
-static VALUE
-ropenldap_conn_network_timeout_eq( VALUE self, VALUE arg )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	double seconds;
-	struct timeval timeout;
-
-	if ( NIL_P(arg) ) {
-		seconds = -1.0;
-	} else {
-		seconds = NUM2DBL( arg );
-	}
-
-	ropenldap_log_obj( self, "debug", "Setting network timeout to %0.5f seconds", seconds );
-	timeout.tv_sec = (time_t)floor( seconds );
-	timeout.tv_usec = (suseconds_t)( fmod(seconds, 1.0) * MILLION_F );
-
-	if ( ldap_set_option(ptr->ldap, LDAP_OPT_NETWORK_TIMEOUT, (const void *)&timeout) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't set option: LDAP_OPT_NETWORK_TIMEOUT" );
-
-	return arg;
-}
-
-
-/*
- * call-seq:
- *    conn.simple_bind( bind_dn, password )   -> result
- *    conn.simple_bind( bind_dn, password ) {|result| ... }
- *
- * Bind to the directory using a simple +bind_dn+ and a +password+.
- *
- */
-static VALUE
-ropenldap_conn_simple_bind( VALUE self, VALUE bind_dn, VALUE password )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	return Qnil;
-}
-
-
-/*
- * Start TLS synchronously; called from ropenldap_conn__start_tls after
- * the GIL is released.
- */
-static VALUE
-ropenldap_conn__start_tls_body( void *ptr )
-{
-	LDAP *ld = ptr;
-	return (VALUE)ldap_start_tls_s( ld, NULL, NULL );
-}
-
-
-/*
- * #_start_ls: backend of the #start_tls method.
- */
-static VALUE
-ropenldap_conn__start_tls( VALUE self )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-
-	int result;
-
-	ropenldap_log_obj( self, "debug", "Starting TLS..." );
-	result = (int)rb_thread_blocking_region( ropenldap_conn__start_tls_body, (void *)ptr->ldap,
-		RUBY_UBF_IO, NULL );
-	ropenldap_check_result( result, "ldap_start_tls_s" );
-	ropenldap_log_obj( self, "debug", "  TLS started." );
-
-	return Qtrue;
-}
-
-
-/*
- * call-seq:
- *    conn.tls_inplace?   -> true or false
- *
- * Returns +true+ if TLS handlers have been installed on the session.
- *
- */
-static VALUE
-ropenldap_conn_tls_inplace_p( VALUE self )
-{
-#ifdef HAVE_LDAP_TLS_INPLACE
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-
-	if ( ldap_tls_inplace(ptr->ldap) ) {
-		return Qtrue;
-	} else {
-		return Qfalse;
-	}
-#else
-	rb_raise( rb_eNotImpError, "not implemented in your version of libldap" );
-#endif /* HAVE_LDAP_TLS_INPLACE */
-}
-
-
-/*
- * call-seq:
- *    conn.tls_cacertfile    -> string
- *
- * Get the full path of the CA certificate file as a String.
- */
-static VALUE
-ropenldap_conn_tls_cacertfile( VALUE self )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	char *path;
-	VALUE pathstring = Qnil;
-
-	if ( ldap_get_option(ptr->ldap, LDAP_OPT_X_TLS_CACERTFILE, &path) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't get option: LDAP_OPT_X_TLS_CACERTFILE" );
-	if ( !path )
-		return Qnil;
-
-	pathstring = rb_str_new2( path );
-	ldap_memfree( path );
-
-	return pathstring;
-}
-
-/*
- * call-seq:
- *    conn.tls_cacertfile = string
- *
- * Set the full path of the CA certificate file as a String.
- */
-static VALUE
-ropenldap_conn_tls_cacertfile_eq( VALUE self, VALUE path )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	VALUE pathstring = rb_obj_as_string( path );
-	const char *pathopt = StringValuePtr( pathstring );
-
-	if ( ldap_set_option(ptr->ldap, LDAP_OPT_X_TLS_CACERTFILE, pathopt) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't set option: LDAP_OPT_X_TLS_CACERTFILE" );
-
-	return path;
-}
-
-
-/*
- * call-seq:
- *    conn.tls_cacertdir    -> string
- *
- * Get the full path of the directory containing CA certificates as a String.
- */
-static VALUE
-ropenldap_conn_tls_cacertdir( VALUE self )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	char *path;
-	VALUE pathstring = Qnil;
-
-	if ( ldap_get_option(ptr->ldap, LDAP_OPT_X_TLS_CACERTDIR, &path) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't get option: LDAP_OPT_X_TLS_CACERTDIR" );
-	if ( !path )
-		return Qnil;
-
-	pathstring = rb_str_new2( path );
-	ldap_memfree( path );
-
-	return pathstring;
-}
-
-/*
- * call-seq:
- *    conn.tls_cacertdir = string
- *
- * Set the path of the directory containing CA certificates as a String.
- */
-static VALUE
-ropenldap_conn_tls_cacertdir_eq( VALUE self, VALUE path )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	VALUE pathstring = rb_obj_as_string( path );
-	const char *pathopt = StringValuePtr( pathstring );
-
-	if ( ldap_set_option(ptr->ldap, LDAP_OPT_X_TLS_CACERTDIR, pathopt) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't set option: LDAP_OPT_X_TLS_CACERTDIR" );
-
-	return path;
-}
-
-
-/*
- * call-seq:
- *    conn.tls_cacertfile    -> string
- *
- * Get the full path of the certificate file as a String.
- */
-static VALUE
-ropenldap_conn_tls_certfile( VALUE self )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	char *path;
-	VALUE pathstring = Qnil;
-
-	if ( ldap_get_option(ptr->ldap, LDAP_OPT_X_TLS_CERTFILE, &path) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't get option: LDAP_OPT_X_TLS_CERTFILE" );
-	if ( !path )
-		return Qnil;
-
-	pathstring = rb_str_new2( path );
-	ldap_memfree( path );
-
-	return pathstring;
-}
-
-/*
- * call-seq:
- *    conn.tls_certfile = string
- *
- * Set the full path of the certificate file as a String.
- */
-static VALUE
-ropenldap_conn_tls_certfile_eq( VALUE self, VALUE path )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	VALUE pathstring = rb_obj_as_string( path );
-	const char *pathopt = StringValuePtr( pathstring );
-
-	if ( ldap_set_option(ptr->ldap, LDAP_OPT_X_TLS_CERTFILE, pathopt) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't set option: LDAP_OPT_X_TLS_CERTFILE" );
-
-	return path;
-}
-
-
-/*
- * call-seq:
- *    conn.tls_keyfile    -> string
- *
- * Get the full path of the file that contains the private key that matches the certificate stored
- * in the #tls_certfile.
- */
-static VALUE
-ropenldap_conn_tls_keyfile( VALUE self )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	char *path;
-	VALUE pathstring = Qnil;
-
-	if ( ldap_get_option(ptr->ldap, LDAP_OPT_X_TLS_KEYFILE, &path) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't get option: LDAP_OPT_X_TLS_KEYFILE" );
-	if ( !path )
-		return Qnil;
-
-	pathstring = rb_str_new2( path );
-	ldap_memfree( path );
-
-	return pathstring;
-}
-
-/*
- * call-seq:
- *    conn.tls_keyfile = newvalue
- *
- * Set the full path to the file that contains the private key that matches the certificate stored
- * in the #tls_certfile.
- */
-static VALUE
-ropenldap_conn_tls_keyfile_eq( VALUE self, VALUE path )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	VALUE pathstring = rb_obj_as_string( path );
-	const char *pathopt = StringValuePtr( pathstring );
-
-	if ( ldap_set_option(ptr->ldap, LDAP_OPT_X_TLS_KEYFILE, pathopt) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't set option: LDAP_OPT_X_TLS_KEYFILE" );
-
-	return path;
-}
-
-
-/*
- * call-seq:
- *    conn.tls_cipher_suite    -> cipherstring
- *
- * Get the allowed cipher suite. See http://www.openssl.org/docs/apps/ciphers.html for the
- * allowed format of the +cipherstring+.
- */
-static VALUE
-ropenldap_conn_tls_cipher_suite( VALUE self )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	char *path;
-	VALUE pathstring = Qnil;
-
-	if ( ldap_get_option(ptr->ldap, LDAP_OPT_X_TLS_CIPHER_SUITE, &path) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't get option: LDAP_OPT_X_TLS_CIPHER_SUITE" );
-	if ( !path )
-		return Qnil;
-
-	pathstring = rb_str_new2( path );
-	ldap_memfree( path );
-
-	return pathstring;
-}
-
-/*
- * call-seq:
- *    conn.tls_cipher_suite = cipherstring
- *
- * Set the allowed cipher suite to +cipherstring+; see http://www.openssl.org/docs/apps/ciphers.html
- * for more about the format of this string.
- */
-static VALUE
-ropenldap_conn_tls_cipher_suite_eq( VALUE self, VALUE cipherstring )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	VALUE string = rb_obj_as_string( cipherstring );
-	const char *cipheropt = StringValuePtr( string );
-
-	if ( ldap_set_option(ptr->ldap, LDAP_OPT_X_TLS_CIPHER_SUITE, cipheropt) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't set option: LDAP_OPT_X_TLS_CIPHER_SUITE" );
-
-	return string;
-}
-
-
-/*
- * call-seq:
- *    conn.tls_random_file    -> true or false
- *
- * Get the path to the random file that will be used when /dev/random and /dev/urandom are
- * not available.
- */
-static VALUE
-ropenldap_conn_tls_random_file( VALUE self )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	char *path;
-	VALUE pathstring = Qnil;
-
-	if ( ldap_get_option(ptr->ldap, LDAP_OPT_X_TLS_RANDOM_FILE, &path) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't get option: LDAP_OPT_X_TLS_RANDOM_FILE" );
-	if ( !path )
-		return Qnil;
-
-	pathstring = rb_str_new2( path );
-	ldap_memfree( path );
-
-	return pathstring;
-}
-
-/*
- * call-seq:
- *    conn.tls_random_file = newvalue
- *
- * Set the path to the random file that will be used when /dev/random and /dev/urandom are
- * not available.
- */
-static VALUE
-ropenldap_conn_tls_random_file_eq( VALUE self, VALUE path )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	VALUE pathstring = rb_obj_as_string( path );
-	const char *pathopt = StringValuePtr( pathstring );
-
-	if ( ldap_set_option(ptr->ldap, LDAP_OPT_X_TLS_RANDOM_FILE, pathopt) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't set option: LDAP_OPT_X_TLS_RANDOM_FILE" );
-
-	return path;
-}
-
-
-/*
- * call-seq:
- *    conn.tls_dhfile    -> string
- *
- * Path to PEM encoded Diffie-Hellman parameter file.
- */
-static VALUE
-ropenldap_conn_tls_dhfile( VALUE self )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	char *path;
-	VALUE pathstring = Qnil;
-
-	if ( ldap_get_option(ptr->ldap, LDAP_OPT_X_TLS_DHFILE, &path) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't get option: LDAP_OPT_X_TLS_DHFILE" );
-	if ( !path )
-		return Qnil;
-
-	pathstring = rb_str_new2( path );
-	ldap_memfree( path );
-
-	return pathstring;
-}
-
-/*
- * call-seq:
- *    conn.tls_dhfile = newvalue
- *
- * Set the path to a PEM-encoded Diffie-Hellman parameter file. If this is specified, DH key 
- * exchange will be used for the ephemeral keying. 
- * 
- * You can use the 'openssl' command-line tool to generate the file like so:
- * 
- *   openssl dhparam -outform PEM -out dh1024.pem -5 1024
- */
-static VALUE
-ropenldap_conn_tls_dhfile_eq( VALUE self, VALUE path )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	VALUE pathstring = rb_obj_as_string( path );
-	const char *pathopt = StringValuePtr( pathstring );
-
-	if ( ldap_set_option(ptr->ldap, LDAP_OPT_X_TLS_DHFILE, pathopt) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't set option: LDAP_OPT_X_TLS_DHFILE" );
-
-	return path;
-}
-
-
-/*
- * call-seq:
- *    conn.tls_crlfile    -> string
- *
- * Get the current path to the file containing a Certificate Revocation List used for verifying that 
- * certificates have not been revoked.
- */
-static VALUE
-ropenldap_conn_tls_crlfile( VALUE self )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	char *path;
-	VALUE pathstring = Qnil;
-
-	if ( ldap_get_option(ptr->ldap, LDAP_OPT_X_TLS_CRLFILE, &path) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't get option: LDAP_OPT_X_TLS_CRLFILE" );
-	if ( !path )
-		return Qnil;
-
-	pathstring = rb_str_new2( path );
-	ldap_memfree( path );
-
-	return pathstring;
-}
-
-/*
- * call-seq:
- *    conn.tls_crlfile = path
- *
- * Set the path to the file containing a Certificate Revocation List used for verifying that 
- * certificates have not been revoked. This value is only used when LDAP has been compiled
- * to use GnuTLS.
- */
-static VALUE
-ropenldap_conn_tls_crlfile_eq( VALUE self, VALUE path )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	VALUE pathstring = rb_obj_as_string( path );
-	const char *pathopt = StringValuePtr( pathstring );
-
-	if ( ldap_set_option(ptr->ldap, LDAP_OPT_X_TLS_CRLFILE, pathopt) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't set option: LDAP_OPT_X_TLS_CRLFILE" );
-
-	return path;
-}
-
-
-/*
- * call-seq:
- *    conn._tls_require_cert    -> fixnum
- *
- * Backend method for #tls_require_cert
- */
-static VALUE
-ropenldap_conn__tls_require_cert( VALUE self )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	int opt;
-
-	if ( ldap_get_option(ptr->ldap, LDAP_OPT_X_TLS_REQUIRE_CERT, &opt) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't get option: LDAP_OPT_X_TLS_REQUIRE_CERT" );
-
-	return INT2FIX( opt );
-}
-
-/*
- * call-seq:
- *    conn._tls_require_cert = fixnum
- *
- * Backend method for #tls_require_cert=.
- */
-static VALUE
-ropenldap_conn__tls_require_cert_eq( VALUE self, VALUE opt )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	const int optval = NUM2INT( opt );
-
-	if ( ldap_set_option(ptr->ldap, LDAP_OPT_X_TLS_REQUIRE_CERT, &optval) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't set option: LDAP_OPT_X_TLS_REQUIRE_CERT" );
-
-	return opt;
-}
-
-
-/*
- * call-seq:
- *    conn._tls_crlcheck    -> fixnum
- *
- * Backend method for #tls_crlcheck.
- */
-static VALUE
-ropenldap_conn__tls_crlcheck( VALUE self )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	int opt;
-
-	if ( ldap_get_option(ptr->ldap, LDAP_OPT_X_TLS_CRLCHECK, &opt) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't get option: LDAP_OPT_X_TLS_CRLCHECK" );
-
-	return INT2FIX( opt );
-}
-
-/*
- * call-seq:
- *    conn._tls_crlcheck = fixnum
- *
- * Backend method for #tls_crlcheck=.
- */
-static VALUE
-ropenldap_conn__tls_crlcheck_eq( VALUE self, VALUE opt )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	const int optval = NUM2INT( opt );
-
-	if ( ldap_set_option(ptr->ldap, LDAP_OPT_X_TLS_CRLCHECK, &optval) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't set option: LDAP_OPT_X_TLS_CRLCHECK" );
-
-	return opt;
-}
-
-
-/*
- * call-seq:
- *    conn.tls_protocol_min    -> fixnum
- *
- * Gets the current minimum protocol version.
- */
-static VALUE
-ropenldap_conn_tls_protocol_min( VALUE self )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	int version;
-
-	if ( ldap_get_option(ptr->ldap, LDAP_OPT_X_TLS_PROTOCOL_MIN, &version) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't get option: LDAP_OPT_X_TLS_PROTOCOL_MIN" );
-
-	return INT2FIX( version );
-}
-
-
-/*
- * call-seq:
- *    conn.tls_protocol_min = fixnum
- *
- * Set the minimum protocol version.
- */
-static VALUE
-ropenldap_conn_tls_protocol_min_eq( VALUE self, VALUE opt )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	const int optval = NUM2INT( opt );
-
-	if ( ldap_set_option(ptr->ldap, LDAP_OPT_X_TLS_PROTOCOL_MIN, &optval) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't set option: LDAP_OPT_X_TLS_PROTOCOL_MIN" );
-
-	return opt;
-}
-
-
-/*
- * call-seq:
- *    conn.tls_package    -> string
- *
- * :FIXME: I can't find any docs on what this does.
- */
-static VALUE
-ropenldap_conn_tls_package( VALUE self )
-{
-#ifdef LDAP_OPT_X_TLS_PACKAGE
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	char *package;
-	VALUE pkgstring = Qnil;
-
-	if ( ldap_get_option(ptr->ldap, LDAP_OPT_X_TLS_PACKAGE, &package) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't get option: LDAP_OPT_X_TLS_PACKAGE" );
-	if ( !package )
-		return Qnil;
-
-	pkgstring = rb_str_new2( package );
-	ldap_memfree( package );
-
-	return pkgstring;
-#else
-	rb_raise( rb_eNotImpError, "not implemented in your version of libldap." );
-#endif /* LDAP_OPT_X_TLS_PACKAGE */
-}
-
-
-/*
- * call-seq:
- *    conn.create_new_tls_context    -> true or false
- *
- * Instructs the library to create a new TLS library context.
- */
-static VALUE
-ropenldap_conn_create_new_tls_context( VALUE self )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	const int flag = 1;
-
-	if ( ldap_set_option(ptr->ldap, LDAP_OPT_X_TLS_NEWCTX, &flag) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't set option: LDAP_OPT_X_TLS_NEWCTX" );
-
-	return Qtrue;
-}
-
-
-/*
- * Turn a STRING_T into a URI object via URI::parse.
- */
-static VALUE
-ropenldap_parse_uri( VALUE string )
-{
-	StringValue( string );
-	return rb_funcall( ropenldap_rbmURI, rb_intern("parse"), 1, string );
-}
-
-
-/*
- * call-seq:
- *     connection.uris   -> array
- *
- * Gets an Array of URIs to be contacted by the library when trying to establish
- * a connection.
- *
- */
-static VALUE
-ropenldap_conn_uris( VALUE self )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	char *uris;
-	VALUE uristring, uriarray;
-
-	if ( ldap_get_option(ptr->ldap, LDAP_OPT_URI, &uris) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't get option: LDAP_OPT_URI" );
-
-	/* Convert to strings first, then collect them into URI objects */
-	uristring = rb_str_new2( uris );
-	ldap_memfree( uris );
-
-	uriarray = rb_funcall( uristring, rb_intern("split"), 0 );
-	rb_block_call( uriarray, rb_intern("collect!"), 0, NULL,
-	               ropenldap_parse_uri, Qnil );
-
-	return uriarray;
-}
-
-
-/*
- * call-seq:
- *    connection.fdno   -> fixnum
- *
- * Return the file descriptor of the underlying socket. If the socket isn't connected yet,
- * this method returns +nil+.
- *
- *    ldapsock = IO.for_fd( conn.fdno, "w+" )
- */
-static VALUE
-ropenldap_conn_fdno( VALUE self )
-{
-	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
-	int fdno = 0;
-
-	if ( ldap_get_option(ptr->ldap, LDAP_OPT_DESC, &fdno) != LDAP_OPT_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "couldn't get option: LDAP_OPT_DESC" );
-
-	/* If the socket isn't set up yet, return nil */
-	if ( fdno < 0 ) return Qnil;
-
-	return INT2FIX( fdno );
-}
-
-
-
-
-/*
- * document-class: OpenLDAP::Connection
- */
-void
-ropenldap_init_connection( void )
-{
-	ropenldap_log( "debug", "Initializing OpenLDAP::Connection" );
-
-#ifdef FOR_RDOC
-	ropenldap_mOpenLDAP = rb_define_module( "OpenLDAP" );
-#endif
-
-	/* OpenLDAP::Connection */
-	ropenldap_cOpenLDAPConnection =
-		rb_define_class_under( ropenldap_mOpenLDAP, "Connection", rb_cObject );
-	rb_include_module( ropenldap_cOpenLDAPConnection, ropenldap_mOpenLDAPLoggable );
-
-	rb_define_alloc_func( ropenldap_cOpenLDAPConnection, ropenldap_conn_s_allocate );
-
-	rb_define_protected_method( ropenldap_cOpenLDAPConnection, "_initialize",
-	                            ropenldap_conn_initialize, -2 );
-
-	rb_define_method( ropenldap_cOpenLDAPConnection, "uris", ropenldap_conn_uris, 0 );
-	rb_define_method( ropenldap_cOpenLDAPConnection, "fdno", ropenldap_conn_fdno, 0 );
-	rb_define_alias(  ropenldap_cOpenLDAPConnection, "fileno", "fdno" );
-	rb_define_method( ropenldap_cOpenLDAPConnection, "simple_bind", ropenldap_conn_simple_bind, 2 );
-
-	rb_define_method( ropenldap_cOpenLDAPConnection, "protocol_version",
-	                  ropenldap_conn_protocol_version, 0 );
-	rb_define_method( ropenldap_cOpenLDAPConnection, "protocol_version=",
-	                  ropenldap_conn_protocol_version_eq, 1 );
-	rb_define_method( ropenldap_cOpenLDAPConnection, "async_connect?",
-	                  ropenldap_conn_async_connect_p, 0 );
-	rb_define_method( ropenldap_cOpenLDAPConnection, "async_connect=",
-	                  ropenldap_conn_async_connect_eq, 1 );
-	rb_define_method( ropenldap_cOpenLDAPConnection, "network_timeout",
-	                  ropenldap_conn_network_timeout, 0 );
-	rb_define_method( ropenldap_cOpenLDAPConnection, "network_timeout=",
-	                  ropenldap_conn_network_timeout_eq, 1 );
-
-	rb_define_method( ropenldap_cOpenLDAPConnection, "tls_inplace?",
-	                  ropenldap_conn_tls_inplace_p, 0 );
-
-	/* Options */
-	rb_define_method( ropenldap_cOpenLDAPConnection, "tls_cacertfile",
-	                  ropenldap_conn_tls_cacertfile, 0 );
-	rb_define_method( ropenldap_cOpenLDAPConnection, "tls_cacertfile=",
-	                  ropenldap_conn_tls_cacertfile_eq, 1 );
-	rb_define_method( ropenldap_cOpenLDAPConnection, "tls_cacertdir",
-	                  ropenldap_conn_tls_cacertdir, 0 );
-	rb_define_method( ropenldap_cOpenLDAPConnection, "tls_cacertdir=",
-	                  ropenldap_conn_tls_cacertdir_eq, 1 );
-	rb_define_method( ropenldap_cOpenLDAPConnection, "tls_certfile",
-	                  ropenldap_conn_tls_certfile, 0 );
-	rb_define_method( ropenldap_cOpenLDAPConnection, "tls_certfile=",
-	                  ropenldap_conn_tls_certfile_eq, 1 );
-	rb_define_method( ropenldap_cOpenLDAPConnection, "tls_keyfile",
-	                  ropenldap_conn_tls_keyfile, 0 );
-	rb_define_method( ropenldap_cOpenLDAPConnection, "tls_keyfile=",
-	                  ropenldap_conn_tls_keyfile_eq, 1 );
-	rb_define_method( ropenldap_cOpenLDAPConnection, "tls_cipher_suite",
-	                  ropenldap_conn_tls_cipher_suite, 0 );
-	rb_define_method( ropenldap_cOpenLDAPConnection, "tls_cipher_suite=",
-	                  ropenldap_conn_tls_cipher_suite_eq, 1 );
-	rb_define_method( ropenldap_cOpenLDAPConnection, "tls_random_file",
-	                  ropenldap_conn_tls_random_file, 0 );
-	rb_define_method( ropenldap_cOpenLDAPConnection, "tls_random_file=",
-	                  ropenldap_conn_tls_random_file_eq, 1 );
-	rb_define_method( ropenldap_cOpenLDAPConnection, "tls_dhfile",
-	                  ropenldap_conn_tls_dhfile, 0 );
-	rb_define_method( ropenldap_cOpenLDAPConnection, "tls_dhfile=",
-	                  ropenldap_conn_tls_dhfile_eq, 1 );
-	rb_define_method( ropenldap_cOpenLDAPConnection, "tls_crlfile",
-	                  ropenldap_conn_tls_crlfile, 0 );
-	rb_define_method( ropenldap_cOpenLDAPConnection, "tls_crlfile=",
-	                  ropenldap_conn_tls_crlfile_eq, 1 );
-
-	/* Integer options */
-	rb_define_method( ropenldap_cOpenLDAPConnection, "tls_protocol_min",
-	                  ropenldap_conn_tls_protocol_min, 0 );
-	rb_define_method( ropenldap_cOpenLDAPConnection, "tls_protocol_min=",
-	                  ropenldap_conn_tls_protocol_min_eq, 1 );
-
-	/* Read-only options */
-	rb_define_method( ropenldap_cOpenLDAPConnection, "tls_package",
-	                  ropenldap_conn_tls_package, 0 );
-
-	rb_define_method( ropenldap_cOpenLDAPConnection, "create_new_tls_context",
-	                  ropenldap_conn_create_new_tls_context, 0 );
-
-	/* Methods with Ruby front-ends */
-	rb_define_protected_method( ropenldap_cOpenLDAPConnection, "_start_tls",
-	                            ropenldap_conn__start_tls, 0 );
-	rb_define_protected_method( ropenldap_cOpenLDAPConnection, "_tls_require_cert",
-	                            ropenldap_conn__tls_require_cert, 0 );
-	rb_define_protected_method( ropenldap_cOpenLDAPConnection, "_tls_require_cert=",
-	                            ropenldap_conn__tls_require_cert_eq, 1 );
-	rb_define_protected_method( ropenldap_cOpenLDAPConnection, "_tls_crlcheck",
-	                            ropenldap_conn__tls_crlcheck, 0 );
-	rb_define_protected_method( ropenldap_cOpenLDAPConnection, "_tls_crlcheck=",
-	                            ropenldap_conn__tls_crlcheck_eq, 1 );
-
-	rb_require( "openldap/connection" );
-}
-

File ext/extconf.rb

-#!/usr/bin/env ruby
-
-require 'mkmf'
-require 'fileutils'
-
-if ENV['MAINTAINER_MODE']
-	$stderr.puts "** Maintainer mode enabled. **"
-	$CFLAGS << ' -Wall' << ' -Wno-unused' << " -O0" << ' -ggdb' << ' -DDEBUG'
-end
-
-
-dir_config( 'openldap' )
-
-find_header( 'ldap.h' ) or
-	abort( "missing ldap.h; do you need to install a developer package?" )
-find_library( 'ldap', 'ldap_initialize' ) or
-	abort( "Could not find LDAP library (http://openldap.org/)." )
-have_const( 'LDAP_API_VERSION', 'ldap.h' ) or
-	abort "no LDAP_API_VERSION constant defined"
-
-have_func( 'ldap_tls_inplace' )
-
-create_header()
-create_makefile( 'openldap_ext' )

File ext/openldap.c

-
-/*
- * Ruby-OpenLDAP -- a Ruby binding to OpenLDAP's libldap
- * $Id$
- *
- * Authors
- *
- * - Michael Granger <ged@FaerieMUD.org>
- *
- * Copyright (c) 2011 Michael Granger
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are
- * permitted provided that the following conditions are met:
- *
- *  * Redistributions of source code must retain the above copyright notice, this
- *    list of conditions and the following disclaimer.
- *
- *  * Redistributions in binary form must reproduce the above copyright notice, this
- *    list of conditions and the following disclaimer in the documentation and/or
- *    other materials provided with the distribution.
- *
- *  * Neither the name of the authors, nor the names of its contributors may be used to
- *    endorse or promote products derived from this software without specific prior
- *    written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *
- */
-
-#include "openldap.h"
-
-VALUE ropenldap_mOpenLDAP;
-VALUE ropenldap_mOpenLDAPLoggable;
-
-VALUE ropenldap_eOpenLDAPError;
-
-VALUE ropenldap_rbmURI;
-
-
-/* --------------------------------------------------------------
- * Logging Functions
- * -------------------------------------------------------------- */
-
-/*
- * Log a message to the given +context+ object's logger.
- */
-void
-#ifdef HAVE_STDARG_PROTOTYPES
-ropenldap_log_obj( VALUE context, const char *level, const char *fmt, ... )
-#else
-ropenldap_log_obj( VALUE context, const char *level, const char *fmt, va_dcl )
-#endif
-{
-	char buf[BUFSIZ];
-	va_list	args;
-	VALUE logger = Qnil;
-	VALUE message = Qnil;
-
-	va_start( args, fmt );
-	vsnprintf( buf, BUFSIZ, fmt, args );
-	message = rb_str_new2( buf );
-
-	logger = rb_funcall( context, rb_intern("log"), 0, 0 );
-	rb_funcall( logger, rb_intern(level), 1, message );
-
-	va_end( args );
-}
-
-
-/*
- * Log a message to the global logger.
- */
-void
-#ifdef HAVE_STDARG_PROTOTYPES
-ropenldap_log( const char *level, const char *fmt, ... )
-#else
-ropenldap_log( const char *level, const char *fmt, va_dcl )
-#endif
-{
-	char buf[BUFSIZ];
-	va_list	args;
-	VALUE logger = Qnil;
-	VALUE message = Qnil;
-
-	va_init_list( args, fmt );
-	vsnprintf( buf, BUFSIZ, fmt, args );
-	message = rb_str_new2( buf );
-
-	logger = rb_funcall( ropenldap_mOpenLDAP, rb_intern("logger"), 0, 0 );
-	rb_funcall( logger, rb_intern(level), 1, message );
-
-	va_end( args );
-}
-
-
-/*
- * Raise an appropriate exception with an appropriate message for the given
- * resultcode.
- */
-void
-#ifdef HAVE_STDARG_PROTOTYPES
-ropenldap_check_result( int resultcode, const char *func, ... )
-#else
-ropenldap_check_result( int resultcode, const char *func, va_dcl )
-#endif
-{
-	char buf[BUFSIZ];
-	va_list args;
-	VALUE exception_class = Qnil;
-
-	if ( resultcode == LDAP_SUCCESS ) return;
-
-	va_init_list( args, func );
-	vsnprintf( buf, BUFSIZ, func, args );
-
-	exception_class =
-		rb_funcall( ropenldap_eOpenLDAPError, rb_intern("subclass_for"), 1, INT2FIX(resultcode) );
-
-	rb_raise( exception_class, "%s", buf );
-}
-
-
-/*
- * Convert an array of string pointers to a Ruby Array of Strings.
- */
-VALUE
-ropenldap_rb_string_array( char **strings )
-{
-	VALUE ary = rb_ary_new();
-	char **iter;
-
-	/* If there aren't any pointers, just return the empty Array */
-	if ( !strings ) return ary;
-
-	for ( iter = strings ; *iter != NULL ; iter++ ) {
-		ropenldap_log( "debug", "  adding %s to string array", *iter );
-		rb_ary_push( ary, rb_str_new2(*iter) );
-	}
-
-	return ary;
-}
-
-
-
-/*
- * call-seq:
- *    OpenLDAP.split_url( str )   -> array
- *
- * Split an LDAP URL into an array of its parts:
- * - uri_scheme
- * - host
- * - port
- * - base
- * - attrs
- * - scope
- * - filter
- * - exts
- * - crit_exts
- */
-static VALUE
-ropenldap_s_split_url( VALUE UNUSED(module), VALUE urlstring )
-{
-	const char *url = StringValueCStr( urlstring );
-	LDAPURLDesc *urldesc;
-	VALUE rval = Qnil, obj = Qnil;
-
-	if ( !ldap_is_ldap_url(url) )
-		rb_raise( rb_eArgError, "Not an LDAP URL." );
-
-	/* Parse the URL */
-	if ( ldap_url_parse(url, &urldesc) != 0 )
-		rb_raise( rb_eRuntimeError, "Error parsing %s as an LDAP URL!", url );
-
-	rval = rb_ary_new2( 9 );
-
-	/* Scheme */
-	if ( urldesc->lud_scheme ) {
-		ropenldap_log( "debug", "  parsed scheme: %s", urldesc->lud_scheme );
-		obj = rb_str_new2( urldesc->lud_scheme );
-		OBJ_INFECT( obj, urlstring );
-		rb_ary_store( rval, 0L, obj );
-	}
-
-	/* LDAP host to contact */
-	if ( urldesc->lud_host ) {
-		ropenldap_log( "debug", "  parsed host: %s", urldesc->lud_host );
-		obj = rb_str_new2( urldesc->lud_host );
-		OBJ_INFECT( obj, urlstring );
-		rb_ary_store( rval, 1L, obj );
-	}
-
-	/* Port */
-	rb_ary_store( rval, 2L, INT2FIX(urldesc->lud_port) );
-
-	/* Base DN */
-	if ( urldesc->lud_dn ) {
-		ropenldap_log( "debug", "  parsed DN: %s", urldesc->lud_dn );
-		obj = rb_str_new2( urldesc->lud_dn );
-		OBJ_INFECT( obj, urlstring );
-		rb_ary_store( rval, 3L, obj );
-	}
-
-	/* Attributes */
-	rb_ary_store( rval, 4L, ropenldap_rb_string_array(urldesc->lud_attrs) );
-
-	/* Numeric scope (LDAP_SCOPE_*) */
-	rb_ary_store( rval, 5L, INT2FIX(urldesc->lud_scope) );
-
-	/* Filter */
-	if ( urldesc->lud_filter ) {
-		ropenldap_log( "debug", "  parsed filter: %s", urldesc->lud_filter );
-		obj = rb_str_new2( urldesc->lud_filter );
-		OBJ_INFECT( obj, urlstring );
-		rb_ary_store( rval, 6L, obj );
-	}
-
-	/* lists of LDAP extensions */
-	rb_ary_store( rval, 7L, ropenldap_rb_string_array(urldesc->lud_exts) );
-
-	/* Critical extension/s flag */
-	rb_ary_store( rval, 8L, urldesc->lud_crit_exts ? Qtrue : Qfalse );
-
-	ldap_free_urldesc( urldesc );
-
-	return rval;
-}
-
-
-/*
- * call-seq:
- *    OpenLDAP.err2string( resultcode )   -> string
- *
- * Return a short description of the +resultcode+ returned by routines in this library.
- *
- */
-static VALUE
-ropenldap_s_err2string( VALUE UNUSED(module), VALUE resultcode )
-{
-	int err = FIX2INT( resultcode );
-	char *string = ldap_err2string( err );
-
-	return rb_str_new2( string );
-}
-
-
-/* Check to be sure the library that's dynamically-linked is the same
- * one it was compiled against. */
-static void
-ropenldap_check_link()
-{
-	LDAPAPIInfo api;
-	api.ldapai_info_version = LDAP_API_INFO_VERSION;
-
-	if ( ldap_get_option(NULL, LDAP_OPT_API_INFO, &api) != LDAP_OPT_SUCCESS ) {
-		rb_warn( "ldap_get_option(API_INFO) failed" );
-		return;
-	}
-
-	if ( api.ldapai_info_version != LDAP_API_INFO_VERSION ) {
-		rb_warn( "LDAP APIInfo version mismatch: library %d, header %d",
-		         api.ldapai_info_version, LDAP_API_INFO_VERSION );
-	}
-
-	if ( api.ldapai_api_version != LDAP_API_VERSION ) {
-		rb_warn( "LDAP API version mismatch: library %d, header %d",
-		         api.ldapai_api_version, LDAP_API_VERSION );
-	}
-
-	if ( strcmp(api.ldapai_vendor_name, LDAP_VENDOR_NAME ) != 0 ) {
-		rb_warn( "LDAP vendor name mismatch: library %s, header %s\n",
-		         api.ldapai_vendor_name, LDAP_VENDOR_NAME );
-	}
-
-	if( api.ldapai_vendor_version != LDAP_VENDOR_VERSION ) {
-		rb_warn( "LDAP vendor version mismatch: library %d, header %d\n",
-		         api.ldapai_vendor_version, LDAP_VENDOR_VERSION );
-	}
-
-	ropenldap_log( "info", "LDAP library: %s %d",
-		           LDAP_VENDOR_NAME, LDAP_VENDOR_VERSION );
-
-	ldap_memfree( api.ldapai_vendor_name );
-	ber_memvfree( (void **)api.ldapai_extensions );
-}
-
-
-/*
- * call-seq:
- *    OpenLDAP.api_info   -> hash
- *
- * Return a Hash describing the API version, vendor, extensions, etc.
- *
- *    conn.api_info
- *    # => {:api_version=>3001, :protocol_version=>3, 
- *          :extensions=>["X_OPENLDAP", "THREAD_SAFE", "X_OPENLDAP_THREAD_SAFE"], 
- *          :vendor_name=>"OpenLDAP", :vendor_version=>20423}
- */
-static VALUE
-ropenldap_s_api_info( VALUE self )
-{
-	VALUE rval = rb_hash_new();
-	LDAPAPIInfo info;
-	info.ldapai_info_version = LDAP_API_INFO_VERSION;
-
-	if ( ldap_get_option(NULL, LDAP_OPT_API_INFO, &info) != LDAP_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "ldap_get_option(API_INFO) failed." );
-
-	rb_hash_aset( rval, ID2SYM(rb_intern("api_version")), INT2FIX(info.ldapai_api_version) );
-	rb_hash_aset( rval, ID2SYM(rb_intern("protocol_version")), INT2FIX(info.ldapai_protocol_version) );
-	rb_hash_aset( rval, ID2SYM(rb_intern("extensions")), ropenldap_rb_string_array(info.ldapai_extensions) );
-	rb_hash_aset( rval, ID2SYM(rb_intern("vendor_name")), rb_str_new2(info.ldapai_vendor_name) );
-	rb_hash_aset( rval, ID2SYM(rb_intern("vendor_version")), INT2FIX(info.ldapai_vendor_version) );
-
-	ldap_memfree( info.ldapai_vendor_name );
-	ber_memvfree( (void **)info.ldapai_extensions );
-
-	return rval;
-}
-
-
-/*
- * call-seq:
- *    OpenLDAP.api_feature_info   -> hash
- *
- * Returns a hash of the versions of the extensions in .api_info[:extensions]
- *
- *    conn.api_feature_info
- *    # => {"X_OPENLDAP"=>20423, "THREAD_SAFE"=>1, "X_OPENLDAP_THREAD_SAFE"=>1}
- */
-static VALUE
-ropenldap_s_api_feature_info( VALUE self )
-{
-	VALUE rval = rb_hash_new();
-	int i;
-	LDAPAPIInfo info;
-	info.ldapai_info_version = LDAP_API_INFO_VERSION;
-
-	if ( ldap_get_option(NULL, LDAP_OPT_API_INFO, &info) != LDAP_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "ldap_get_option(API_INFO) failed." );
-
-	for( i=0; info.ldapai_extensions[i] != NULL; i++ ) {
-		LDAPAPIFeatureInfo fi;
-		fi.ldapaif_info_version = LDAP_FEATURE_INFO_VERSION;
-		fi.ldapaif_name = info.ldapai_extensions[i];
-		fi.ldapaif_version = 0;
-
-		if ( ldap_get_option(NULL, LDAP_OPT_API_FEATURE_INFO, &fi) == LDAP_SUCCESS ) {
-			if(fi.ldapaif_info_version == LDAP_FEATURE_INFO_VERSION) {
-				rb_hash_aset( rval, rb_str_new2(fi.ldapaif_name), INT2FIX(fi.ldapaif_version) );
-			} else {
-				ropenldap_log( "warn", "Feature info version mismatch for %s; expected %d, got %d",
-				               fi.ldapaif_name, LDAP_FEATURE_INFO_VERSION, fi.ldapaif_info_version );
-				rb_hash_aset( rval, rb_str_new2(fi.ldapaif_name), Qnil );
-			}
-		} else {
-			ldap_memfree( info.ldapai_vendor_name );
-			ber_memvfree( (void **)info.ldapai_extensions );
-			rb_raise( ropenldap_eOpenLDAPError, "ldap_get_option(API_FEATURE_INFO) failed." );
-		}
-	}
-
-	ldap_memfree( info.ldapai_vendor_name );
-	ber_memvfree( (void **)info.ldapai_extensions );
-
-	return rval;
-}
-
-
-/*
- * call-seq:
- *    OpenLDAP.uris   -> array
- *
- * Return an Array of URIs to be contacted by the library when trying to establish a connection.
- *
- *    OpenLDAP.uris
- *    # => ['ldap://ldap.example.com:389']
- */
-static VALUE
-ropenldap_s_uris( VALUE self )
-{
-	VALUE rval;
-	char *uris;
-
-	if ( ldap_get_option(NULL, LDAP_OPT_URI, &uris) != LDAP_SUCCESS )
-		rb_raise( ropenldap_eOpenLDAPError, "ldap_get_option(URI) failed." );
-
-	rval = rb_str_new2( uris );
-	ldap_memfree( uris );
-
-	return rb_funcall( rval, rb_intern("split"), 1, rb_str_new(" ", 1) );
-}
-
-
-
-void
-Init_openldap_ext( void )
-{
-	rb_require( "uri" );
-	ropenldap_rbmURI = rb_const_get( rb_cObject, rb_intern("URI") );
-
-	rb_require( "openldap" );
-	ropenldap_mOpenLDAP = rb_define_module( "OpenLDAP" );
-
-	rb_require( "openldap/mixins" );
-	ropenldap_mOpenLDAPLoggable = rb_define_module_under( ropenldap_mOpenLDAP, "Loggable" );
-	ropenldap_eOpenLDAPError =
-		rb_define_class_under( ropenldap_mOpenLDAP, "Error", rb_eRuntimeError );
-
-	/* Constants */
-
-	/* versions */
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_API_VERSION", INT2FIX(LDAP_API_VERSION) );
-
-	/* Ports */
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_PORT", INT2FIX(LDAP_PORT) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAPS_PORT", INT2FIX(LDAPS_PORT) );
-
-	/* RFC constants */
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_ROOT_DSE", rb_str_new2(LDAP_ROOT_DSE) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_NO_ATTRS", rb_str_new2(LDAP_NO_ATTRS) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_ALL_USER_ATTRIBUTES",
-	                 rb_str_new2(LDAP_ALL_USER_ATTRIBUTES) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_ALL_OPERATIONAL_ATTRIBUTES",
-				     rb_str_new2(LDAP_ALL_OPERATIONAL_ATTRIBUTES) );
-
-	/* RFC4511 maxInt */
- 	rb_define_const( ropenldap_mOpenLDAP, "LDAP_MAXINT", INT2NUM(LDAP_MAXINT) );
-
-	/* search scopes */
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_SCOPE_BASE", INT2FIX(LDAP_SCOPE_BASE) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_SCOPE_BASEOBJECT", INT2FIX(LDAP_SCOPE_BASEOBJECT) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_SCOPE_ONELEVEL", INT2FIX(LDAP_SCOPE_ONELEVEL) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_SCOPE_ONE", INT2FIX(LDAP_SCOPE_ONE) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_SCOPE_SUBTREE", INT2FIX(LDAP_SCOPE_SUBTREE) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_SCOPE_SUB", INT2FIX(LDAP_SCOPE_SUB) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_SCOPE_SUBORDINATE", INT2FIX(LDAP_SCOPE_SUBORDINATE) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_SCOPE_CHILDREN", INT2FIX(LDAP_SCOPE_CHILDREN) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_SCOPE_DEFAULT", INT2FIX(LDAP_SCOPE_DEFAULT) );
-
-	/* result codes */
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_SUCCESS", INT2FIX(LDAP_SUCCESS) );
-
- 	rb_define_const( ropenldap_mOpenLDAP, "LDAP_OPERATIONS_ERROR", INT2FIX(LDAP_OPERATIONS_ERROR) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_PROTOCOL_ERROR", INT2FIX(LDAP_PROTOCOL_ERROR) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_TIMELIMIT_EXCEEDED", INT2FIX(LDAP_TIMELIMIT_EXCEEDED) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_SIZELIMIT_EXCEEDED", INT2FIX(LDAP_SIZELIMIT_EXCEEDED) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_COMPARE_FALSE", INT2FIX(LDAP_COMPARE_FALSE) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_COMPARE_TRUE", INT2FIX(LDAP_COMPARE_TRUE) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_AUTH_METHOD_NOT_SUPPORTED", INT2FIX(LDAP_AUTH_METHOD_NOT_SUPPORTED) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_STRONG_AUTH_NOT_SUPPORTED", INT2FIX(LDAP_STRONG_AUTH_NOT_SUPPORTED) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_STRONG_AUTH_REQUIRED", INT2FIX(LDAP_STRONG_AUTH_REQUIRED) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_STRONGER_AUTH_REQUIRED", INT2FIX(LDAP_STRONGER_AUTH_REQUIRED) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_PARTIAL_RESULTS", INT2FIX(LDAP_PARTIAL_RESULTS) );
-
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_REFERRAL", INT2FIX(LDAP_REFERRAL) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_ADMINLIMIT_EXCEEDED", INT2FIX(LDAP_ADMINLIMIT_EXCEEDED) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_UNAVAILABLE_CRITICAL_EXTENSION", INT2FIX(LDAP_UNAVAILABLE_CRITICAL_EXTENSION) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_CONFIDENTIALITY_REQUIRED", INT2FIX(LDAP_CONFIDENTIALITY_REQUIRED) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_SASL_BIND_IN_PROGRESS", INT2FIX(LDAP_SASL_BIND_IN_PROGRESS) );
-
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_NO_SUCH_ATTRIBUTE", INT2FIX(LDAP_NO_SUCH_ATTRIBUTE) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_UNDEFINED_TYPE", INT2FIX(LDAP_UNDEFINED_TYPE) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_INAPPROPRIATE_MATCHING", INT2FIX(LDAP_INAPPROPRIATE_MATCHING) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_CONSTRAINT_VIOLATION", INT2FIX(LDAP_CONSTRAINT_VIOLATION) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_TYPE_OR_VALUE_EXISTS", INT2FIX(LDAP_TYPE_OR_VALUE_EXISTS) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_INVALID_SYNTAX", INT2FIX(LDAP_INVALID_SYNTAX) );
-
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_NO_SUCH_OBJECT", INT2FIX(LDAP_NO_SUCH_OBJECT) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_ALIAS_PROBLEM", INT2FIX(LDAP_ALIAS_PROBLEM) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_INVALID_DN_SYNTAX", INT2FIX(LDAP_INVALID_DN_SYNTAX) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_IS_LEAF", INT2FIX(LDAP_IS_LEAF) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_ALIAS_DEREF_PROBLEM", INT2FIX(LDAP_ALIAS_DEREF_PROBLEM) );
-
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_X_PROXY_AUTHZ_FAILURE", INT2FIX(LDAP_X_PROXY_AUTHZ_FAILURE) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_INAPPROPRIATE_AUTH", INT2FIX(LDAP_INAPPROPRIATE_AUTH) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_INVALID_CREDENTIALS", INT2FIX(LDAP_INVALID_CREDENTIALS) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_INSUFFICIENT_ACCESS", INT2FIX(LDAP_INSUFFICIENT_ACCESS) );
-
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_BUSY", INT2FIX(LDAP_BUSY) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_UNAVAILABLE", INT2FIX(LDAP_UNAVAILABLE) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_UNWILLING_TO_PERFORM", INT2FIX(LDAP_UNWILLING_TO_PERFORM) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_LOOP_DETECT", INT2FIX(LDAP_LOOP_DETECT) );
-
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_NAMING_VIOLATION", INT2FIX(LDAP_NAMING_VIOLATION) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_OBJECT_CLASS_VIOLATION", INT2FIX(LDAP_OBJECT_CLASS_VIOLATION) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_NOT_ALLOWED_ON_NONLEAF", INT2FIX(LDAP_NOT_ALLOWED_ON_NONLEAF) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_NOT_ALLOWED_ON_RDN", INT2FIX(LDAP_NOT_ALLOWED_ON_RDN) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_ALREADY_EXISTS", INT2FIX(LDAP_ALREADY_EXISTS) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_NO_OBJECT_CLASS_MODS", INT2FIX(LDAP_NO_OBJECT_CLASS_MODS) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_RESULTS_TOO_LARGE", INT2FIX(LDAP_RESULTS_TOO_LARGE) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_AFFECTS_MULTIPLE_DSAS", INT2FIX(LDAP_AFFECTS_MULTIPLE_DSAS) );
-
-#ifdef LDAP_VLV_ERROR
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_VLV_ERROR", INT2FIX(LDAP_VLV_ERROR) );
-#endif
-
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_OPT_SUCCESS", INT2FIX(LDAP_OPT_SUCCESS) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_OPT_ERROR", INT2FIX(LDAP_OPT_ERROR) );
-
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_OTHER", INT2FIX(LDAP_OTHER) );
-
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_SERVER_DOWN", INT2FIX(LDAP_SERVER_DOWN) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_LOCAL_ERROR", INT2FIX(LDAP_LOCAL_ERROR) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_ENCODING_ERROR", INT2FIX(LDAP_ENCODING_ERROR) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_DECODING_ERROR", INT2FIX(LDAP_DECODING_ERROR) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_TIMEOUT", INT2FIX(LDAP_TIMEOUT) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_AUTH_UNKNOWN", INT2FIX(LDAP_AUTH_UNKNOWN) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_FILTER_ERROR", INT2FIX(LDAP_FILTER_ERROR) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_USER_CANCELLED", INT2FIX(LDAP_USER_CANCELLED) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_PARAM_ERROR", INT2FIX(LDAP_PARAM_ERROR) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_NO_MEMORY", INT2FIX(LDAP_NO_MEMORY) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_CONNECT_ERROR", INT2FIX(LDAP_CONNECT_ERROR) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_NOT_SUPPORTED", INT2FIX(LDAP_NOT_SUPPORTED) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_CONTROL_NOT_FOUND", INT2FIX(LDAP_CONTROL_NOT_FOUND) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_NO_RESULTS_RETURNED", INT2FIX(LDAP_NO_RESULTS_RETURNED) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_MORE_RESULTS_TO_RETURN", INT2FIX(LDAP_MORE_RESULTS_TO_RETURN) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_CLIENT_LOOP", INT2FIX(LDAP_CLIENT_LOOP) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_REFERRAL_LIMIT_EXCEEDED", INT2FIX(LDAP_REFERRAL_LIMIT_EXCEEDED) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_X_CONNECTING", INT2FIX(LDAP_X_CONNECTING) );
-
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_OPT_X_TLS_NEVER", INT2FIX(LDAP_OPT_X_TLS_NEVER) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_OPT_X_TLS_HARD", INT2FIX(LDAP_OPT_X_TLS_HARD) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_OPT_X_TLS_DEMAND", INT2FIX(LDAP_OPT_X_TLS_DEMAND) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_OPT_X_TLS_ALLOW", INT2FIX(LDAP_OPT_X_TLS_ALLOW) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_OPT_X_TLS_TRY", INT2FIX(LDAP_OPT_X_TLS_TRY) );
-
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_OPT_X_TLS_CRL_NONE", INT2FIX(LDAP_OPT_X_TLS_CRL_NONE) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_OPT_X_TLS_CRL_PEER", INT2FIX(LDAP_OPT_X_TLS_CRL_PEER) );
-	rb_define_const( ropenldap_mOpenLDAP, "LDAP_OPT_X_TLS_CRL_ALL", INT2FIX(LDAP_OPT_X_TLS_CRL_ALL) );
-
-	/* Module functions */
-	rb_define_singleton_method( ropenldap_mOpenLDAP, "split_url", ropenldap_s_split_url, 1 );
-	rb_define_singleton_method( ropenldap_mOpenLDAP, "err2string", ropenldap_s_err2string, 1 );
-	rb_define_singleton_method( ropenldap_mOpenLDAP, "api_info", ropenldap_s_api_info, 0 );
-	rb_define_singleton_method( ropenldap_mOpenLDAP, "api_feature_info", ropenldap_s_api_feature_info, 0 );
-
-	rb_define_singleton_method( ropenldap_mOpenLDAP, "uris", ropenldap_s_uris, 0 );
-
-	/* Initialize the other parts of the extension */
-	ropenldap_init_connection();
-
-	/* Detect mismatched linking */
-	ropenldap_check_link();
-}
-

File ext/openldap.h

-/* 
- * Header for openldap.c
- */
-
-#ifndef __OPENLDAP_H__
-#define __OPENLDAP_H__
-
-#include <stdio.h>
-#include <math.h>
-#include <string.h>
-#include <inttypes.h>
-#include <assert.h>
-
-#include <ldap.h>
-
-#include <ruby.h>
-
-#include "extconf.h"
-
-/* --------------------------------------------------------------
- * Globals
- * -------------------------------------------------------------- */
-
-/* Reference to the URI module */
-extern VALUE ropenldap_rbmURI;
-
-extern VALUE ropenldap_mOpenLDAP;
-extern VALUE ropenldap_mOpenLDAPLoggable;
-
-extern VALUE ropenldap_cOpenLDAPConnection;
-
-extern VALUE ropenldap_eOpenLDAPError;
-
-
-/* --------------------------------------------------------------
- * Typedefs
- * -------------------------------------------------------------- */
-
-/* OpenLDAP::Connection struct */
-struct ropenldap_connection {
-    LDAP    *ldap;
-    VALUE   connection;
-};
-
-
-/* --------------------------------------------------------------
- * Macros
- * -------------------------------------------------------------- */
-#define IsConnection( obj ) rb_obj_is_kind_of( (obj), ropenldap_cOpenLDAPConnection )
-
-#ifdef UNUSED
-#elif defined(__GNUC__)
-# define UNUSED(x) UNUSED_ ## x __attribute__((unused))
-#elif defined(__LCLINT__)
-# define UNUSED(x) /*@unused@*/ x
-#else
-# define UNUSED(x) x
-#endif
-
-
-/* --------------------------------------------------------------
- * Declarations
- * -------------------------------------------------------------- */
-
-#ifdef HAVE_STDARG_PROTOTYPES
-#include <stdarg.h>
-#define va_init_list(a,b) va_start(a,b)
-void ropenldap_log_obj( VALUE, const char *, const char *, ... );
-void ropenldap_log( const char *, const char *, ... );
-void ropenldap_check_result( int, const char *, ... );
-#else
-#include <varargs.h>
-#define va_init_list(a,b) va_start(a)
-void ropenldap_log_obj( VALUE, const char *, const char *, va_dcl );
-void ropenldap_log( const char *, const char *, va_dcl );
-void ropenldap_check_result( int, va_dcl );
-#endif
-
-VALUE ropenldap_rb_string_array         _(( char ** ));
-
-
-/* --------------------------------------------------------------
- * Initializers
- * -------------------------------------------------------------- */
-
-void Init_openldap_ext                  _(( void ));
-void ropenldap_init_connection          _(( void ));
-
-
-#endif /* __OPENLDAP_H__ */
-

File ext/openldap_ext/connection.c

+/*
+ * Ruby-OpenLDAP -- a Ruby binding to OpenLDAP's libldap
+ * $Id$
+ *
+ * Authors
+ *
+ * - Michael Granger <ged@FaerieMUD.org>
+ *
+ * Copyright (c) 2011 Michael Granger
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice, this
+ *    list of conditions and the following disclaimer in the documentation and/or
+ *    other materials provided with the distribution.
+ *
+ *  * Neither the name of the authors, nor the names of its contributors may be used to
+ *    endorse or promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ */
+
+#include "openldap.h"
+
+
+#define MILLION_F 1000000.0
+
+
+/* --------------------------------------------------------------
+ * Declarations
+ * -------------------------------------------------------------- */
+VALUE ropenldap_cOpenLDAPConnection;
+
+
+/* --------------------------------------------------
+ *	Memory-management functions
+ * -------------------------------------------------- */
+
+/*
+ * Allocation function
+ */
+static struct ropenldap_connection *
+ropenldap_conn_alloc( LDAP *ldp )
+{
+	struct ropenldap_connection *ptr = ALLOC( struct ropenldap_connection );
+
+	ptr->ldap = ldp;
+
+	return ptr;
+}
+
+
+/*
+ * GC Mark function
+ */
+static void
+ropenldap_conn_gc_mark( struct ropenldap_connection *ptr )
+{
+	/* No-op */
+}
+
+
+
+/*
+ * GC Free function
+ */
+static void
+ropenldap_conn_gc_free( struct ropenldap_connection *ptr )
+{
+	if ( ptr ) {
+		ptr->ldap = NULL;
+
+		xfree( ptr );
+		ptr = NULL;
+	}
+}
+
+
+/*
+ * Object validity checker. Returns the data pointer.
+ */
+static struct ropenldap_connection *
+check_conn( VALUE self )
+{
+	Check_Type( self, T_DATA );
+
+    if ( !IsConnection(self) ) {
+		rb_raise( rb_eTypeError, "wrong argument type %s (expected an OpenLDAP::Connection)",
+				  rb_obj_classname( self ) );
+    }
+
+	return DATA_PTR( self );
+}
+
+
+/*
+ * Fetch the data pointer and check it for sanity.
+ */
+static struct ropenldap_connection *
+ropenldap_get_conn( VALUE self )
+{
+	struct ropenldap_connection *conn = check_conn( self );
+
+	if ( !conn ) rb_fatal( "Use of uninitialized OpenLDAP::Connection" );
+
+	return conn;
+}
+
+
+
+/* --------------------------------------------------------------
+ * Class methods
+ * -------------------------------------------------------------- */
+
+/*
+ * call-seq:
+ *    OpenLDAP::Connection.allocate   -> store
+ *
+ * Allocate a new OpenLDAP::Connection object.
+ *
+ */
+static VALUE
+ropenldap_conn_s_allocate( VALUE klass )
+{
+	return Data_Wrap_Struct( klass, ropenldap_conn_gc_mark, ropenldap_conn_gc_free, 0 );
+}
+
+
+/* --------------------------------------------------------------
+ * Instance methods
+ * -------------------------------------------------------------- */
+
+/*
+ * call-seq:
+ *    OpenLDAP::Connection.new( *uris )           -> conn
+ *
+ * Create a new OpenLDAP::Connection object using the given +uris+.
+ *
+ */
+static VALUE
+ropenldap_conn_initialize( VALUE self, VALUE urls )
+{
+	ropenldap_log_obj( self, "debug", "Initializing 0x%x", self );
+
+	if ( !check_conn(self) ) {
+		VALUE urlstring;
+		LDAP *ldp = NULL;
+		char *url = NULL;
+		struct ropenldap_connection *conn;
+		int result = 0;
+		int proto_ver = 3;
+
+		urlstring = rb_funcall( urls, rb_intern("join"), 1, rb_str_new(" ", 1) );
+		url = RSTRING_PTR( rb_obj_as_string(urlstring) );
+
+		if ( !ldap_is_ldap_url(url) )
+			rb_raise( rb_eArgError, "'%s' is not an LDAP url", url );
+
+		ropenldap_log_obj( self, "info", "Creating a new %s (%s)", rb_obj_classname(self), url );
+		result = ldap_initialize( &ldp, url );
+		ropenldap_check_result( result, "ldap_initialize( \"%s\" )", url );
+
+		conn = DATA_PTR( self ) = ropenldap_conn_alloc( ldp );
+
+	} else {
+		rb_raise( ropenldap_eOpenLDAPError,
+				  "Cannot re-initialize a store once it's been created." );
+	}
+
+	return Qnil;
+}
+
+
+/*
+ * call-seq:
+ *    conn.protocol_version   -> fixnum
+ *
+ * Get the protocol version use by the connection.
+ *
+ *    conn.protocol_version
+ *    # => 3
+ */
+static VALUE
+ropenldap_conn_protocol_version( VALUE self )
+{
+	struct ropenldap_connection *ptr = ropenldap_get_conn( self );
+	int version = 0;
+
+	if ( ldap_get_option(ptr->ldap, LDAP_OPT_PROTOCOL_VERSION, &version) != LDAP_OPT_SUCCESS )
+		rb_raise( ropenldap_eOpenLDAPError, "couldn't get option: LDAP_OPT_PROTOCOL_VERSION" );
+
+	return INT2FIX( version );
+}
+
+
+/*
+ * call-seq:
+ *    conn.protocol_version = version
+ *
+ * Set the protocol version use by the connection to +version+.