1 /*	$NetBSD: config.c,v 1.1.1.3 2010/12/12 15:23:24 adam Exp $	*/
2 
3 /* OpenLDAP: pkg/ldap/servers/slapd/back-sql/config.c,v 1.32.2.8 2010/04/13 20:23:42 kurt Exp */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1999-2010 The OpenLDAP Foundation.
7  * Portions Copyright 1999 Dmitry Kovalev.
8  * Portions Copyright 2002 Pierangelo Masarati.
9  * Portions Copyright 2004 Mark Adamson.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted only as authorized by the OpenLDAP
14  * Public License.
15  *
16  * A copy of this license is available in the file LICENSE in the
17  * top-level directory of the distribution or, alternatively, at
18  * <http://www.OpenLDAP.org/license.html>.
19  */
20 /* ACKNOWLEDGEMENTS:
21  * This work was initially developed by Dmitry Kovalev for inclusion
22  * by OpenLDAP Software.  Additional significant contributors include
23  * Pierangelo Masarati.
24  */
25 
26 #include "portable.h"
27 
28 #include <stdio.h>
29 #include "ac/string.h"
30 #include <sys/types.h>
31 
32 #include "slap.h"
33 #include "ldif.h"
34 #include "proto-sql.h"
35 
36 static int
37 create_baseObject(
38 	BackendDB	*be,
39 	const char	*fname,
40 	int		lineno );
41 
42 static int
43 read_baseObject(
44 	BackendDB	*be,
45 	const char	*fname );
46 
47 int
48 backsql_db_config(
49 	BackendDB	*be,
50 	const char	*fname,
51 	int		lineno,
52 	int		argc,
53 	char		**argv )
54 {
55 	backsql_info 	*bi = (backsql_info *)be->be_private;
56 
57 	Debug( LDAP_DEBUG_TRACE, "==>backsql_db_config()\n", 0, 0, 0 );
58 	assert( bi != NULL );
59 
60 	if ( !strcasecmp( argv[ 0 ], "dbhost" ) ) {
61 		if ( argc < 2 ) {
62 			Debug( LDAP_DEBUG_TRACE,
63 				"<==backsql_db_config (%s line %d): "
64 				"missing hostname in \"dbhost\" directive\n",
65 				fname, lineno, 0 );
66 			return 1;
67 	    	}
68 		bi->sql_dbhost = ch_strdup( argv[ 1 ] );
69 		Debug( LDAP_DEBUG_TRACE,
70 			"<==backsql_db_config(): hostname=%s\n",
71 			bi->sql_dbhost, 0, 0 );
72 
73 	} else if ( !strcasecmp( argv[ 0 ], "dbuser" ) ) {
74 		if ( argc < 2 ) {
75 			Debug( LDAP_DEBUG_TRACE,
76 				"<==backsql_db_config (%s line %d): "
77 				"missing username in \"dbuser\" directive\n",
78 				fname, lineno, 0 );
79 			return 1;
80 		}
81 		bi->sql_dbuser = ch_strdup( argv[ 1 ] );
82 		Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): dbuser=%s\n",
83 			bi->sql_dbuser, 0, 0 );
84 
85 	} else if ( !strcasecmp( argv[ 0 ], "dbpasswd" ) ) {
86 		if ( argc < 2 ) {
87 			Debug( LDAP_DEBUG_TRACE,
88 				"<==backsql_db_config (%s line %d): "
89 				"missing password in \"dbpasswd\" directive\n",
90 				fname, lineno, 0 );
91 			return 1;
92 		}
93 		bi->sql_dbpasswd = ch_strdup( argv[ 1 ] );
94 		Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
95 			"dbpasswd=%s\n", /* bi->sql_dbpasswd */ "xxxx", 0, 0 );
96 
97 	} else if ( !strcasecmp( argv[ 0 ], "dbname" ) ) {
98 		if ( argc < 2 ) {
99 			Debug( LDAP_DEBUG_TRACE,
100 				"<==backsql_db_config (%s line %d): "
101 				"missing database name in \"dbname\" "
102 				"directive\n", fname, lineno, 0 );
103 			return 1;
104 		}
105 		bi->sql_dbname = ch_strdup( argv[ 1 ] );
106 		Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): dbname=%s\n",
107 			bi->sql_dbname, 0, 0 );
108 
109 	} else if ( !strcasecmp( argv[ 0 ], "concat_pattern" ) ) {
110 		if ( argc < 2 ) {
111 			Debug( LDAP_DEBUG_TRACE,
112 				"<==backsql_db_config (%s line %d): "
113 				"missing pattern"
114 				"in \"concat_pattern\" directive\n",
115 				fname, lineno, 0 );
116 			return 1;
117 		}
118 		if ( backsql_split_pattern( argv[ 1 ], &bi->sql_concat_func, 2 ) ) {
119 			Debug( LDAP_DEBUG_TRACE,
120 				"<==backsql_db_config (%s line %d): "
121 				"unable to parse pattern \"%s\"\n"
122 				"in \"concat_pattern\" directive\n",
123 				fname, lineno, argv[ 1 ] );
124 			return 1;
125 		}
126 		Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
127 			"concat_pattern=\"%s\"\n", argv[ 1 ], 0, 0 );
128 
129 	} else if ( !strcasecmp( argv[ 0 ], "subtree_cond" ) ) {
130 		if ( argc < 2 ) {
131 			Debug( LDAP_DEBUG_TRACE,
132 				"<==backsql_db_config (%s line %d): "
133 				"missing SQL condition "
134 				"in \"subtree_cond\" directive\n",
135 				fname, lineno, 0 );
136 			return 1;
137 		}
138 		ber_str2bv( argv[ 1 ], 0, 1, &bi->sql_subtree_cond );
139 		Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
140 			"subtree_cond=%s\n", bi->sql_subtree_cond.bv_val, 0, 0 );
141 
142 	} else if ( !strcasecmp( argv[ 0 ], "children_cond" ) ) {
143 		if ( argc < 2 ) {
144 			Debug( LDAP_DEBUG_TRACE,
145 				"<==backsql_db_config (%s line %d): "
146 				"missing SQL condition "
147 				"in \"children_cond\" directive\n",
148 				fname, lineno, 0 );
149 			return 1;
150 		}
151 		ber_str2bv( argv[ 1 ], 0, 1, &bi->sql_children_cond );
152 		Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
153 			"children_cond=%s\n", bi->sql_children_cond.bv_val, 0, 0 );
154 
155 	} else if ( !strcasecmp( argv[ 0 ], "dn_match_cond" ) ) {
156 		if ( argc < 2 ) {
157 			Debug( LDAP_DEBUG_TRACE,
158 				"<==backsql_db_config (%s line %d): "
159 				"missing SQL condition "
160 				"in \"dn_match_cond\" directive\n",
161 				fname, lineno, 0 );
162 			return 1;
163 		}
164 		ber_str2bv( argv[ 1 ], 0, 1, &bi->sql_dn_match_cond );
165 		Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
166 			"children_cond=%s\n", bi->sql_dn_match_cond.bv_val, 0, 0 );
167 
168 	} else if ( !strcasecmp( argv[ 0 ], "oc_query" ) ) {
169 		if ( argc < 2 ) {
170 			Debug( LDAP_DEBUG_TRACE,
171 				"<==backsql_db_config (%s line %d): "
172 				"missing SQL statement "
173 				"in \"oc_query\" directive\n",
174 				fname, lineno, 0 );
175 			return 1;
176 		}
177 		bi->sql_oc_query = ch_strdup( argv[ 1 ] );
178 		Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
179 			"oc_query=%s\n", bi->sql_oc_query, 0, 0 );
180 
181 	} else if ( !strcasecmp( argv[ 0 ], "at_query" ) ) {
182 		if ( argc < 2 ) {
183 			Debug( LDAP_DEBUG_TRACE,
184 				"<==backsql_db_config (%s line %d): "
185 				"missing SQL statement "
186 				"in \"at_query\" directive\n",
187 				fname, lineno, 0 );
188 			return 1;
189 		}
190 		bi->sql_at_query = ch_strdup( argv[ 1 ] );
191 		Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
192 			"at_query=%s\n", bi->sql_at_query, 0, 0 );
193 
194 	} else if ( !strcasecmp( argv[ 0 ], "insentry_stmt" ) ||
195 			!strcasecmp( argv[ 0 ], "insentry_query" ) )
196 	{
197 		if ( argc < 2 ) {
198 			Debug( LDAP_DEBUG_TRACE,
199 				"<==backsql_db_config (%s line %d): "
200 				"missing SQL statement "
201 				"in \"insentry_stmt\" directive\n",
202 				fname, lineno, 0 );
203 			return 1;
204 		}
205 		bi->sql_insentry_stmt = ch_strdup( argv[ 1 ] );
206 		Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
207 			"insentry_stmt=%s\n", bi->sql_insentry_stmt, 0, 0 );
208 
209 	} else if ( !strcasecmp( argv[ 0 ], "create_needs_select" ) ) {
210 		if ( argc < 2 ) {
211 			Debug( LDAP_DEBUG_TRACE,
212 				"<==backsql_db_config (%s line %d): "
213 				"missing { yes | no }"
214 				"in \"create_needs_select\" directive\n",
215 				fname, lineno, 0 );
216 			return 1;
217 		}
218 
219 		if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
220 			bi->sql_flags |= BSQLF_CREATE_NEEDS_SELECT;
221 
222 		} else if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
223 			bi->sql_flags &= ~BSQLF_CREATE_NEEDS_SELECT;
224 
225 		} else {
226 			Debug( LDAP_DEBUG_TRACE,
227 				"<==backsql_db_config (%s line %d): "
228 				"\"create_needs_select\" directive arg "
229 				"must be \"yes\" or \"no\"\n",
230 				fname, lineno, 0 );
231 			return 1;
232 
233 		}
234 		Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
235 			"create_needs_select =%s\n",
236 			BACKSQL_CREATE_NEEDS_SELECT( bi ) ? "yes" : "no",
237 			0, 0 );
238 
239 	} else if ( !strcasecmp( argv[ 0 ], "upper_func" ) ) {
240 		if ( argc < 2 ) {
241 			Debug( LDAP_DEBUG_TRACE,
242 				"<==backsql_db_config (%s line %d): "
243 				"missing function name "
244 				"in \"upper_func\" directive\n",
245 				fname, lineno, 0 );
246 			return 1;
247 		}
248 		ber_str2bv( argv[ 1 ], 0, 1, &bi->sql_upper_func );
249 		Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
250 			"upper_func=%s\n", bi->sql_upper_func.bv_val, 0, 0 );
251 
252 	} else if ( !strcasecmp( argv[ 0 ], "upper_needs_cast" ) ) {
253 		if ( argc < 2 ) {
254 			Debug( LDAP_DEBUG_TRACE,
255 				"<==backsql_db_config (%s line %d): "
256 				"missing { yes | no }"
257 				"in \"upper_needs_cast\" directive\n",
258 				fname, lineno, 0 );
259 			return 1;
260 		}
261 
262 		if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
263 			bi->sql_flags |= BSQLF_UPPER_NEEDS_CAST;
264 
265 		} else if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
266 			bi->sql_flags &= ~BSQLF_UPPER_NEEDS_CAST;
267 
268 		} else {
269 			Debug( LDAP_DEBUG_TRACE,
270 				"<==backsql_db_config (%s line %d): "
271 				"\"upper_needs_cast\" directive arg "
272 				"must be \"yes\" or \"no\"\n",
273 				fname, lineno, 0 );
274 			return 1;
275 
276 		}
277 		Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
278 			"upper_needs_cast =%s\n",
279 			BACKSQL_UPPER_NEEDS_CAST( bi ) ? "yes" : "no", 0, 0 );
280 
281 	} else if ( !strcasecmp( argv[ 0 ], "strcast_func" ) ) {
282 		if ( argc < 2 ) {
283 			Debug( LDAP_DEBUG_TRACE,
284 				"<==backsql_db_config (%s line %d): "
285 				"missing function name "
286 				"in \"strcast_func\" directive\n",
287 				fname, lineno, 0 );
288 			return 1;
289 		}
290 		ber_str2bv( argv[ 1 ], 0, 1, &bi->sql_strcast_func );
291 		Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
292 			"strcast_func=%s\n", bi->sql_strcast_func.bv_val, 0, 0 );
293 
294 	} else if ( !strcasecmp( argv[ 0 ], "delentry_stmt" ) ||
295 			!strcasecmp( argv[ 0 ], "delentry_query" ) )
296 	{
297 		if ( argc < 2 ) {
298 			Debug( LDAP_DEBUG_TRACE,
299 				"<==backsql_db_config (%s line %d): "
300 				"missing SQL statement "
301 				"in \"delentry_stmt\" directive\n",
302 				fname, lineno, 0 );
303 			return 1;
304 		}
305 		bi->sql_delentry_stmt = ch_strdup( argv[ 1 ] );
306 		Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
307 			"delentry_stmt=%s\n", bi->sql_delentry_stmt, 0, 0 );
308 
309 	} else if ( !strcasecmp( argv[ 0 ], "renentry_stmt" ) ||
310 			!strcasecmp( argv[ 0 ], "renentry_query" ) )
311 	{
312 		if ( argc < 2 ) {
313 			Debug( LDAP_DEBUG_TRACE,
314 				"<==backsql_db_config (%s line %d): "
315 				"missing SQL statement "
316 				"in \"renentry_stmt\" directive\n",
317 				fname, lineno, 0 );
318 			return 1;
319 		}
320 		bi->sql_renentry_stmt = ch_strdup( argv[ 1 ] );
321 		Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
322 			"renentry_stmt=%s\n", bi->sql_renentry_stmt, 0, 0 );
323 
324 	} else if ( !strcasecmp( argv[ 0 ], "delobjclasses_stmt" ) ||
325 			!strcasecmp( argv[ 0 ], "delobjclasses_query" ) )
326 	{
327 		if ( argc < 2 ) {
328 			Debug( LDAP_DEBUG_TRACE,
329 				"<==backsql_db_config (%s line %d): "
330 				"missing SQL statement "
331 				"in \"delobjclasses_stmt\" directive\n",
332 				fname, lineno, 0 );
333 			return 1;
334 		}
335 		bi->sql_delobjclasses_stmt = ch_strdup( argv[ 1 ] );
336 		Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
337 			"delobjclasses_stmt=%s\n", bi->sql_delobjclasses_stmt, 0, 0 );
338 
339 	} else if ( !strcasecmp( argv[ 0 ], "has_ldapinfo_dn_ru" ) ) {
340 		if ( argc < 2 ) {
341 			Debug( LDAP_DEBUG_TRACE,
342 				"<==backsql_db_config (%s line %d): "
343 				"missing { yes | no }"
344 				"in \"has_ldapinfo_dn_ru\" directive\n",
345 				fname, lineno, 0 );
346 			return 1;
347 		}
348 
349 		if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
350 			bi->sql_flags |= BSQLF_HAS_LDAPINFO_DN_RU;
351 			bi->sql_flags |= BSQLF_DONTCHECK_LDAPINFO_DN_RU;
352 
353 		} else if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
354 			bi->sql_flags &= ~BSQLF_HAS_LDAPINFO_DN_RU;
355 			bi->sql_flags |= BSQLF_DONTCHECK_LDAPINFO_DN_RU;
356 
357 		} else {
358 			Debug( LDAP_DEBUG_TRACE,
359 				"<==backsql_db_config (%s line %d): "
360 				"\"has_ldapinfo_dn_ru\" directive arg "
361 				"must be \"yes\" or \"no\"\n",
362 				fname, lineno, 0 );
363 			return 1;
364 
365 		}
366 		Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
367 			"has_ldapinfo_dn_ru=%s\n",
368 			BACKSQL_HAS_LDAPINFO_DN_RU( bi ) ? "yes" : "no", 0, 0 );
369 
370 	} else if ( !strcasecmp( argv[ 0 ], "fail_if_no_mapping" ) ) {
371 		if ( argc < 2 ) {
372 			Debug( LDAP_DEBUG_TRACE,
373 				"<==backsql_db_config (%s line %d): "
374 				"missing { yes | no }"
375 				"in \"fail_if_no_mapping\" directive\n",
376 				fname, lineno, 0 );
377 			return 1;
378 		}
379 
380 		if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
381 			bi->sql_flags |= BSQLF_FAIL_IF_NO_MAPPING;
382 
383 		} else if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
384 			bi->sql_flags &= ~BSQLF_FAIL_IF_NO_MAPPING;
385 
386 		} else {
387 			Debug( LDAP_DEBUG_TRACE,
388 				"<==backsql_db_config (%s line %d): "
389 				"\"fail_if_no_mapping\" directive arg "
390 				"must be \"yes\" or \"no\"\n",
391 				fname, lineno, 0 );
392 			return 1;
393 
394 		}
395 		Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
396 			"fail_if_no_mapping=%s\n",
397 			BACKSQL_FAIL_IF_NO_MAPPING( bi ) ? "yes" : "no", 0, 0 );
398 
399 	} else if ( !strcasecmp( argv[ 0 ], "allow_orphans" ) ) {
400 		if ( argc < 2 ) {
401 			Debug( LDAP_DEBUG_TRACE,
402 				"<==backsql_db_config (%s line %d): "
403 				"missing { yes | no }"
404 				"in \"allow_orphans\" directive\n",
405 				fname, lineno, 0 );
406 			return 1;
407 		}
408 
409 		if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
410 			bi->sql_flags |= BSQLF_ALLOW_ORPHANS;
411 
412 		} else if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
413 			bi->sql_flags &= ~BSQLF_ALLOW_ORPHANS;
414 
415 		} else {
416 			Debug( LDAP_DEBUG_TRACE,
417 				"<==backsql_db_config (%s line %d): "
418 				"\"allow_orphans\" directive arg "
419 				"must be \"yes\" or \"no\"\n",
420 				fname, lineno, 0 );
421 			return 1;
422 
423 		}
424 		Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
425 			"allow_orphans=%s\n",
426 			BACKSQL_ALLOW_ORPHANS( bi ) ? "yes" : "no", 0, 0 );
427 
428 	} else if ( !strcasecmp( argv[ 0 ], "baseobject" ) ) {
429 		if ( be->be_suffix == NULL ) {
430 			Debug( LDAP_DEBUG_TRACE,
431 				"<==backsql_db_config (%s line %d): : "
432 				"must be defined after \"suffix\"\n",
433 				fname, lineno, 0 );
434 			return 1;
435 		}
436 
437 		if ( bi->sql_baseObject ) {
438 			Debug( LDAP_DEBUG_TRACE,
439 				"<==backsql_db_config (%s line %d): : "
440 				"\"baseObject\" already provided (will be overwritten)\n",
441 				fname, lineno, 0 );
442 			entry_free( bi->sql_baseObject );
443 		}
444 
445 		switch ( argc ) {
446 		case 1:
447 			return create_baseObject( be, fname, lineno );
448 
449 		case 2:
450 			return read_baseObject( be, argv[ 1 ] );
451 
452 		default:
453 			Debug( LDAP_DEBUG_TRACE,
454 				"<==backsql_db_config (%s line %d): "
455 				"trailing values "
456 				"in \"baseObject\" directive?\n",
457 				fname, lineno, 0 );
458 			return 1;
459 		}
460 
461 	} else if ( !strcasecmp( argv[ 0 ], "sqllayer" ) ) {
462 		if ( backsql_api_config( bi, argv[ 1 ], argc - 2, &argv[ 2 ] ) )
463 		{
464 			Debug( LDAP_DEBUG_TRACE,
465 				"<==backsql_db_config (%s line %d): "
466 				"unable to load sqllayer \"%s\"\n",
467 				fname, lineno, argv[ 1 ] );
468 			return 1;
469 		}
470 
471 	} else if ( !strcasecmp( argv[ 0 ], "id_query" ) ) {
472 		if ( argc < 2 ) {
473 			Debug( LDAP_DEBUG_TRACE,
474 				"<==backsql_db_config (%s line %d): "
475 				"missing SQL condition "
476 				"in \"id_query\" directive\n",
477 				fname, lineno, 0 );
478 			return 1;
479 		}
480 		bi->sql_id_query = ch_strdup( argv[ 1 ] );
481 		Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
482 			"id_query=%s\n", bi->sql_id_query, 0, 0 );
483 
484 	} else if ( !strcasecmp( argv[ 0 ], "use_subtree_shortcut" ) ) {
485 		if ( argc < 2 ) {
486 			Debug( LDAP_DEBUG_TRACE,
487 				"<==backsql_db_config (%s line %d): "
488 				"missing { yes | no }"
489 				"in \"use_subtree_shortcut\" directive\n",
490 				fname, lineno, 0 );
491 			return 1;
492 		}
493 
494 		if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
495 			bi->sql_flags |= BSQLF_USE_SUBTREE_SHORTCUT;
496 
497 		} else if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
498 			bi->sql_flags &= ~BSQLF_USE_SUBTREE_SHORTCUT;
499 
500 		} else {
501 			Debug( LDAP_DEBUG_TRACE,
502 				"<==backsql_db_config (%s line %d): "
503 				"\"use_subtree_shortcut\" directive arg "
504 				"must be \"yes\" or \"no\"\n",
505 				fname, lineno, 0 );
506 			return 1;
507 
508 		}
509 		Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
510 			"use_subtree_shortcut=%s\n",
511 			BACKSQL_USE_SUBTREE_SHORTCUT( bi ) ? "yes" : "no",
512 			0, 0 );
513 
514 	} else if ( !strcasecmp( argv[ 0 ], "fetch_all_attrs" ) ) {
515 		if ( argc < 2 ) {
516 			Debug( LDAP_DEBUG_TRACE,
517 				"<==backsql_db_config (%s line %d): "
518 				"missing { yes | no }"
519 				"in \"fetch_all_attrs\" directive\n",
520 				fname, lineno, 0 );
521 			return 1;
522 		}
523 
524 		if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
525 			bi->sql_flags |= BSQLF_FETCH_ALL_ATTRS;
526 
527 		} else if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
528 			bi->sql_flags &= ~BSQLF_FETCH_ALL_ATTRS;
529 
530 		} else {
531 			Debug( LDAP_DEBUG_TRACE,
532 				"<==backsql_db_config (%s line %d): "
533 				"\"fetch_all_attrs\" directive arg "
534 				"must be \"yes\" or \"no\"\n",
535 				fname, lineno, 0 );
536 			return 1;
537 
538 		}
539 		Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
540 			"fetch_all_attrs=%s\n",
541 			BACKSQL_FETCH_ALL_ATTRS( bi ) ? "yes" : "no",
542 			0, 0 );
543 
544 	} else if ( !strcasecmp( argv[ 0 ], "fetch_attrs" ) ) {
545 		char		*str, *s, *next;
546 		const char	*delimstr = ",";
547 
548 		if ( argc < 2 ) {
549 			Debug( LDAP_DEBUG_TRACE,
550 				"<==backsql_db_config (%s line %d): "
551 				"missing <attrlist>"
552 				"in \"fetch_all_attrs <attrlist>\" directive\n",
553 				fname, lineno, 0 );
554 			return 1;
555 		}
556 
557 		str = ch_strdup( argv[ 1 ] );
558 		for ( s = ldap_pvt_strtok( str, delimstr, &next );
559 				s != NULL;
560 				s = ldap_pvt_strtok( NULL, delimstr, &next ) )
561 		{
562 			if ( strlen( s ) == 1 ) {
563 				if ( *s == '*' ) {
564 					bi->sql_flags |= BSQLF_FETCH_ALL_USERATTRS;
565 					argv[ 1 ][ s - str ] = ',';
566 
567 				} else if ( *s == '+' ) {
568 					bi->sql_flags |= BSQLF_FETCH_ALL_OPATTRS;
569 					argv[ 1 ][ s - str ] = ',';
570 				}
571 			}
572 		}
573 		ch_free( str );
574 		bi->sql_anlist = str2anlist( bi->sql_anlist, argv[ 1 ], delimstr );
575 		if ( bi->sql_anlist == NULL ) {
576 			return -1;
577 		}
578 
579 	} else if ( !strcasecmp( argv[ 0 ], "check_schema" ) ) {
580 		if ( argc != 2 ) {
581 			Debug( LDAP_DEBUG_TRACE,
582 				"<==backsql_db_config (%s line %d): "
583 				"missing { yes | no }"
584 				"in \"check_schema\" directive\n",
585 				fname, lineno, 0 );
586 			return 1;
587 		}
588 
589 		if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
590 			bi->sql_flags |= BSQLF_CHECK_SCHEMA;
591 
592 		} else if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
593 			bi->sql_flags &= ~BSQLF_CHECK_SCHEMA;
594 
595 		} else {
596 			Debug( LDAP_DEBUG_TRACE,
597 				"<==backsql_db_config (%s line %d): "
598 				"\"check_schema\" directive arg "
599 				"must be \"yes\" or \"no\"\n",
600 				fname, lineno, 0 );
601 			return 1;
602 
603 		}
604 		Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
605 			"check_schema=%s\n",
606 			BACKSQL_CHECK_SCHEMA( bi ) ? "yes" : "no",
607 			0, 0 );
608 
609 	} else if ( !strcasecmp( argv[ 0 ], "aliasing_keyword" ) ) {
610 		if ( argc != 2 ) {
611 			Debug( LDAP_DEBUG_TRACE,
612 				"<==backsql_db_config (%s line %d): "
613 				"missing arg "
614 				"in \"aliasing_keyword <string>\" directive\n",
615 				fname, lineno, 0 );
616 			return 1;
617 		}
618 
619 		if ( ! BER_BVISNULL( &bi->sql_aliasing ) ) {
620 			ch_free( bi->sql_aliasing.bv_val );
621 		}
622 
623 		ber_str2bv( argv[ 1 ], strlen( argv[ 1 ] ) + 1, 1,
624 			&bi->sql_aliasing );
625 		/* add a trailing space... */
626 		bi->sql_aliasing.bv_val[ bi->sql_aliasing.bv_len - 1] = ' ';
627 
628 	} else if ( !strcasecmp( argv[ 0 ], "aliasing_quote" ) ) {
629 		if ( argc != 2 ) {
630 			Debug( LDAP_DEBUG_TRACE,
631 				"<==backsql_db_config (%s line %d): "
632 				"missing arg "
633 				"in \"aliasing_quote <string>\" directive\n",
634 				fname, lineno, 0 );
635 			return 1;
636 		}
637 
638 		if ( ! BER_BVISNULL( &bi->sql_aliasing_quote ) ) {
639 			ch_free( bi->sql_aliasing_quote.bv_val );
640 		}
641 
642 		ber_str2bv( argv[ 1 ], 0, 1, &bi->sql_aliasing_quote );
643 
644 	} else {
645 		return SLAP_CONF_UNKNOWN;
646 	}
647 
648 	return 0;
649 }
650 
651 /*
652  * Read the entries specified in fname and merge the attributes
653  * to the user defined baseObject entry. Note that if we find any errors
654  * what so ever, we will discard the entire entries, print an
655  * error message and return.
656  */
657 static int
658 read_baseObject(
659 	BackendDB	*be,
660 	const char	*fname )
661 {
662 	backsql_info 	*bi = (backsql_info *)be->be_private;
663 	LDIFFP		*fp;
664 	int		rc = 0, lineno = 0, lmax = 0, ldifrc;
665 	char		*buf = NULL;
666 
667 	assert( fname != NULL );
668 
669 	fp = ldif_open( fname, "r" );
670 	if ( fp == NULL ) {
671 		Debug( LDAP_DEBUG_ANY,
672 			"could not open back-sql baseObject "
673 			"attr file \"%s\" - absolute path?\n",
674 			fname, 0, 0 );
675 		perror( fname );
676 		return LDAP_OTHER;
677 	}
678 
679 	bi->sql_baseObject = entry_alloc();
680 	if ( bi->sql_baseObject == NULL ) {
681 		Debug( LDAP_DEBUG_ANY,
682 			"read_baseObject_file: entry_alloc failed", 0, 0, 0 );
683 		ldif_close( fp );
684 		return LDAP_NO_MEMORY;
685 	}
686 	bi->sql_baseObject->e_name = be->be_suffix[0];
687 	bi->sql_baseObject->e_nname = be->be_nsuffix[0];
688 	bi->sql_baseObject->e_attrs = NULL;
689 
690 	while (( ldifrc = ldif_read_record( fp, &lineno, &buf, &lmax )) > 0 ) {
691 		Entry		*e = str2entry( buf );
692 		Attribute	*a;
693 
694 		if( e == NULL ) {
695 			fprintf( stderr, "back-sql baseObject: "
696 					"could not parse entry (line=%d)\n",
697 					lineno );
698 			rc = LDAP_OTHER;
699 			break;
700 		}
701 
702 		/* make sure the DN is the database's suffix */
703 		if ( !be_issuffix( be, &e->e_nname ) ) {
704 			fprintf( stderr,
705 				"back-sql: invalid baseObject - "
706 				"dn=\"%s\" (line=%d)\n",
707 				e->e_name.bv_val, lineno );
708 			entry_free( e );
709 			rc = LDAP_OTHER;
710 			break;
711 		}
712 
713 		/*
714 		 * we found a valid entry, so walk thru all the attributes in the
715 		 * entry, and add each attribute type and description to baseObject
716 		 */
717 		for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
718 			if ( attr_merge( bi->sql_baseObject, a->a_desc,
719 						a->a_vals,
720 						( a->a_nvals == a->a_vals ) ?
721 						NULL : a->a_nvals ) )
722 			{
723 				rc = LDAP_OTHER;
724 				break;
725 			}
726 		}
727 
728 		entry_free( e );
729 		if ( rc ) {
730 			break;
731 		}
732 	}
733 
734 	if ( ldifrc < 0 )
735 		rc = LDAP_OTHER;
736 
737 	if ( rc ) {
738 		entry_free( bi->sql_baseObject );
739 		bi->sql_baseObject = NULL;
740 	}
741 
742 	ch_free( buf );
743 
744 	ldif_close( fp );
745 
746 	Debug( LDAP_DEBUG_CONFIG, "back-sql baseObject file \"%s\" read.\n",
747 			fname, 0, 0 );
748 
749 	return rc;
750 }
751 
752 static int
753 create_baseObject(
754 	BackendDB	*be,
755 	const char	*fname,
756 	int		lineno )
757 {
758 	backsql_info 	*bi = (backsql_info *)be->be_private;
759 	LDAPRDN		rdn;
760 	char		*p;
761 	int		rc, iAVA;
762 	char		buf[1024];
763 
764 	snprintf( buf, sizeof(buf),
765 			"dn: %s\n"
766 			"objectClass: extensibleObject\n"
767 			"description: builtin baseObject for back-sql\n"
768 			"description: all entries mapped "
769 				"in table \"ldap_entries\" "
770 				"must have "
771 				"\"" BACKSQL_BASEOBJECT_IDSTR "\" "
772 				"in the \"parent\" column",
773 			be->be_suffix[0].bv_val );
774 
775 	bi->sql_baseObject = str2entry( buf );
776 	if ( bi->sql_baseObject == NULL ) {
777 		Debug( LDAP_DEBUG_TRACE,
778 			"<==backsql_db_config (%s line %d): "
779 			"unable to parse baseObject entry\n",
780 			fname, lineno, 0 );
781 		return 1;
782 	}
783 
784 	if ( BER_BVISEMPTY( &be->be_suffix[ 0 ] ) ) {
785 		return 0;
786 	}
787 
788 	rc = ldap_bv2rdn( &be->be_suffix[ 0 ], &rdn, (char **)&p,
789 			LDAP_DN_FORMAT_LDAP );
790 	if ( rc != LDAP_SUCCESS ) {
791 		snprintf( buf, sizeof(buf),
792 			"unable to extract RDN "
793 			"from baseObject DN \"%s\" (%d: %s)",
794 			be->be_suffix[ 0 ].bv_val,
795 			rc, ldap_err2string( rc ) );
796 		Debug( LDAP_DEBUG_TRACE,
797 			"<==backsql_db_config (%s line %d): %s\n",
798 			fname, lineno, buf );
799 		return 1;
800 	}
801 
802 	for ( iAVA = 0; rdn[ iAVA ]; iAVA++ ) {
803 		LDAPAVA				*ava = rdn[ iAVA ];
804 		AttributeDescription		*ad = NULL;
805 		slap_syntax_transform_func	*transf = NULL;
806 		struct berval			bv = BER_BVNULL;
807 		const char			*text = NULL;
808 
809 		assert( ava != NULL );
810 
811 		rc = slap_bv2ad( &ava->la_attr, &ad, &text );
812 		if ( rc != LDAP_SUCCESS ) {
813 			snprintf( buf, sizeof(buf),
814 				"AttributeDescription of naming "
815 				"attribute #%d from baseObject "
816 				"DN \"%s\": %d: %s",
817 				iAVA, be->be_suffix[ 0 ].bv_val,
818 				rc, ldap_err2string( rc ) );
819 			Debug( LDAP_DEBUG_TRACE,
820 				"<==backsql_db_config (%s line %d): %s\n",
821 				fname, lineno, buf );
822 			return 1;
823 		}
824 
825 		transf = ad->ad_type->sat_syntax->ssyn_pretty;
826 		if ( transf ) {
827 			/*
828 	 		 * transform value by pretty function
829 			 *	if value is empty, use empty_bv
830 			 */
831 			rc = ( *transf )( ad->ad_type->sat_syntax,
832 				ava->la_value.bv_len
833 					? &ava->la_value
834 					: (struct berval *) &slap_empty_bv,
835 				&bv, NULL );
836 
837 			if ( rc != LDAP_SUCCESS ) {
838 				snprintf( buf, sizeof(buf),
839 					"prettying of attribute #%d "
840 					"from baseObject "
841 					"DN \"%s\" failed: %d: %s",
842 					iAVA, be->be_suffix[ 0 ].bv_val,
843 					rc, ldap_err2string( rc ) );
844 				Debug( LDAP_DEBUG_TRACE,
845 					"<==backsql_db_config (%s line %d): "
846 					"%s\n",
847 					fname, lineno, buf );
848 				return 1;
849 			}
850 		}
851 
852 		if ( !BER_BVISNULL( &bv ) ) {
853 			if ( ava->la_flags & LDAP_AVA_FREE_VALUE ) {
854 				ber_memfree( ava->la_value.bv_val );
855 			}
856 			ava->la_value = bv;
857 			ava->la_flags |= LDAP_AVA_FREE_VALUE;
858 		}
859 
860 		attr_merge_normalize_one( bi->sql_baseObject,
861 				ad, &ava->la_value, NULL );
862 	}
863 
864 	ldap_rdnfree( rdn );
865 
866 	return 0;
867 }
868 
869