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; }
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; } } }
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; }
/* * 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; }