Esempio n. 1
0
static GdaLdapClass *
worker_gdaprov_ldap_get_class_info (WorkerLdapClassInfoData *data, GError **error)
{
	GdaLdapClass *retval = NULL;

	/* initialize known classes */
	data->cdata->classes_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
							   NULL,
							   (GDestroyNotify) ldap_class_free);

	LDAPMessage *msg, *entry;
	int res;
	gchar *subschema = NULL;

	char *subschemasubentry[] = {"subschemaSubentry", NULL};
	char *schema_attrs[] = {"objectClasses", NULL};
	
	/* look for subschema */
	if (! gda_ldap_ensure_bound (data->cnc, NULL))
		return NULL;

	gda_ldap_execution_slowdown (data->cnc);
	res = ldap_search_ext_s (data->cdata->handle, "", LDAP_SCOPE_BASE,
				 "(objectclass=*)",
				 subschemasubentry, 0,
				 NULL, NULL, NULL, 0,
				 &msg);
	if (res != LDAP_SUCCESS) {
		gda_ldap_may_unbind (data->cnc);
		return NULL;
	}

	if ((entry = ldap_first_entry (data->cdata->handle, msg))) {
		char *attr;
		BerElement *ber;
		if ((attr = ldap_first_attribute (data->cdata->handle, entry, &ber))) {
			BerValue **bvals;
			if ((bvals = ldap_get_values_len (data->cdata->handle, entry, attr))) {
				subschema = g_strdup (bvals[0]->bv_val);
				ldap_value_free_len (bvals);
			}
			ldap_memfree (attr);
		}
		if (ber)
			ber_free (ber, 0);
	}
	ldap_msgfree (msg);

	if (! subschema) {
		gda_ldap_may_unbind (data->cnc);
		return NULL;
	}

	/* look for attributeTypes */
	gda_ldap_execution_slowdown (data->cnc);
	res = ldap_search_ext_s (data->cdata->handle, subschema, LDAP_SCOPE_BASE,
				 "(objectclass=*)",
				 schema_attrs, 0,
				 NULL, NULL, NULL, 0,
				 &msg);
	g_free (subschema);
	if (res != LDAP_SUCCESS) {
		gda_ldap_may_unbind (data->cnc);
		return NULL;
	}

	GHashTable *h_refs;
	h_refs = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_strfreev);
	for (entry = ldap_first_entry (data->cdata->handle, msg);
	     entry;
	     entry = ldap_next_entry (data->cdata->handle, msg)) {
		char *attr;
		BerElement *ber;
		for (attr = ldap_first_attribute (data->cdata->handle, msg, &ber);
		     attr;
		     attr = ldap_next_attribute (data->cdata->handle, msg, ber)) {
			if (strcasecmp(attr, "objectClasses")) {
				ldap_memfree (attr);
				continue;
			}

			BerValue **bvals;
			bvals = ldap_get_values_len (data->cdata->handle, entry, attr);
			if (bvals) {
				gint i;
				for (i = 0; bvals[i]; i++) {
					LDAPObjectClass *oc;
					const char *errp;
					int retcode;
					oc = ldap_str2objectclass (bvals[i]->bv_val, &retcode,
								   &errp,
								   LDAP_SCHEMA_ALLOW_ALL);
					if (oc && oc->oc_oid && oc->oc_names && oc->oc_names[0]) {
						GdaLdapClass *lcl;
						guint k;
						lcl = g_new0 (GdaLdapClass, 1);
						lcl->oid = g_strdup (oc->oc_oid);
//#define CLASS_DEBUG
#ifdef CLASS_DEBUG
						g_print ("FOUND CLASS\n");
#endif
						lcl->names = make_array_from_strv (oc->oc_names,
										   &(lcl->nb_names));
						for (k = 0; lcl->names[k]; k++) {
#ifdef CLASS_DEBUG
							g_print ("  oc_names[%d] = %s\n",
								 k, lcl->names[k]);
#endif
							g_hash_table_insert (data->cdata->classes_hash,
									     lcl->names[k],
									     lcl);
						}
						if (oc->oc_desc) {
#ifdef CLASS_DEBUG
							g_print ("  oc_desc = %s\n", oc->oc_desc);
#endif
							lcl->description = g_strdup (oc->oc_desc);
						}
#ifdef CLASS_DEBUG
						g_print ("  oc_kind = %d\n", oc->oc_kind);
#endif
						switch (oc->oc_kind) {
						case 0:
							lcl->kind = GDA_LDAP_CLASS_KIND_ABSTRACT;
							break;
						case 1:
							lcl->kind = GDA_LDAP_CLASS_KIND_STRUTURAL;
							break;
						case 2:
							lcl->kind = GDA_LDAP_CLASS_KIND_AUXILIARY;
							break;
						default:
							lcl->kind = GDA_LDAP_CLASS_KIND_UNKNOWN;
							break;
						}
						lcl->obsolete = oc->oc_obsolete;
#ifdef CLASS_DEBUG
						g_print ("  oc_obsolete = %d\n", oc->oc_obsolete);

#endif
						gchar **refs;
						refs = make_array_from_strv (oc->oc_sup_oids, NULL);
						if (refs)
							g_hash_table_insert (h_refs, lcl, refs);
						else
							data->cdata->top_classes = g_slist_insert_sorted (data->cdata->top_classes,
									     lcl, (GCompareFunc) classes_sort);
#ifdef CLASS_DEBUG
						for (k = 0; oc->oc_sup_oids && oc->oc_sup_oids[k]; k++)
							g_print ("  oc_sup_oids[0] = %s\n",
								 oc->oc_sup_oids[k]);
#endif

						lcl->req_attributes =
							make_array_from_strv (oc->oc_at_oids_must,
									      &(lcl->nb_req_attributes));
#ifdef CLASS_DEBUG
						for (k = 0; oc->oc_at_oids_must && oc->oc_at_oids_must[k]; k++)
							g_print ("  oc_at_oids_must[0] = %s\n",
								 oc->oc_at_oids_must[k]);
#endif
						lcl->opt_attributes =
							make_array_from_strv (oc->oc_at_oids_may,
									      &(lcl->nb_opt_attributes));
#ifdef CLASS_DEBUG
						for (k = 0; oc->oc_at_oids_may && oc->oc_at_oids_may[k]; k++)
							g_print ("  oc_at_oids_may[0] = %s\n",
								 oc->oc_at_oids_may[k]);
#endif
						  
					}
					if (oc)
						ldap_memfree (oc);
				}
				ldap_value_free_len (bvals);
			}
			  
			ldap_memfree (attr);
		}
		if (ber)
			ber_free (ber, 0);
	}
	ldap_msgfree (msg);

	/* create hierarchy */
	g_hash_table_foreach (h_refs, (GHFunc) classes_h_func, data->cdata);
	g_hash_table_destroy (h_refs);

	retval = g_hash_table_lookup (data->cdata->classes_hash, data->classname);
	gda_ldap_may_unbind (data->cnc);
	return retval;
}
Esempio n. 2
0
static GdaLdapEntry *
worker_gdaprov_ldap_describe_entry (WorkerLdapDescrEntryData *data, GError **error)
{
	if (! gda_ldap_ensure_bound (data->cnc, error))
		return NULL;

	gda_ldap_execution_slowdown (data->cnc);

	int res;
	LDAPMessage *msg = NULL;
	const gchar *real_dn;
	real_dn = data->dn ? data->dn : data->cdata->base_dn;
 retry:
	res = ldap_search_ext_s (data->cdata->handle, real_dn, LDAP_SCOPE_BASE,
				 "(objectClass=*)", NULL, 0,
				 NULL, NULL, NULL, -1,
				 &msg);
	switch (res) {
	case LDAP_SUCCESS:
	case LDAP_NO_SUCH_OBJECT: {
		gint nb_entries;
		LDAPMessage *ldap_row;
		char *attr;
		BerElement* ber;
		GdaLdapEntry *lentry;
		GArray *array = NULL;

		nb_entries = ldap_count_entries (data->cdata->handle, msg);
		if (nb_entries == 0) {
			ldap_msgfree (msg);
			gda_ldap_may_unbind (data->cnc);
			return NULL;
		}
		else if (nb_entries > 1) {
			g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
				     GDA_SERVER_PROVIDER_INTERNAL_ERROR,
				     _("LDAP server returned more than one entry with DN '%s'"),
				     real_dn);
			gda_ldap_may_unbind (data->cnc);
			return NULL;
		}

		lentry = g_new0 (GdaLdapEntry, 1);
		lentry->dn = g_strdup (real_dn);
		lentry->attributes_hash = g_hash_table_new (g_str_hash, g_str_equal);
		array = g_array_new (TRUE, FALSE, sizeof (GdaLdapAttribute*));
		ldap_row = ldap_first_entry (data->cdata->handle, msg);
		for (attr = ldap_first_attribute (data->cdata->handle, ldap_row, &ber);
		     attr;
		     attr = ldap_next_attribute (data->cdata->handle, ldap_row, ber)) {
			BerValue **bvals;
			GArray *varray = NULL;
			bvals = ldap_get_values_len (data->cdata->handle, ldap_row, attr);
			if (bvals) {
				gint i;
				for (i = 0; bvals [i]; i++) {
					if (!varray)
						varray = g_array_new (TRUE, FALSE, sizeof (GValue *));
					GValue *value;
					GType type;
					type = gda_ldap_get_g_type (data->cnc, data->cdata, attr, NULL);
					/*g_print ("Type for attr %s is %s\n", attr, gda_g_type_to_string (type)); */
					value = gda_ldap_attr_value_to_g_value (data->cdata, type, bvals[i]);
					g_array_append_val (varray, value);
				}
				ldap_value_free_len (bvals);
			}
			if (varray) {
				GdaLdapAttribute *lattr = NULL;
				lattr = g_new0 (GdaLdapAttribute, 1);
				lattr->attr_name = g_strdup (attr);
				lattr->values = (GValue**) varray->data;
				lattr->nb_values = varray->len;
				g_array_free (varray, FALSE);

				g_array_append_val (array, lattr);
				g_hash_table_insert (lentry->attributes_hash, lattr->attr_name, lattr);
			}
			ldap_memfree (attr);
		}
		if (ber)
			ber_free (ber, 0);
		ldap_msgfree (msg);
		if (array) {
			g_array_sort (array, (GCompareFunc) attr_array_sort_func);
			lentry->attributes = (GdaLdapAttribute**) array->data;
			lentry->nb_attributes = array->len;
			g_array_free (array, FALSE);
		}
		gda_ldap_may_unbind (data->cnc);
		return lentry;
	}
	case LDAP_SERVER_DOWN:
	default: {
		if (res == LDAP_SERVER_DOWN) {
			gint i;
			for (i = 0; i < 5; i++) {
				if (gda_ldap_rebind (data->cnc, NULL))
					goto retry;
				g_usleep (G_USEC_PER_SEC * 2);
			}
		}
		/* error */
		int ldap_errno;
		ldap_get_option (data->cdata->handle, LDAP_OPT_ERROR_NUMBER, &ldap_errno);
		g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_OTHER_ERROR,
			     "%s", ldap_err2string(ldap_errno));
		gda_ldap_may_unbind (data->cnc);
		return NULL;
	}
	}
}
Esempio n. 3
0
static LdapAttribute *
worker_gda_ldap_get_attr_info (WorkerLdapAttrInfoData *data, GError **error)
{
	LdapAttribute *retval = NULL;

	if (data->cdata->attributes_hash)
		return g_hash_table_lookup (data->cdata->attributes_hash, data->attribute);

	/* initialize known types */
	data->cdata->attributes_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
							NULL,
							(GDestroyNotify) ldap_attribute_free);
	

	if (data->cdata->attributes_cache_file) {
		/* try to load from cache file, which must contain one line per attribute:
		 * <syntax oid>,0|1,<attribute name>
		 */
		gchar *fdata;
		if (g_file_get_contents (data->cdata->attributes_cache_file, &fdata, NULL, NULL)) {
			gchar *start, *ptr;
			gchar **array;
			start = fdata;
			while (1) {
				gboolean done = FALSE;
				for (ptr = start; *ptr && (*ptr != '\n'); ptr++);
				if (*ptr == '\n')
					*ptr = 0;
				else
					done = TRUE;
				
				if (*start && (*start != '#')) {
					array = g_strsplit (start, ",", 3);
					if (array[0] && array[1] && array[2]) {
						LdapAttribute *lat;
						lat = g_new (LdapAttribute, 1);
						lat->name = g_strdup (array[2]);
						lat->type = gda_ldap_get_type_info (array[0]);
						lat->single_value = (*array[1] == '0' ? FALSE : TRUE);
						g_hash_table_insert (data->cdata->attributes_hash,
								     lat->name, lat);
						/*g_print ("CACHE ADDED [%s][%p][%d] for OID %s\n",
						  lat->name, lat->type, lat->single_value,
						  array[0]);*/
					}
					g_strfreev (array);
				}
				if (done)
					break;
				else
					start = ptr+1;
			}
			g_free (fdata);
			return g_hash_table_lookup (data->cdata->attributes_hash, data->attribute);
		}
	}

	GString *string = NULL;
	LDAPMessage *msg, *entry;
	int res;
	gchar *subschema = NULL;

	char *subschemasubentry[] = {"subschemaSubentry", NULL};
	char *schema_attrs[] = {"attributeTypes", NULL};
	
	/* look for subschema */
	if (! gda_ldap_ensure_bound (data->cnc, NULL))
		return NULL;

	gda_ldap_execution_slowdown (data->cnc);
	res = ldap_search_ext_s (data->cdata->handle, "", LDAP_SCOPE_BASE,
				 "(objectclass=*)",
				 subschemasubentry, 0,
				 NULL, NULL, NULL, 0,
				 &msg);
	if (res != LDAP_SUCCESS) {
		gda_ldap_may_unbind (data->cnc);
		return NULL;
	}

	if ((entry = ldap_first_entry (data->cdata->handle, msg))) {
		char *attr;
		BerElement *ber;
		if ((attr = ldap_first_attribute (data->cdata->handle, entry, &ber))) {
			BerValue **bvals;
			if ((bvals = ldap_get_values_len (data->cdata->handle, entry, attr))) {
				subschema = g_strdup (bvals[0]->bv_val);
				ldap_value_free_len (bvals);
			}
			ldap_memfree (attr);
		}
		if (ber)
			ber_free (ber, 0);
	}
	ldap_msgfree (msg);

	if (! subschema) {
		gda_ldap_may_unbind (data->cnc);
		return NULL;
	}

	/* look for attributeTypes */
	gda_ldap_execution_slowdown (data->cnc);
	res = ldap_search_ext_s (data->cdata->handle, subschema, LDAP_SCOPE_BASE,
				 "(objectclass=*)",
				 schema_attrs, 0,
				 NULL, NULL, NULL, 0,
				 &msg);
	g_free (subschema);
	if (res != LDAP_SUCCESS) {
		gda_ldap_may_unbind (data->cnc);
		return NULL;
	}

	if (data->cdata->attributes_cache_file)
		string = g_string_new ("# Cache file. This file can safely be removed, in this case\n"
				       "# it will be automatically recreated.\n"
				       "# DO NOT MODIFY\n");
	for (entry = ldap_first_entry (data->cdata->handle, msg);
	     entry;
	     entry = ldap_next_entry (data->cdata->handle, msg)) {
		char *attr;
		BerElement *ber;
		for (attr = ldap_first_attribute (data->cdata->handle, msg, &ber);
		     attr;
		     attr = ldap_next_attribute (data->cdata->handle, msg, ber)) {
			if (strcasecmp(attr, "attributeTypes")) {
				ldap_memfree (attr);
				continue;
			}

			BerValue **bvals;
			bvals = ldap_get_values_len (data->cdata->handle, entry, attr);
			if (bvals) {
				gint i;
				for (i = 0; bvals[i]; i++) {
					LDAPAttributeType *at;
					const char *errp;
					int retcode;
					at = ldap_str2attributetype (bvals[i]->bv_val, &retcode,
								     &errp,
								     LDAP_SCHEMA_ALLOW_ALL);
					if (at && at->at_names && at->at_syntax_oid &&
					    at->at_names[0] && *(at->at_names[0])) {
						LdapAttribute *lat;
						lat = g_new (LdapAttribute, 1);
						lat->name = g_strdup (at->at_names [0]);
						lat->type = gda_ldap_get_type_info (at->at_syntax_oid);
						lat->single_value = (at->at_single_value == 0 ? FALSE : TRUE);
						g_hash_table_insert (data->cdata->attributes_hash,
								     lat->name, lat);
						/*g_print ("ADDED [%s][%p][%d] for OID %s\n",
						  lat->name, lat->type, lat->single_value,
						  at->at_syntax_oid);*/
						if (string)
							g_string_append_printf (string, "%s,%d,%s\n",
										at->at_syntax_oid,
										lat->single_value,
										lat->name);
									  
					}
					if (at)
						ldap_memfree (at);
				}
				ldap_value_free_len (bvals);
			}
			  
			ldap_memfree (attr);
		}
		if (ber)
			ber_free (ber, 0);
	}
	ldap_msgfree (msg);

	if (string) {
		if (! g_file_set_contents (data->cdata->attributes_cache_file, string->str, -1, NULL)) {
			gchar *dirname;
			dirname = g_path_get_dirname (data->cdata->attributes_cache_file);
			g_mkdir_with_parents (dirname, 0700);
			g_free (dirname);
			g_file_set_contents (data->cdata->attributes_cache_file, string->str, -1, NULL);
		}
		g_string_free (string, TRUE);
	}

	gda_ldap_may_unbind (data->cnc);
	retval = g_hash_table_lookup (data->cdata->attributes_hash, data->attribute);
	return retval;
}
Esempio n. 4
0
/* 
 * Prepare connection request
 *
 * In this function, the following _must_ be done:
 *   - check for the presence and validify of the parameters required to actually open a connection,
 *     using @params
 *   - open the real connection to the database using the parameters previously checked, create one or
 *     more GdaDataModel objects and declare them to the virtual connection with table names
 *   - create a LdapConnectionData structure and associate it to @cnc
 *
 * Returns: TRUE if no error occurred, or FALSE otherwise (and an ERROR connection event must be added to @cnc)
 */
