1 /*
2 * Copyright (C) 2003 Akira TAGOH <tagoh@gnome-db.org>
3 * Copyright (C) 2003 German Poo-Caaman~o <gpoo@ubiobio.cl>
4 * Copyright (C) 2003 Gonzalo Paniagua Javier <gonzalo@gnome-db.org>
5 * Copyright (C) 2003 Rodrigo Moya <rodrigo@gnome-db.org>
6 * Copyright (C) 2004 Julio M. Merino Vidal <jmmv@menta.net>
7 * Copyright (C) 2004 Jürg Billeter <j@bitron.ch>
8 * Copyright (C) 2004 Szalai Ferenc <szferi@einstein.ki.iif.hu>
9 * Copyright (C) 2005 - 2012 Vivien Malerba <malerba@gnome-db.org>
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the
23 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
24 * Boston, MA 02110-1301, USA.
25 */
26
27 #include <stdlib.h>
28 #include <string.h>
29 #include <glib/gi18n-lib.h>
30 #include <virtual/gda-ldap-connection.h>
31 #include <libgda/gda-connection-private.h>
32 #include <libgda/gda-data-model-iter.h>
33 #include <libgda/gda-util.h>
34 #include <libgda/gda-data-model-array.h>
35 #include <libgda/sql-parser/gda-sql-parser.h>
36 #include "gda-ldap.h"
37 #include "gda-ldap-provider.h"
38 #include "gdaprov-data-model-ldap.h"
39 #include "gda-ldap-util.h"
40
41 static void gda_ldap_provider_class_init (GdaLdapProviderClass *klass);
42 static void gda_ldap_provider_init (GdaLdapProvider *provider,
43 GdaLdapProviderClass *klass);
44 static void gda_ldap_provider_finalize (GObject *object);
45
46 static const gchar *gda_ldap_provider_get_name (GdaServerProvider *provider);
47 static const gchar *gda_ldap_provider_get_version (GdaServerProvider *provider);
48 static GdaConnection *gda_ldap_provider_create_connection (GdaServerProvider *provider);
49 static gboolean gda_ldap_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
50 GdaQuarkList *params, GdaQuarkList *auth,
51 guint *task_id, GdaServerProviderAsyncCallback async_cb, gpointer cb_data);
52 static GObject *gda_ldap_provider_statement_execute (GdaServerProvider *provider, GdaConnection *cnc,
53 GdaStatement *stmt, GdaSet *params,
54 GdaStatementModelUsage model_usage,
55 GType *col_types, GdaSet **last_inserted_row,
56 guint *task_id, GdaServerProviderExecCallback async_cb,
57 gpointer cb_data, GError **error);
58 static const gchar *gda_ldap_provider_get_server_version (GdaServerProvider *provider,
59 GdaConnection *cnc);
60 static const gchar *gda_ldap_provider_get_database (GdaServerProvider *provider, GdaConnection *cnc);
61
62 static GObjectClass *parent_class = NULL;
63
64 /*
65 * private connection data destroy
66 */
67 static void gda_ldap_free_cnc_data (LdapConnectionData *cdata);
68
69 /*
70 * GdaLdapProvider class implementation
71 */
72 static void
gda_ldap_provider_class_init(GdaLdapProviderClass * klass)73 gda_ldap_provider_class_init (GdaLdapProviderClass *klass)
74 {
75 GObjectClass *object_class = G_OBJECT_CLASS (klass);
76 GdaServerProviderClass *provider_class = GDA_SERVER_PROVIDER_CLASS (klass);
77
78 parent_class = g_type_class_peek_parent (klass);
79
80 object_class->finalize = gda_ldap_provider_finalize;
81 provider_class->create_connection = gda_ldap_provider_create_connection;
82
83 provider_class->get_name = gda_ldap_provider_get_name;
84 provider_class->get_version = gda_ldap_provider_get_version;
85 provider_class->open_connection = gda_ldap_provider_open_connection;
86 provider_class->get_server_version = gda_ldap_provider_get_server_version;
87 provider_class->get_database = gda_ldap_provider_get_database;
88 provider_class->statement_execute = gda_ldap_provider_statement_execute;
89 }
90
91 static void
gda_ldap_provider_init(G_GNUC_UNUSED GdaLdapProvider * pg_prv,G_GNUC_UNUSED GdaLdapProviderClass * klass)92 gda_ldap_provider_init (G_GNUC_UNUSED GdaLdapProvider *pg_prv,
93 G_GNUC_UNUSED GdaLdapProviderClass *klass)
94 {
95 /* nothing specific there */
96 }
97
98 static void
gda_ldap_provider_finalize(GObject * object)99 gda_ldap_provider_finalize (GObject *object)
100 {
101 GdaLdapProvider *pg_prv = (GdaLdapProvider *) object;
102
103 g_return_if_fail (GDA_IS_LDAP_PROVIDER (pg_prv));
104
105 /* chain to parent class */
106 parent_class->finalize(object);
107 }
108
109 GType
gda_ldap_provider_get_type(void)110 gda_ldap_provider_get_type (void)
111 {
112 static GType type = 0;
113
114 if (G_UNLIKELY (type == 0)) {
115 static GMutex registering;
116 static GTypeInfo info = {
117 sizeof (GdaLdapProviderClass),
118 (GBaseInitFunc) NULL,
119 (GBaseFinalizeFunc) NULL,
120 (GClassInitFunc) gda_ldap_provider_class_init,
121 NULL, NULL,
122 sizeof (GdaLdapProvider),
123 0,
124 (GInstanceInitFunc) gda_ldap_provider_init,
125 0
126 };
127 g_mutex_lock (®istering);
128 if (type == 0)
129 type = g_type_register_static (GDA_TYPE_VPROVIDER_DATA_MODEL, "GdaLdapProvider", &info, 0);
130 g_mutex_unlock (®istering);
131 }
132
133 return type;
134 }
135
136 /*
137 * Get provider name request
138 */
139 static const gchar *
gda_ldap_provider_get_name(G_GNUC_UNUSED GdaServerProvider * provider)140 gda_ldap_provider_get_name (G_GNUC_UNUSED GdaServerProvider *provider)
141 {
142 return LDAP_PROVIDER_NAME;
143 }
144
145 /*
146 * Get version request
147 */
148 static const gchar *
gda_ldap_provider_get_version(G_GNUC_UNUSED GdaServerProvider * provider)149 gda_ldap_provider_get_version (G_GNUC_UNUSED GdaServerProvider *provider)
150 {
151 return PACKAGE_VERSION;
152 }
153
154 static GdaConnection *
gda_ldap_provider_create_connection(GdaServerProvider * provider)155 gda_ldap_provider_create_connection (GdaServerProvider *provider)
156 {
157 GdaConnection *cnc;
158 g_return_val_if_fail (GDA_IS_LDAP_PROVIDER (provider), NULL);
159
160 cnc = g_object_new (GDA_TYPE_LDAP_CONNECTION, "provider", provider, NULL);
161
162 return cnc;
163 }
164
165 /*
166 * compute cache file's absolute name
167 */
168 static gchar *
compute_data_file_name(GdaQuarkList * params,gboolean is_cache,const gchar * data_type)169 compute_data_file_name (GdaQuarkList *params, gboolean is_cache, const gchar *data_type)
170 {
171 /* real cache file name */
172 GString *string;
173 gchar *cfile, *evalue;
174 const gchar *base_dn;
175 const gchar *host;
176 const gchar *require_ssl;
177 const gchar *port;
178 gint rport;
179 gboolean use_ssl;
180
181 base_dn = gda_quark_list_find (params, "DB_NAME");
182 host = gda_quark_list_find (params, "HOST");
183 if (!host)
184 host = "127.0.0.1";
185 port = gda_quark_list_find (params, "PORT");
186 require_ssl = gda_quark_list_find (params, "USE_SSL");
187 use_ssl = (require_ssl && ((*require_ssl == 't') || (*require_ssl == 'T'))) ? TRUE : FALSE;
188 if (port && *port)
189 rport = atoi (port);
190 else {
191 if (use_ssl)
192 rport = LDAPS_PORT;
193 else
194 rport = LDAP_PORT;
195 }
196 string = g_string_new ("");
197 evalue = gda_rfc1738_encode (host);
198 g_string_append_printf (string, ",=%s", evalue);
199 g_free (evalue);
200 g_string_append_printf (string, ";PORT=%d", rport);
201 if (base_dn) {
202 evalue = gda_rfc1738_encode (base_dn);
203 g_string_append_printf (string, ";BASE_DN,=%s", evalue);
204 g_free (evalue);
205 }
206 evalue = g_compute_checksum_for_string (G_CHECKSUM_SHA1, string->str, -1);
207 g_string_free (string, TRUE);
208 if (is_cache)
209 cfile = g_strdup_printf ("%s_%s", evalue, data_type);
210 else
211 cfile = g_strdup_printf ("ldap-%s.%s", evalue, data_type);
212 g_free (evalue);
213
214 gchar *fname;
215 if (is_cache)
216 fname = g_build_path (G_DIR_SEPARATOR_S, g_get_user_cache_dir (),
217 "libgda", "ldap", cfile, NULL);
218 else
219 fname = g_build_path (G_DIR_SEPARATOR_S, g_get_user_data_dir (),
220 "libgda", cfile, NULL);
221
222 g_free (cfile);
223 return fname;
224 }
225
226 typedef struct {
227 gchar *filter_format;
228 gchar *attribute;
229 } LdapAuthMapping;
230
231 LdapAuthMapping mappings[] = {
232 {"(&(uid=%s)(objectclass=inetOrgPerson))", "uid"},
233 {"(sAMAccountName=%s)", "sAMAccountName"}, /* Active Directory */
234 };
235
236 /*
237 * Using @url and @username, performs the following tasks:
238 * - bind to the LDAP server anonymously
239 * - search the directory to identify the entry for the provided user name,
240 * filter: (&(uid=##uid)(objectclass=inetOrgPerson))
241 * - if one and only one entry is returned, get the DN of the entry and check that the UID is correct
242 *
243 * If all the steps are right, it returns the DN of the identified entry as a new string.
244 */
245 static gchar *
fetch_user_dn(const gchar * url,const gchar * base,const gchar * username,LdapAuthMapping * mapping)246 fetch_user_dn (const gchar *url, const gchar *base, const gchar *username, LdapAuthMapping *mapping)
247 {
248 LDAP *ld;
249 int res;
250 int version = LDAP_VERSION3;
251 gchar *dn = NULL;
252 LDAPMessage *msg = NULL;
253
254 if (! username)
255 return NULL;
256
257 res = ldap_initialize (&ld, url);
258 if (res != LDAP_SUCCESS)
259 return NULL;
260
261 res = ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION, &version);
262 if (res != LDAP_SUCCESS) {
263 if (res == LDAP_PROTOCOL_ERROR) {
264 version = LDAP_VERSION2;
265 res = ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION, &version);
266 }
267 if (res != LDAP_SUCCESS)
268 goto out;
269 }
270
271 struct berval cred;
272 memset (&cred, 0, sizeof (cred));
273 res = ldap_sasl_bind_s (ld, NULL, NULL, &cred, NULL, NULL, NULL);
274 if (res != LDAP_SUCCESS)
275 goto out;
276
277 gchar *filter;
278 gchar *attributes[] = {NULL, NULL};
279 attributes[0] = mapping->attribute;
280 filter = g_strdup_printf (mapping->filter_format, username);
281 res = ldap_search_ext_s (ld, base, LDAP_SCOPE_SUBTREE,
282 filter, attributes, 0,
283 NULL, NULL, NULL, 2, &msg);
284 g_free (filter);
285 if (res != LDAP_SUCCESS)
286 goto out;
287
288 LDAPMessage *ldap_row;
289 for (ldap_row = ldap_first_entry (ld, msg);
290 ldap_row;
291 ldap_row = ldap_next_entry (ld, ldap_row)) {
292 char *attr, *uid;
293 attr = ldap_get_dn (ld, ldap_row);
294 if (attr) {
295 BerElement* ber;
296 for (uid = ldap_first_attribute (ld, ldap_row, &ber);
297 uid;
298 uid = ldap_next_attribute (ld, ldap_row, ber)) {
299 BerValue **bvals;
300 bvals = ldap_get_values_len (ld, ldap_row, uid);
301 if (!bvals || !bvals[0] || bvals[1] || strcmp (bvals[0]->bv_val, username)) {
302 g_free (dn);
303 dn = NULL;
304 }
305 ldap_value_free_len (bvals);
306 ldap_memfree (uid);
307 }
308
309 if (dn) {
310 /* more than 1 entry => unique DN could not be identified */
311 g_free (dn);
312 dn = NULL;
313 goto out;
314 }
315
316 dn = g_strdup (attr);
317 ldap_memfree (attr);
318 }
319 }
320
321 out:
322 if (msg)
323 ldap_msgfree (msg);
324 ldap_unbind_ext (ld, NULL, NULL);
325 /*g_print ("Identified DN: [%s]\n", dn);*/
326 return dn;
327 }
328
329 /*
330 * Open connection request
331 *
332 * In this function, the following _must_ be done:
333 * - check for the presence and validify of the parameters required to actually open a connection,
334 * using @params
335 * - open the real connection to the database using the parameters previously checked, create one or
336 * more GdaDataModel objects and declare them to the virtual connection with table names
337 * - open virtual (SQLite) connection
338 * - create a LdapConnectionData structure and associate it to @cnc
339 *
340 * Returns: TRUE if no error occurred, or FALSE otherwise (and an ERROR connection event must be added to @cnc)
341 */
342 static gboolean
gda_ldap_provider_open_connection(GdaServerProvider * provider,GdaConnection * cnc,GdaQuarkList * params,GdaQuarkList * auth,G_GNUC_UNUSED guint * task_id,GdaServerProviderAsyncCallback async_cb,G_GNUC_UNUSED gpointer cb_data)343 gda_ldap_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
344 GdaQuarkList *params, GdaQuarkList *auth,
345 G_GNUC_UNUSED guint *task_id, GdaServerProviderAsyncCallback async_cb,
346 G_GNUC_UNUSED gpointer cb_data)
347 {
348 g_return_val_if_fail (GDA_IS_LDAP_PROVIDER (provider), FALSE);
349 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
350
351 /* Don't allow asynchronous connection opening for virtual providers */
352 if (async_cb) {
353 gda_connection_add_event_string (cnc, _("Provider does not support asynchronous connection open"));
354 return FALSE;
355 }
356
357 /* Check for connection parameters */
358 const gchar *base_dn;
359 const gchar *host;
360 const gchar *tmp;
361 const gchar *port;
362 const gchar *user = NULL;
363 gchar *dnuser = NULL;
364 const gchar *pwd = NULL;
365 const gchar *time_limit = NULL;
366 const gchar *size_limit = NULL;
367 const gchar *tls_method = NULL;
368 const gchar *tls_cacert = NULL;
369 int rtls_method = -1;
370 gint rport;
371 gboolean use_ssl, use_cache;
372
373 base_dn = gda_quark_list_find (params, "DB_NAME");
374 if (!base_dn) {
375 gda_connection_add_event_string (cnc, "%s",
376 _("The connection string must contain the DB_NAME value"));
377 return FALSE;
378 }
379 host = gda_quark_list_find (params, "HOST");
380 if (!host)
381 host = "127.0.0.1";
382 port = gda_quark_list_find (params, "PORT");
383 tmp = gda_quark_list_find (params, "USE_SSL");
384 use_ssl = (tmp && ((*tmp == 't') || (*tmp == 'T'))) ? TRUE : FALSE;
385 tmp = gda_quark_list_find (params, "USE_CACHE");
386 use_cache = (!tmp || ((*tmp == 't') || (*tmp == 'T'))) ? TRUE : FALSE;
387 if (port && *port)
388 rport = atoi (port);
389 else {
390 if (use_ssl)
391 rport = LDAPS_PORT;
392 else
393 rport = LDAP_PORT;
394 }
395 user = gda_quark_list_find (auth, "USERNAME");
396 if (!user)
397 user = gda_quark_list_find (params, "USERNAME");
398 pwd = gda_quark_list_find (auth, "PASSWORD");
399 if (!pwd)
400 pwd = gda_quark_list_find (params, "PASSWORD");
401
402 tls_cacert = gda_quark_list_find (params, "TLS_CACERT");
403 tls_method = gda_quark_list_find (params, "TLS_REQCERT");
404 if (tls_method && *tls_method) {
405 if (! g_ascii_strcasecmp (tls_method, "never"))
406 rtls_method = LDAP_OPT_X_TLS_NEVER;
407 else if (! g_ascii_strcasecmp (tls_method, "hard"))
408 rtls_method = LDAP_OPT_X_TLS_HARD;
409 else if (! g_ascii_strcasecmp (tls_method, "demand"))
410 rtls_method = LDAP_OPT_X_TLS_DEMAND;
411 else if (! g_ascii_strcasecmp (tls_method, "allow"))
412 rtls_method = LDAP_OPT_X_TLS_ALLOW;
413 else if (! g_ascii_strcasecmp (tls_method, "try"))
414 rtls_method = LDAP_OPT_X_TLS_TRY;
415 else {
416 gda_connection_add_event_string (cnc, "%s",
417 _("Invalid value for 'TLS_REQCERT'"));
418 return FALSE;
419 }
420 }
421 time_limit = gda_quark_list_find (params, "TIME_LIMIT");
422 size_limit = gda_quark_list_find (params, "SIZE_LIMIT");
423
424 /* open LDAP connection */
425 LdapConnectionData *cdata;
426 LDAP *ld;
427 int res;
428 gchar *url;
429
430 if (use_ssl) {
431 /* Configuring SSL/TLS options:
432 * this is for texting purpose only, and should actually be done through LDAP's conf.
433 * files, see: man 5 ldap.conf
434 *
435 * For example ~/.ldaprc can contain:
436 * TLS_REQCERT demand
437 * TLS_CACERT /usr/share/ca-certificates/mozilla/Thawte_Premium_Server_CA.crt
438 *
439 * Note: if server certificate verification fails,
440 * the error message is: "Can't contact LDAP server"
441 */
442 if (rtls_method >= 0) {
443 res = ldap_set_option (NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &rtls_method);
444 if (res != LDAP_SUCCESS) {
445 gda_connection_add_event_string (cnc, ldap_err2string (res));
446 return FALSE;
447 }
448 }
449
450 if (tls_cacert && *tls_cacert) {
451 res = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTFILE, tls_cacert);
452 if (res != LDAP_SUCCESS) {
453 gda_connection_add_event_string (cnc, ldap_err2string (res));
454 return FALSE;
455 }
456 }
457
458 url = g_strdup_printf ("ldaps://%s:%d", host, rport);
459 }
460 else
461 url = g_strdup_printf ("ldap://%s:%d", host, rport);
462
463 if (user && *user && ! gda_ldap_parse_dn (user, NULL)) {
464 /* analysing the @user parameter */
465 /* the user name is not a DN => we need to fetch the DN of the entry
466 * using filters defined in the "mappings" array @user */
467 guint i;
468 const gchar *ptr;
469 GString *rname;
470 rname = g_string_new ("");
471 for (ptr = user; *ptr; ptr++) {
472 if ((*ptr == ',') || (*ptr == '\\') || (*ptr == '#') ||
473 (*ptr == '+') || (*ptr == '<') ||
474 (*ptr == '>') || (*ptr == ';') || (*ptr == '"') ||
475 (*ptr == '=') || (*ptr == '*'))
476 g_string_append_c (rname, '\\');
477 g_string_append_c (rname, *ptr);
478 }
479 for (i = 0; i < sizeof (mappings) / sizeof (LdapAuthMapping); i++) {
480 gchar *tmp;
481 tmp = fetch_user_dn (url, base_dn, rname->str, &(mappings[i]));
482 if (tmp) {
483 dnuser = tmp;
484 break;
485 }
486 }
487 g_string_free (rname, TRUE);
488
489 /* if no DN user has been found, then still use the provided name AS IS
490 * => dnuser can be %NULL here */
491 }
492
493 res = ldap_initialize (&ld, url);
494 if (res != LDAP_SUCCESS) {
495 gda_connection_add_event_string (cnc, ldap_err2string (res));
496 g_free (url);
497 g_free (dnuser);
498 return FALSE;
499 }
500
501 cdata = g_new0 (LdapConnectionData, 1);
502 cdata->keep_bound_count = 0;
503 cdata->handle = ld;
504 cdata->url = url;
505 cdata->time_limit = 0;
506 cdata->size_limit = 0;
507 cdata->base_dn = g_strdup (base_dn);
508 if (use_cache)
509 cdata->attributes_cache_file = compute_data_file_name (params, TRUE, "attrs");
510
511 /* set protocol version to 3 by default */
512 int version = LDAP_VERSION3;
513 res = ldap_set_option (cdata->handle, LDAP_OPT_PROTOCOL_VERSION, &version);
514 if (res != LDAP_SUCCESS) {
515 if (res == LDAP_PROTOCOL_ERROR) {
516 version = LDAP_VERSION2;
517 res = ldap_set_option (cdata->handle, LDAP_OPT_PROTOCOL_VERSION, &version);
518 }
519 if (res != LDAP_SUCCESS) {
520 gda_connection_add_event_string (cnc, ldap_err2string (res));
521 gda_ldap_free_cnc_data (cdata);
522 g_free (dnuser);
523 return FALSE;
524 }
525 }
526
527 /* time limit */
528 if (time_limit && *time_limit) {
529 int limit = atoi (time_limit);
530 res = ldap_set_option (cdata->handle, LDAP_OPT_TIMELIMIT, &limit);
531 if (res != LDAP_SUCCESS) {
532 gda_connection_add_event_string (cnc, ldap_err2string (res));
533 gda_ldap_free_cnc_data (cdata);
534 g_free (dnuser);
535 return FALSE;
536 }
537 cdata->time_limit = limit;
538 }
539
540 /* size limit */
541 if (size_limit && *size_limit) {
542 int limit = atoi (size_limit);
543 res = ldap_set_option (cdata->handle, LDAP_OPT_SIZELIMIT, &limit);
544 if (res != LDAP_SUCCESS) {
545 gda_connection_add_event_string (cnc, ldap_err2string (res));
546 gda_ldap_free_cnc_data (cdata);
547 g_free (dnuser);
548 return FALSE;
549 }
550 cdata->size_limit = limit;
551 }
552
553 /* authentication */
554 struct berval cred;
555 memset (&cred, 0, sizeof (cred));
556 cred.bv_len = pwd && *pwd ? strlen (pwd) : 0;
557 cred.bv_val = pwd && *pwd ? (char *) pwd : NULL;
558 res = ldap_sasl_bind_s (ld, dnuser ? dnuser : user, NULL, &cred, NULL, NULL, NULL);
559 if (res != LDAP_SUCCESS) {
560 gda_connection_add_event_string (cnc, ldap_err2string (res));
561 gda_ldap_free_cnc_data (cdata);
562 g_free (dnuser);
563 return FALSE;
564 }
565 if (pwd) {
566 gchar *tmp;
567 tmp = g_strdup_printf ("PASSWORD=%s", pwd);
568 cdata->auth = gda_quark_list_new_from_string (tmp);
569 g_free (tmp);
570 }
571 if (dnuser) {
572 gchar *tmp;
573 tmp = g_strdup_printf ("USERNAME=%s", dnuser);
574 if (cdata->auth)
575 gda_quark_list_add_from_string (cdata->auth, tmp, FALSE);
576 else
577 cdata->auth = gda_quark_list_new_from_string (tmp);
578 g_free (tmp);
579 dnuser = NULL;
580 }
581 else if (user) {
582 gchar *tmp;
583 tmp = g_strdup_printf ("USERNAME=%s", user);
584 if (cdata->auth)
585 gda_quark_list_add_from_string (cdata->auth, tmp, FALSE);
586 else
587 cdata->auth = gda_quark_list_new_from_string (tmp);
588 g_free (tmp);
589 }
590
591 /* set startup file name */
592 gchar *fname;
593 fname = compute_data_file_name (params, FALSE, "start");
594 g_object_set ((GObject*) cnc, "startup-file", fname, NULL);
595 g_free (fname);
596
597 /* open virtual connection */
598 g_object_set_data ((GObject*) cnc, "__gda_connection_LDAP", (gpointer) 0x01);
599 gda_virtual_connection_internal_set_provider_data (GDA_VIRTUAL_CONNECTION (cnc),
600 cdata, (GDestroyNotify) gda_ldap_free_cnc_data);
601 if (! GDA_SERVER_PROVIDER_CLASS (parent_class)->open_connection (GDA_SERVER_PROVIDER (provider), cnc, params,
602 NULL, NULL, NULL, NULL)) {
603 gda_virtual_connection_internal_set_provider_data (GDA_VIRTUAL_CONNECTION (cnc), NULL, NULL);
604 gda_connection_add_event_string (cnc, _("Can't open virtual connection"));
605 gda_ldap_free_cnc_data (cdata);
606 return FALSE;
607 }
608
609 gda_ldap_may_unbind (cdata);
610 return TRUE;
611 }
612
613 /*
614 * Unbinds the connection if possible (i.e. if cdata->keep_bound_count is 0)
615 * This allows to avoid keeping the connection to the LDAP server if unused
616 */
617 void
gda_ldap_may_unbind(LdapConnectionData * cdata)618 gda_ldap_may_unbind (LdapConnectionData *cdata)
619 {
620 if (!cdata || (cdata->keep_bound_count > 0))
621 return;
622 if (cdata->handle) {
623 ldap_unbind_ext (cdata->handle, NULL, NULL);
624 cdata->handle = NULL;
625 }
626 }
627
628 /*
629 * Makes sure the connection is opened
630 */
631 gboolean
gda_ldap_ensure_bound(LdapConnectionData * cdata,GError ** error)632 gda_ldap_ensure_bound (LdapConnectionData *cdata, GError **error)
633 {
634 if (!cdata)
635 return FALSE;
636 else if (cdata->handle)
637 return TRUE;
638
639 return gda_ldap_rebind (cdata, error);
640 }
641
642 /*
643 * Reopens a connection after the server has closed it (possibly because of a timeout)
644 *
645 * If it fails, then @cdata is left unchanged, otherwise it is modified to be useable again.
646 */
647 gboolean
gda_ldap_rebind(LdapConnectionData * cdata,GError ** error)648 gda_ldap_rebind (LdapConnectionData *cdata, GError **error)
649 {
650 if (!cdata)
651 return FALSE;
652
653 /*g_print ("Trying to reconnect...\n");*/
654 LDAP *ld;
655 int res;
656 res = ldap_initialize (&ld, cdata->url);
657 if (res != LDAP_SUCCESS) {
658 g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_OPEN_ERROR,
659 "%s", ldap_err2string (res));
660 return FALSE;
661 }
662
663 /* set protocol version to 3 by default */
664 int version = LDAP_VERSION3;
665 res = ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION, &version);
666 if (res != LDAP_SUCCESS) {
667 if (res == LDAP_PROTOCOL_ERROR) {
668 version = LDAP_VERSION2;
669 res = ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION, &version);
670 }
671 if (res != LDAP_SUCCESS) {
672 g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_OPEN_ERROR,
673 "%s", ldap_err2string (res));
674 ldap_unbind_ext (ld, NULL, NULL);
675 return FALSE;
676 }
677 }
678
679 /* authentication */
680 struct berval cred;
681 const gchar *pwd = "";
682 const gchar *user = "";
683 if (cdata->auth)
684 pwd = gda_quark_list_find (cdata->auth, "PASSWORD");
685 memset (&cred, 0, sizeof (cred));
686 cred.bv_len = pwd && *pwd ? strlen (pwd) : 0;
687 cred.bv_val = pwd && *pwd ? (char *) pwd : NULL;
688
689 if (cdata->auth)
690 user = gda_quark_list_find (cdata->auth, "USERNAME");
691 res = ldap_sasl_bind_s (ld, user, NULL, &cred, NULL, NULL, NULL);
692 if (cdata->auth)
693 gda_quark_list_protect_values (cdata->auth);
694
695 if (res != LDAP_SUCCESS) {
696 g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_OPEN_ERROR,
697 "%s", ldap_err2string (res));
698 ldap_unbind_ext (ld, NULL, NULL);
699 return FALSE;
700 }
701
702 /* time limit */
703 int limit = cdata->time_limit;
704 res = ldap_set_option (cdata->handle, LDAP_OPT_TIMELIMIT, &limit);
705 if (res != LDAP_SUCCESS) {
706 g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_OPEN_ERROR,
707 "%s", ldap_err2string (res));
708 ldap_unbind_ext (ld, NULL, NULL);
709 return FALSE;
710 }
711
712 /* size limit */
713 limit = cdata->size_limit;
714 res = ldap_set_option (cdata->handle, LDAP_OPT_SIZELIMIT, &limit);
715 if (res != LDAP_SUCCESS) {
716 g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_OPEN_ERROR,
717 "%s", ldap_err2string (res));
718 ldap_unbind_ext (ld, NULL, NULL);
719 return FALSE;
720 }
721
722 /* all ok */
723 if (cdata->handle) {
724 /* don't call ldap_unbind_ext() as it often crashed the application */
725 /*ldap_unbind_ext (cdata->handle, NULL, NULL);*/
726 }
727 cdata->handle = ld;
728
729 /*g_print ("Reconnected!\n");*/
730 return TRUE;
731 }
732
733 /*
734 * Server version request
735 */
736 static const gchar *
gda_ldap_provider_get_server_version(GdaServerProvider * provider,GdaConnection * cnc)737 gda_ldap_provider_get_server_version (GdaServerProvider *provider, GdaConnection *cnc)
738 {
739 LdapConnectionData *cdata;
740
741 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
742 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
743
744 cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data (GDA_VIRTUAL_CONNECTION (cnc));
745 if (!cdata)
746 return FALSE;
747
748 if (! cdata->server_version) {
749 /* FIXME: don't know how to get information about the LDAP server! */
750 }
751 return cdata->server_version;
752 }
753
754 /*
755 * Get database request
756 */
757 static const gchar *
gda_ldap_provider_get_database(GdaServerProvider * provider,GdaConnection * cnc)758 gda_ldap_provider_get_database (GdaServerProvider *provider, GdaConnection *cnc)
759 {
760 LdapConnectionData *cdata;
761
762 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
763 g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
764
765 cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data (GDA_VIRTUAL_CONNECTION (cnc));
766 if (!cdata)
767 return NULL;
768 return cdata->base_dn;
769 }
770
771 /*
772 * Extra SQL
773 */
774 typedef struct {
775 gchar *table_name;
776 gboolean other_args; /* set to %TRUE if any of the arguments below have been specified */
777 gchar *base_dn;
778 gchar *filter;
779 gchar *attributes;
780 GdaLdapSearchScope scope;
781 } ExtraSqlCommand;
782 static void extra_sql_command_free (ExtraSqlCommand *cmde);
783
784 #define NOT_AN_EXTRA_SQL_COMMAND (ExtraSqlCommand*) 0x01
785 #define SKIP_SPACES(x) for (; *(x) && (g_ascii_isspace (*(x)) || (*(x)=='\n')); (x)++)
786 static ExtraSqlCommand *parse_extra_sql_command (gchar *cmd, const gchar *cmde_name,
787 GError **error);
788 static GdaDataModel *table_parameters_describe (const gchar *base_dn, const gchar *filter,
789 const gchar *attributes,
790 GdaLdapSearchScope scope);
791 static GObject *
gda_ldap_provider_statement_execute(GdaServerProvider * provider,GdaConnection * cnc,GdaStatement * stmt,GdaSet * params,GdaStatementModelUsage model_usage,GType * col_types,GdaSet ** last_inserted_row,guint * task_id,GdaServerProviderExecCallback async_cb,gpointer cb_data,GError ** error)792 gda_ldap_provider_statement_execute (GdaServerProvider *provider, GdaConnection *cnc,
793 GdaStatement *stmt, GdaSet *params,
794 GdaStatementModelUsage model_usage,
795 GType *col_types, GdaSet **last_inserted_row,
796 guint *task_id, GdaServerProviderExecCallback async_cb,
797 gpointer cb_data, GError **error)
798 {
799 if (async_cb) {
800 g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
801 "%s", _("Provider does not support asynchronous statement execution"));
802 return NULL;
803 }
804 gchar *sql;
805 sql = gda_statement_to_sql (stmt, params, NULL);
806 if (sql) {
807 /* parse SQL:
808 * CREATE LDAP TABLE <table name> WITH BASE='base_dn' FILTER='filter'
809 * ATTRIBUTES='attributes' SCOPE='scope'
810 */
811 gchar *ssql = sql;
812 SKIP_SPACES (ssql);
813 if (! g_ascii_strncasecmp (ssql, "CREATE", 6)) {
814 ExtraSqlCommand *cmde;
815 GError *lerror = NULL;
816 GObject *retval = NULL;
817 cmde = parse_extra_sql_command (ssql, "CREATE", &lerror);
818 if (cmde != NOT_AN_EXTRA_SQL_COMMAND) {
819 GdaConnectionEvent *event = NULL;
820 if (cmde) {
821 if (gda_ldap_connection_declare_table (GDA_LDAP_CONNECTION (cnc),
822 cmde->table_name, cmde->base_dn,
823 cmde->filter, cmde->attributes,
824 cmde->scope, &lerror))
825 retval = (GObject*) gda_set_new (NULL);
826 else {
827 event = gda_connection_point_available_event (cnc,
828 GDA_CONNECTION_EVENT_ERROR);
829 gda_connection_event_set_description (event, lerror && lerror->message ?
830 lerror->message : _("No detail"));
831 gda_connection_add_event (cnc, event);
832 g_propagate_error (error, lerror);
833 }
834 extra_sql_command_free (cmde);
835 }
836 else {
837 event = gda_connection_point_available_event (cnc,
838 GDA_CONNECTION_EVENT_ERROR);
839 gda_connection_event_set_description (event, lerror && lerror->message ?
840 lerror->message : _("No detail"));
841 gda_connection_add_event (cnc, event);
842 g_propagate_error (error, lerror);
843 }
844
845 gda_connection_internal_statement_executed (cnc, stmt, params, event);
846 g_free (sql);
847 return retval;
848 }
849 }
850
851 /* parse SQL:
852 * DROP LDAP TABLE <table name>
853 */
854 else if (! g_ascii_strncasecmp (ssql, "DROP", 4)) {
855 ExtraSqlCommand *cmde;
856 GError *lerror = NULL;
857 GObject *retval = NULL;
858 cmde = parse_extra_sql_command (ssql, "DROP", &lerror);
859 if (cmde != NOT_AN_EXTRA_SQL_COMMAND) {
860 GdaConnectionEvent *event = NULL;
861 if (cmde) {
862 if (cmde->other_args) {
863 g_set_error (&lerror, GDA_SQL_PARSER_ERROR,
864 GDA_SQL_PARSER_SYNTAX_ERROR,
865 "%s",
866 _("Too many arguments"));
867 event = gda_connection_point_available_event (cnc,
868 GDA_CONNECTION_EVENT_ERROR);
869 gda_connection_event_set_description (event,
870 lerror->message);
871 gda_connection_add_event (cnc, event);
872 g_propagate_error (error, lerror);
873 }
874 else {
875 if (gda_ldap_connection_undeclare_table (GDA_LDAP_CONNECTION (cnc),
876 cmde->table_name, &lerror))
877 retval = (GObject*) gda_set_new (NULL);
878 else {
879 event = gda_connection_point_available_event (cnc,
880 GDA_CONNECTION_EVENT_ERROR);
881 gda_connection_event_set_description (event, lerror && lerror->message ?
882 lerror->message : _("No detail"));
883 gda_connection_add_event (cnc, event);
884 g_propagate_error (error, lerror);
885 }
886 }
887 extra_sql_command_free (cmde);
888 }
889 else {
890 event = gda_connection_point_available_event (cnc,
891 GDA_CONNECTION_EVENT_ERROR);
892 gda_connection_event_set_description (event, lerror && lerror->message ?
893 lerror->message : _("No detail"));
894 gda_connection_add_event (cnc, event);
895 g_propagate_error (error, lerror);
896 }
897 gda_connection_internal_statement_executed (cnc, stmt, params, event);
898 g_free (sql);
899 return retval;
900 }
901 }
902 /* parse SQL:
903 * ALTER LDAP TABLE <table name> [...]
904 * DESCRIBE LDAP TABLE <table name>
905 */
906 else if (! g_ascii_strncasecmp (ssql, "ALTER", 5) ||
907 ! g_ascii_strncasecmp (ssql, "DESCRIBE", 8)) {
908 ExtraSqlCommand *cmde;
909 GError *lerror = NULL;
910 GObject *retval = NULL;
911 gboolean alter;
912
913 alter = g_ascii_strncasecmp (ssql, "ALTER", 5) ? FALSE : TRUE;
914
915 cmde = parse_extra_sql_command (ssql, alter ? "ALTER" : "DESCRIBE", &lerror);
916 if ((cmde != NOT_AN_EXTRA_SQL_COMMAND) &&
917 (alter || (!alter && !cmde->other_args))) {
918 GdaConnectionEvent *event = NULL;
919 if (cmde) {
920 const gchar *base_dn, *filter, *attributes;
921 GdaLdapSearchScope scope;
922 if (gda_ldap_connection_describe_table (GDA_LDAP_CONNECTION (cnc),
923 cmde->table_name,
924 &base_dn, &filter,
925 &attributes, &scope, &lerror)) {
926 if (cmde->other_args) {
927 if (! cmde->base_dn && base_dn)
928 cmde->base_dn = g_strdup (base_dn);
929 if (! cmde->filter && filter)
930 cmde->filter = g_strdup (filter);
931 if (! cmde->attributes && attributes)
932 cmde->attributes = g_strdup (attributes);
933 if (! cmde->scope)
934 cmde->scope = scope;
935 if (gda_ldap_connection_undeclare_table (GDA_LDAP_CONNECTION (cnc),
936 cmde->table_name, &lerror) &&
937 gda_ldap_connection_declare_table (GDA_LDAP_CONNECTION (cnc),
938 cmde->table_name, cmde->base_dn,
939 cmde->filter, cmde->attributes,
940 cmde->scope, &lerror))
941 retval = (GObject*) gda_set_new (NULL);
942 }
943 else {
944 GdaDataModel *array;
945 array = table_parameters_describe (base_dn, filter,
946 attributes, scope);
947 retval = (GObject*) array;
948 }
949 }
950 if (!retval) {
951 event = gda_connection_point_available_event (cnc,
952 GDA_CONNECTION_EVENT_ERROR);
953 gda_connection_event_set_description (event, lerror && lerror->message ?
954 lerror->message : _("No detail"));
955 gda_connection_add_event (cnc, event);
956 g_propagate_error (error, lerror);
957 }
958 extra_sql_command_free (cmde);
959 }
960 gda_connection_internal_statement_executed (cnc, stmt, params, event);
961 g_free (sql);
962 return retval;
963 }
964 }
965 g_free (sql);
966 }
967 return GDA_SERVER_PROVIDER_CLASS (parent_class)->statement_execute (provider, cnc, stmt, params,
968 model_usage, col_types,
969 last_inserted_row, task_id,
970 async_cb, cb_data, error);
971 }
972
973 /*
974 * Free connection's specific data
975 */
976 static void
gda_ldap_free_cnc_data(LdapConnectionData * cdata)977 gda_ldap_free_cnc_data (LdapConnectionData *cdata)
978 {
979 if (cdata->handle)
980 ldap_unbind_ext (cdata->handle, NULL, NULL);
981 if (cdata->attributes_hash)
982 g_hash_table_destroy (cdata->attributes_hash);
983 g_free (cdata->attributes_cache_file);
984 g_free (cdata->base_dn);
985 g_free (cdata->server_version);
986 g_free (cdata->url);
987 if (cdata->auth)
988 gda_quark_list_free (cdata->auth);
989 g_free (cdata);
990 }
991
992 static const gchar *
scope_to_string(GdaLdapSearchScope scope)993 scope_to_string (GdaLdapSearchScope scope)
994 {
995 switch (scope) {
996 case GDA_LDAP_SEARCH_BASE:
997 return "BASE";
998 case GDA_LDAP_SEARCH_ONELEVEL:
999 return "ONELEVEL";
1000 case GDA_LDAP_SEARCH_SUBTREE:
1001 return "SUBTREE";
1002 default:
1003 return _("Unknown");
1004 }
1005 }
1006
1007 static GdaDataModel *
table_parameters_describe(const gchar * base_dn,const gchar * filter,const gchar * attributes,GdaLdapSearchScope scope)1008 table_parameters_describe (const gchar *base_dn, const gchar *filter, const gchar *attributes,
1009 GdaLdapSearchScope scope)
1010 {
1011 GdaDataModel *array;
1012 GValue *v1, *v2;
1013 GList *list;
1014 array = gda_data_model_array_new_with_g_types (2, G_TYPE_STRING,
1015 G_TYPE_STRING);
1016 gda_data_model_set_column_title (array, 0, _("Parameter"));
1017 gda_data_model_set_column_title (array, 1, _("Value"));
1018 g_value_set_string ((v1 = gda_value_new (G_TYPE_STRING)), "BASE");
1019 g_value_set_string ((v2 = gda_value_new (G_TYPE_STRING)), base_dn);
1020 list = g_list_append (NULL, v1);
1021 list = g_list_append (list, v2);
1022 gda_data_model_append_values (array, list, NULL);
1023 g_list_free (list);
1024 gda_value_free (v1);
1025 gda_value_free (v2);
1026
1027 g_value_set_string ((v1 = gda_value_new (G_TYPE_STRING)), "FILTER");
1028 g_value_set_string ((v2 = gda_value_new (G_TYPE_STRING)), filter);
1029 list = g_list_append (NULL, v1);
1030 list = g_list_append (list, v2);
1031 gda_data_model_append_values (array, list, NULL);
1032 g_list_free (list);
1033 gda_value_free (v1);
1034 gda_value_free (v2);
1035
1036 g_value_set_string ((v1 = gda_value_new (G_TYPE_STRING)), "ATTRIBUTES");
1037 g_value_set_string ((v2 = gda_value_new (G_TYPE_STRING)), attributes);
1038 list = g_list_append (NULL, v1);
1039 list = g_list_append (list, v2);
1040 gda_data_model_append_values (array, list, NULL);
1041 g_list_free (list);
1042 gda_value_free (v1);
1043 gda_value_free (v2);
1044
1045 g_value_set_string ((v1 = gda_value_new (G_TYPE_STRING)), "SCOPE");
1046 g_value_set_string ((v2 = gda_value_new (G_TYPE_STRING)), scope_to_string (scope));
1047 list = g_list_append (NULL, v1);
1048 list = g_list_append (list, v2);
1049 gda_data_model_append_values (array, list, NULL);
1050 g_list_free (list);
1051 gda_value_free (v1);
1052 gda_value_free (v2);
1053 return array;
1054 }
1055
1056 /*
1057 * Extra commands parsing
1058 */
1059 /*
1060 * consumes @str for a singly quoted string
1061 * Returns: a pointer to the next non analysed char
1062 */
1063 static gchar *
parse_string(gchar * str,gchar ** out_part)1064 parse_string (gchar *str, gchar **out_part)
1065 {
1066 gchar *ptr = str;
1067 *out_part = NULL;
1068
1069 SKIP_SPACES (ptr);
1070 if (!*ptr)
1071 return NULL;
1072 if (*ptr != '\'') {
1073 if (!g_ascii_strncasecmp (ptr, "null", 4)) {
1074 ptr += 4;
1075 return ptr;
1076 }
1077 else
1078 return NULL;
1079 }
1080 ptr++;
1081 *out_part = ptr;
1082 for (; *ptr && (*ptr != '\''); ptr++);
1083 if (!*ptr)
1084 return NULL;
1085 *ptr = 0;
1086 ptr++;
1087 return ptr;
1088 }
1089
1090 /*
1091 * consumes @str for an identifier
1092 * Returns: a pointer to the next non analysed char
1093 */
1094 static gchar *
parse_ident(gchar * str,gchar ** out_part)1095 parse_ident (gchar *str, gchar **out_part)
1096 {
1097 gchar *ptr = str;
1098 *out_part = NULL;
1099
1100 SKIP_SPACES (ptr);
1101 *out_part = ptr;
1102 for (; *ptr && (g_ascii_isalnum (*ptr) || (*ptr == '_')) ; ptr++);
1103 if (ptr == *out_part) {
1104 *out_part = NULL;
1105 return NULL;
1106 }
1107 return ptr;
1108 }
1109
1110 static void
extra_sql_command_free(ExtraSqlCommand * cmde)1111 extra_sql_command_free (ExtraSqlCommand *cmde)
1112 {
1113 g_free (cmde->table_name);
1114 g_free (cmde->base_dn);
1115 g_free (cmde->filter);
1116 g_free (cmde->attributes);
1117 g_free (cmde);
1118 }
1119
1120 /*
1121 * CREATE LDAP TABLE <table name> BASE='base_dn' FILTER='filter' ATTRIBUTES='attributes' SCOPE='scope'
1122 * DROP LDAP TABLE <table name>
1123 * ALTER LDAP TABLE <table name>
1124 * ALTER LDAP TABLE <table name> BASE='base_dn' FILTER='filter' ATTRIBUTES='attributes' SCOPE='scope'
1125 *
1126 * Returns: a #ExtraSqlCommand pointer, or %NULL, or NOT_AN_EXTRA_SQL_COMMAND (if not "CREATE LDAP...")
1127 */
1128 static ExtraSqlCommand *
parse_extra_sql_command(gchar * cmd,const gchar * cmde_name,GError ** error)1129 parse_extra_sql_command (gchar *cmd, const gchar *cmde_name, GError **error)
1130 {
1131 ExtraSqlCommand *args;
1132 gchar *ptr, *errptr, *part, *tmp;
1133 args = g_new0 (ExtraSqlCommand, 1);
1134 args->other_args = FALSE;
1135
1136 ptr = cmd + strlen (cmde_name);
1137
1138 /* make sure about complete command */
1139 errptr = ptr;
1140 if (! (ptr = parse_ident (ptr, &part)))
1141 return NOT_AN_EXTRA_SQL_COMMAND;
1142 if (!part || g_ascii_strncasecmp (part, "ldap", 4))
1143 return NOT_AN_EXTRA_SQL_COMMAND;
1144
1145 errptr = ptr;
1146 if (! (ptr = parse_ident (ptr, &part)))
1147 goto onerror;
1148 if (!part || g_ascii_strncasecmp (part, "table", 5))
1149 goto onerror;
1150
1151 /* table name */
1152 SKIP_SPACES (ptr);
1153 errptr = ptr;
1154 if (! (ptr = parse_ident (ptr, &part)))
1155 goto onerror;
1156 tmp = g_strndup (part, ptr-part);
1157 args->table_name = g_ascii_strdown (tmp, -1);
1158 g_free (tmp);
1159
1160 /* key=value arguments */
1161 while (TRUE) {
1162 errptr = ptr;
1163 SKIP_SPACES (ptr);
1164 if (! (ptr = parse_ident (ptr, &part))) {
1165 ptr = errptr;
1166 break;
1167 }
1168 if (part) {
1169 gchar **where = NULL;
1170 if (!g_ascii_strncasecmp (part, "base", 4))
1171 where = &(args->base_dn);
1172 else if (!g_ascii_strncasecmp (part, "filter", 6))
1173 where = &(args->filter);
1174 else if (!g_ascii_strncasecmp (part, "attributes", 10))
1175 where = &(args->attributes);
1176 else if (!g_ascii_strncasecmp (part, "scope", 5))
1177 where = NULL;
1178 else
1179 goto onerror;
1180
1181 /* = */
1182 errptr = ptr;
1183 SKIP_SPACES (ptr);
1184 if (*ptr != '=')
1185 goto onerror;
1186 ptr++;
1187
1188 /* value */
1189 errptr = ptr;
1190 SKIP_SPACES (ptr);
1191 if (! (ptr = parse_string (ptr, &part)))
1192 goto onerror;
1193 if (part) {
1194 if (where)
1195 *where = g_strdup (part);
1196 else {
1197 if (!g_ascii_strcasecmp (part, "base"))
1198 args->scope = GDA_LDAP_SEARCH_BASE;
1199 else if (!g_ascii_strcasecmp (part, "onelevel"))
1200 args->scope = GDA_LDAP_SEARCH_ONELEVEL;
1201 else if (!g_ascii_strcasecmp (part, "subtree"))
1202 args->scope = GDA_LDAP_SEARCH_SUBTREE;
1203 else
1204 goto onerror;
1205 }
1206 args->other_args = TRUE;
1207 }
1208 else
1209 goto onerror;
1210 }
1211 else
1212 break;
1213 }
1214
1215 /* end */
1216 SKIP_SPACES (ptr);
1217 if (*ptr && (*ptr != ';'))
1218 goto onerror;
1219 #ifdef GDA_DEBUG_NO
1220 g_print ("TABLE=>%s, BASE=>%s, FILTER=>%s, ATTRIBUTES=>%s, SCOPE=>%d\n", args->table_name,
1221 args->base_dn, args->filter,
1222 args->attributes, args->scope);
1223 #endif
1224
1225 return args;
1226
1227 onerror:
1228 SKIP_SPACES (errptr);
1229 g_set_error (error, GDA_SQL_PARSER_ERROR, GDA_SQL_PARSER_SYNTAX_ERROR,
1230 _("near \"%s\": syntax error"), errptr);
1231 extra_sql_command_free (args);
1232 return NULL;
1233 }
1234