static gboolean
gda_ldap_provider_prepare_connection (GdaServerProvider *provider, GdaConnection *cnc,
				      GdaQuarkList *params, GdaQuarkList *auth)
{
	g_return_val_if_fail (GDA_IS_LDAP_PROVIDER (provider), FALSE);
	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);

	/* Check for connection parameters */
	const gchar *base_dn;
	const gchar *host;
	const gchar *tmp;
	const gchar *port;
	const gchar *user = NULL;
	gchar *dnuser = NULL;
        const gchar *pwd = NULL;
        const gchar *time_limit = NULL;
        const gchar *size_limit = NULL;
        const gchar *tls_method = NULL;
        const gchar *tls_cacert = NULL;
	int rtls_method = -1;
	gint rport;
	gboolean use_ssl, use_cache;

	/* calling the parent's function first */
	GdaServerProviderBase *parent_functions;
        parent_functions = gda_server_provider_get_impl_functions_for_class (parent_class, GDA_SERVER_PROVIDER_FUNCTIONS_BASE);
	if (parent_functions->prepare_connection) {
		if (! parent_functions->prepare_connection (GDA_SERVER_PROVIDER (provider), cnc, params, auth))
			return FALSE;
	}

        base_dn = gda_quark_list_find (params, "DB_NAME");
        if (!base_dn) {
                gda_connection_add_event_string (cnc, "%s",
                                                 _("The connection string must contain the DB_NAME value"));
                return FALSE;
        }
	host = gda_quark_list_find (params, "HOST");
	if (!host)
		host = "127.0.0.1";
        port = gda_quark_list_find (params, "PORT");
        tmp = gda_quark_list_find (params, "USE_SSL");
	use_ssl = (tmp && ((*tmp == 't') || (*tmp == 'T'))) ? TRUE : FALSE;
	tmp = gda_quark_list_find (params, "USE_CACHE");
	use_cache = (!tmp || ((*tmp == 't') || (*tmp == 'T'))) ? TRUE : FALSE;
	if (port && *port)
		rport = atoi (port);
	else {
		if (use_ssl)
			rport = LDAPS_PORT;
		else
			rport = LDAP_PORT;
	}
	user = gda_quark_list_find (auth, "USERNAME");
        if (!user)
                user = gda_quark_list_find (params, "USERNAME");
        pwd = gda_quark_list_find (auth, "PASSWORD");
        if (!pwd)
                pwd = gda_quark_list_find (params, "PASSWORD");

	tls_cacert = gda_quark_list_find (params, "TLS_CACERT");
	tls_method = gda_quark_list_find (params, "TLS_REQCERT");
	if (tls_method && *tls_method) {
		if (! g_ascii_strcasecmp (tls_method, "never"))
			rtls_method = LDAP_OPT_X_TLS_NEVER;
		else if (! g_ascii_strcasecmp (tls_method, "hard"))
			rtls_method = LDAP_OPT_X_TLS_HARD;
		else if (! g_ascii_strcasecmp (tls_method, "demand"))
			rtls_method = LDAP_OPT_X_TLS_DEMAND;
		else if (! g_ascii_strcasecmp (tls_method, "allow"))
			rtls_method = LDAP_OPT_X_TLS_ALLOW;
		else if (! g_ascii_strcasecmp (tls_method, "try"))
			rtls_method = LDAP_OPT_X_TLS_TRY;
		else {
			gda_connection_add_event_string (cnc, "%s",
							 _("Invalid value for 'TLS_REQCERT'"));
			return FALSE;
		}
	}
	time_limit = gda_quark_list_find (params, "TIME_LIMIT");
	size_limit = gda_quark_list_find (params, "SIZE_LIMIT");

	/* open LDAP connection */
	LdapConnectionData *cdata;
	LDAP *ld;
        int res;
	gchar *url;

	if (use_ssl) {
		/* Configuring SSL/TLS options:
		 * this is for texting purpose only, and should actually be done through LDAP's conf.
		 * files, see: man 5 ldap.conf
		 *
		 * For example ~/.ldaprc can contain:
		 * TLS_REQCERT demand
		 * TLS_CACERT /usr/share/ca-certificates/mozilla/Thawte_Premium_Server_CA.crt
		 *
		 * Note: if server certificate verification fails,
		 * the error message is: "Can't contact LDAP server"
		 */
		if (rtls_method >= 0) {
			res = ldap_set_option (NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &rtls_method);
			if (res != LDAP_SUCCESS) {
				gda_connection_add_event_string (cnc, ldap_err2string (res));
				return FALSE;
			}
		}

		if (tls_cacert && *tls_cacert) {
			res = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTFILE, tls_cacert);
			if (res != LDAP_SUCCESS) {
				gda_connection_add_event_string (cnc, ldap_err2string (res));
				return FALSE;
			}
		}

		url = g_strdup_printf ("ldaps://%s:%d", host, rport);
	}
	else
		url = g_strdup_printf ("ldap://%s:%d", host, rport);

	if (user && *user && ! gda_ldap_parse_dn (user, NULL)) {
		/* analysing the @user parameter */
		/* the user name is not a DN => we need to fetch the DN of the entry
		 * using filters defined in the "mappings" array @user */
		guint i;
		const gchar *ptr;
		GString *rname;
		rname = g_string_new ("");
		for (ptr = user; *ptr; ptr++) {
			if ((*ptr == ',') || (*ptr == '\\') || (*ptr == '#') ||
			    (*ptr == '+') || (*ptr == '<') ||
			    (*ptr == '>') || (*ptr == ';') || (*ptr == '"') ||
			    (*ptr == '=') || (*ptr == '*'))
				g_string_append_c (rname, '\\');
			g_string_append_c (rname, *ptr);
		}
		for (i = 0; i < sizeof (mappings) / sizeof (LdapAuthMapping); i++) {
			gchar *tmp;
			tmp = fetch_user_dn (url, base_dn, rname->str, &(mappings[i]));
			if (tmp) {
				dnuser = tmp;
				break;
			}
		}
		g_string_free (rname, TRUE);

		/* if no DN user has been found, then still use the provided name AS IS
		 * => dnuser can be %NULL here */
	}

	res = ldap_initialize (&ld, url);
        if (res != LDAP_SUCCESS) {
		gda_connection_add_event_string (cnc, ldap_err2string (res));
		g_free (url);
		g_free (dnuser);
                return FALSE;
        }

	cdata = g_new0 (LdapConnectionData, 1);
	cdata->keep_bound_count = 0;
	cdata->handle = ld;
	cdata->url = url;
	cdata->time_limit = 0;
	cdata->size_limit = 0;
	cdata->base_dn = g_strdup (base_dn);
	if (use_cache)
		cdata->attributes_cache_file = compute_data_file_name (params, TRUE, "attrs");

	/* set protocol version to 3 by default */
	int version = LDAP_VERSION3;
	res = ldap_set_option (cdata->handle, LDAP_OPT_PROTOCOL_VERSION, &version);
        if (res != LDAP_SUCCESS) {
		if (res == LDAP_PROTOCOL_ERROR) {
			version = LDAP_VERSION2;
			res = ldap_set_option (cdata->handle, LDAP_OPT_PROTOCOL_VERSION, &version);
		}
		if (res != LDAP_SUCCESS) {
			gda_connection_add_event_string (cnc, ldap_err2string (res));
			gda_ldap_free_cnc_data (cdata);
			g_free (dnuser);
			return FALSE;
		}
        }

	/* time limit */
	if (time_limit && *time_limit) {
		int limit = atoi (time_limit);
		res = ldap_set_option (cdata->handle, LDAP_OPT_TIMELIMIT, &limit);
		if (res != LDAP_SUCCESS) {
			gda_connection_add_event_string (cnc, ldap_err2string (res));
			gda_ldap_free_cnc_data (cdata);
			g_free (dnuser);
			return FALSE;
		}
		cdata->time_limit = limit;
	}

	/* size limit */
	if (size_limit && *size_limit) {
		int limit = atoi (size_limit);
		res = ldap_set_option (cdata->handle, LDAP_OPT_SIZELIMIT, &limit);
		if (res != LDAP_SUCCESS) {
			gda_connection_add_event_string (cnc, ldap_err2string (res));
			gda_ldap_free_cnc_data (cdata);
			g_free (dnuser);
			return FALSE;
		}
		cdata->size_limit = limit;
	}

	/* authentication */
	struct berval cred;
        memset (&cred, 0, sizeof (cred));
        cred.bv_len = pwd && *pwd ? strlen (pwd) : 0;
        cred.bv_val = pwd && *pwd ? (char *) pwd : NULL;
        res = ldap_sasl_bind_s (ld, dnuser ? dnuser : user, NULL, &cred, NULL, NULL, NULL);
	if (res != LDAP_SUCCESS) {
		gda_connection_add_event_string (cnc, ldap_err2string (res));
		gda_ldap_free_cnc_data (cdata);
		g_free (dnuser);
                return FALSE;
	}
	if (pwd) {
		gchar *tmp;
		tmp = g_strdup_printf ("PASSWORD=%s", pwd);
		cdata->auth = gda_quark_list_new_from_string (tmp);
		g_free (tmp);
	}
	if (dnuser) {
		gchar *tmp;
		tmp = g_strdup_printf ("USERNAME=%s", dnuser);
		if (cdata->auth)
			gda_quark_list_add_from_string (cdata->auth, tmp, FALSE);
		else
			cdata->auth = gda_quark_list_new_from_string (tmp);
		g_free (tmp);
		dnuser = NULL;
	}
	else if (user) {
		gchar *tmp;
		tmp = g_strdup_printf ("USERNAME=%s", user);
		if (cdata->auth)
			gda_quark_list_add_from_string (cdata->auth, tmp, FALSE);
		else
			cdata->auth = gda_quark_list_new_from_string (tmp);
		g_free (tmp);
	}

	/* set startup file name */
	gchar *fname;
	fname = compute_data_file_name (params, FALSE, "start");
	g_object_set ((GObject*) cnc, "startup-file", fname, NULL);
	g_free (fname);

	/* open virtual connection */
	gda_virtual_connection_internal_set_provider_data (GDA_VIRTUAL_CONNECTION (cnc), 
							   cdata, (GDestroyNotify) gda_ldap_free_cnc_data);
	gda_ldap_may_unbind (GDA_LDAP_CONNECTION (cnc));
	return TRUE;
}