]> git.sur5r.net Git - openldap/blob - servers/slapd/back-sql/back-sql.h
minor naming cleanup; improvements to DN mapping layer; major docs update
[openldap] / servers / slapd / back-sql / back-sql.h
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2005 The OpenLDAP Foundation.
5  * Portions Copyright 1999 Dmitry Kovalev.
6  * Portions Copyright 2002 Pierangelo Mararati.
7  * Portions Copyright 2004 Mark Adamson.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted only as authorized by the OpenLDAP
12  * Public License.
13  *
14  * A copy of this license is available in the file LICENSE in the
15  * top-level directory of the distribution or, alternatively, at
16  * <http://www.OpenLDAP.org/license.html>.
17  */
18 /* ACKNOWLEDGEMENTS:
19  * This work was initially developed by Dmitry Kovalev for inclusion
20  * by OpenLDAP Software.  Additional significant contributors include
21  * Pierangelo Masarati and Mark Adamson.
22  */
23 /*
24  * The following changes have been addressed:
25  *       
26  * Enhancements:
27  *   - re-styled code for better readability
28  *   - upgraded backend API to reflect recent changes
29  *   - LDAP schema is checked when loading SQL/LDAP mapping
30  *   - AttributeDescription/ObjectClass pointers used for more efficient
31  *     mapping lookup
32  *   - bervals used where string length is required often
33  *   - atomized write operations by committing at the end of each operation
34  *     and defaulting connection closure to rollback
35  *   - added LDAP access control to write operations
36  *   - fully implemented modrdn (with rdn attrs change, deleteoldrdn,
37  *     access check, parent/children check and more)
38  *   - added parent access control, children control to delete operation
39  *   - added structuralObjectClass operational attribute check and
40  *     value return on search
41  *   - added hasSubordinate operational attribute on demand
42  *   - search limits are appropriately enforced
43  *   - function backsql_strcat() has been made more efficient
44  *   - concat function has been made configurable by means of a pattern
45  *   - added config switches:
46  *       - fail_if_no_mapping   write operations fail if there is no mapping
47  *       - has_ldapinfo_dn_ru   overrides autodetect
48  *       - concat_pattern       a string containing two '?' is used
49  *                              (note that "?||?" should be more portable
50  *                              than builtin function "CONCAT(?,?)")
51  *       - strcast_func         cast of string constants in "SELECT DISTINCT
52  *                              statements (needed by PostgreSQL)
53  *       - upper_needs_cast     cast the argument of upper when required
54  *                              (basically when building dn substring queries)
55  *   - added noop control
56  *   - added values return filter control
57  *   - hasSubordinate can be used in search filters (with limitations)
58  *   - eliminated oc->name; use oc->oc->soc_cname instead
59  * 
60  * Todo:
61  *   - add security checks for SQL statements that can be injected (?)
62  *   - re-test with previously supported RDBMs
63  *   - replace dn_ru and so with normalized dn (no need for upper() and so
64  *     in dn match)
65  *   - implement a backsql_normalize() function to replace the upper()
66  *     conversion routines
67  *   - note that subtree deletion, subtree renaming and so could be easily
68  *     implemented (rollback and consistency checks are available :)
69  *   - implement "lastmod" and other operational stuff (ldap_entries table ?)
70  *   - check how to allow multiple operations with one statement, to remove
71  *     BACKSQL_REALLOC_STMT from modify.c (a more recent unixODBC lib?)
72  */
73 /*
74  * Improvements submitted by (ITS#3432)
75  *
76  * 1. id_query.patch            applied (with changes)
77  * 2. shortcut.patch            applied (reworked)
78  * 3. create_hint.patch         applied
79  * 4. count_query.patch         rejected (conflicts with other features)
80  * 5. returncodes.patch         applied (with sanity checks)
81  * 6. connpool.patch            under evaluation
82  * 7. modoc.patch               under evaluation
83  * 8. miscfixes.patch           applied (reworked; FIXME: other
84  *                              operations may need to load the
85  *                              entire entry for ACL purposes)
86  *
87  * original description:
88
89          Changes that were made to the SQL backend.
90
91 The patches were made against 2.2.18 and can be applied individually,
92 but would best be applied in the numerical order of the file names.
93 A synopsis of each patch is given here:
94
95
96 1. Added an option to set SQL query for the "id_query" operation.
97
98 2. Added an option to the SQL backend called "use_subtree_shortcut".
99 When a search is performed, the SQL query includes a WHERE clause
100 which says the DN must be "LIKE %<searchbase>".  The LIKE operation
101 can be slow in an RDBM. This shortcut option says that if the
102 searchbase of the LDAP search is the root DN of the SQL backend,
103 and thus all objects will match the LIKE operator, do not include
104 the "LIKE %<searchbase>" clause in the SQL query (it is replaced
105 instead by the always true "1=1" clause to keep the "AND"'s 
106 working correctly).  This option is off by default, and should be
107 turned on only if all objects to be found in the RDBM are under the
108 same root DN. Multiple backends working within the same RDBM table
109 space would encounter problems. LDAP searches whose searchbase are
110 not at the root DN will bypass this shortcut and employ the LIKE 
111 clause.
112
113 3. Added a "create_hint" column to ldap_oc_mappings table. Allows
114 taking the value of an attr named in "create_hint" and passing it to
115 the create_proc procedure.  This is necessary for when an objectClass's
116 table is partition indexed by some indexing column and thus the value
117 in that indexing column cannot change after the row is created. The
118 value for the indexed column is passed into the create_proc, which
119 uses it to fill in the indexed column as the new row is created.
120
121 4. When loading the values of an attribute, the count(*) of the number
122 of values is fetched first and memory is allocated for the array of
123 values and normalized values. The old system of loading the values one
124 by one and running realloc() on the array of values and normalized
125 values each time was badly fragmenting memory. The array of values and
126 normalized values would be side by side in memory, and realloc()'ing
127 them over and over would force them to leapfrog each other through all
128 of available memory. Attrs with a large number of values could not be
129 loaded without crashing the slapd daemon.
130
131 5. Added code to interpret the value returned by stored procedures
132 which have expect_return set. Returned value is interpreted as an LDAP
133 return code. This allows the distinction between the SQL failing to
134 execute and the SQL running to completion and returning an error code
135 which can indicate a policy violation.
136
137 6. Added RDBM connection pooling. Once an operation is finished the
138 connection to the RDBM is returned to a pool rather than closing.
139 Allows the next operation to skip the initialization and authentication
140 phases of contacting the RDBM. Also, if licensing with ODBC places
141 a limit on the number of connections, an LDAP thread can block waiting
142 for another thread to finish, so that no LDAP errors are returned
143 for having more LDAP connections than allowed RDBM connections. An
144 RDBM connection which receives an SQL error is marked as "tainted"
145 so that it will be closed rather than returned to the pool.
146   Also, RDBM connections must be bound to a given LDAP connection AND
147 operation number, and NOT just the connection number.  Asynchronous
148 LDAP clients can have multiple simultaneous LDAP operations which
149 should not share the same RDBM connection.  A given LDAP operation can
150 even make multiple SQL operations (e.g. a BIND operation which
151 requires SASL to perform an LDAP search to convert the SASL ID to an
152 LDAP DN), so each RDBM connection now has a refcount that must reach
153 zero before the connection is returned to the free pool.
154
155 7. Added ability to change the objectClass of an object. Required 
156 considerable work to copy all attributes out of old object and into
157 new object.  Does a schema check before proceeding.  Creates a new
158 object, fills it in, deletes the old object, then changes the 
159 oc_map_id and keyval of the entry in the "ldap_entries" table.
160
161 8.  Generic fixes. Includes initializing pointers before they
162 get used in error branch cases, pointer checks before dereferencing,
163 resetting a return code to success after a COMPARE op, sealing
164 memory leaks, and in search.c, changing some of the "1=1" tests to
165 "2=2", "3=3", etc so that when reading slapd trace output, the 
166 location in the source code where the x=x test was added to the SQL
167 can be easily distinguished.
168  */
169
170 #ifndef __BACKSQL_H__
171 #define __BACKSQL_H__
172
173 /* former sql-types.h */
174 #include <sql.h>
175 #include <sqlext.h>
176
177 typedef struct {
178         SWORD           ncols;
179         BerVarray       col_names;
180         UDWORD          *col_prec;
181         char            **cols;
182         SQLINTEGER      *value_len;
183 } BACKSQL_ROW_NTS;
184
185 /*
186  * Better use the standard length of 8192 (as of slap.h)?
187  *
188  * NOTE: must be consistent with definition in ldap_entries table
189  */
190 /* #define BACKSQL_MAX_DN_LEN   SLAP_LDAPDN_MAXLEN */
191 #define BACKSQL_MAX_DN_LEN      255
192
193 /*
194  * define to enable very extensive trace logging (debug only)
195  */
196 #undef BACKSQL_TRACE
197
198 /*
199  * define to enable varchars as unique keys in user tables
200  *
201  * by default integers are used (and recommended)
202  * for performances.  Integers are used anyway in back-sql
203  * related tables.
204  */
205 #undef BACKSQL_ARBITRARY_KEY
206
207 /*
208  * define to enable experimental support for syncporv overlay
209  */
210 #ifdef LDAP_DEVEL
211 #define BACKSQL_SYNCPROV
212 #endif /* LDAP_DEVEL */
213
214 /*
215  * define to the appropriate aliasing string
216  *
217  * some RDBMSes tolerate (or require) that " AS " is not used
218  * when aliasing tables/columns
219  */
220 #define BACKSQL_ALIASING        "AS "
221 /* #define      BACKSQL_ALIASING        "" */
222
223 /*
224  * define to the appropriate quoting char
225  *
226  * some RDBMSes tolerate/require that the aliases be enclosed
227  * in quotes.  This is especially true for those that do not
228  * allow keywords used as aliases.
229  */
230 /* #define BACKSQL_ALIASING_QUOTE       '"' */
231 /* #define BACKSQL_ALIASING_QUOTE       '\'' */
232
233 /*
234  * API
235  *
236  * a simple mechanism to allow DN mucking between the LDAP
237  * and the stored string representation.
238  */
239 typedef struct backsql_api {
240         char                    *ba_name;
241         int                     (*ba_config)( struct backsql_api *self, int argc, char *argv[] );
242         int                     (*ba_destroy)( struct backsql_api *self );
243
244         int                     (*ba_dn2odbc)( Operation *op, SlapReply *rs, struct berval *dn );
245         int                     (*ba_odbc2dn)( Operation *op, SlapReply *rs, struct berval *dn );
246
247         void                    *ba_private;
248         struct backsql_api      *ba_next;
249 } backsql_api;
250
251 /*
252  * Entry ID structure
253  */
254 typedef struct backsql_entryID {
255         /* #define BACKSQL_ARBITRARY_KEY to allow a non-numeric key.
256          * It is required by some special applications that use
257          * strings as keys for the main table.
258          * In this case, #define BACKSQL_MAX_KEY_LEN consistently
259          * with the key size definition */
260 #ifdef BACKSQL_ARBITRARY_KEY
261         struct berval           eid_id;
262         struct berval           eid_keyval;
263 #define BACKSQL_MAX_KEY_LEN     64
264 #else /* ! BACKSQL_ARBITRARY_KEY */
265         /* The original numeric key is maintained as default. */
266         unsigned long           eid_id;
267         unsigned long           eid_keyval;
268 #endif /* ! BACKSQL_ARBITRARY_KEY */
269
270         unsigned long           eid_oc_id;
271         struct berval           eid_dn;
272         struct berval           eid_ndn;
273         struct backsql_entryID  *eid_next;
274 } backsql_entryID;
275
276 #ifdef BACKSQL_ARBITRARY_KEY
277 #define BACKSQL_ENTRYID_INIT { BER_BVNULL, BER_BVNULL, 0, BER_BVNULL, BER_BVNULL, NULL }
278 #else /* ! BACKSQL_ARBITRARY_KEY */
279 #define BACKSQL_ENTRYID_INIT { 0, 0, 0, BER_BVNULL, BER_BVNULL, NULL }
280 #endif /* BACKSQL_ARBITRARY_KEY */
281
282 /*
283  * "structural" objectClass mapping structure
284  */
285 typedef struct backsql_oc_map_rec {
286         /*
287          * Structure of corresponding LDAP objectClass definition
288          */
289         ObjectClass             *bom_oc;
290 #define BACKSQL_OC_NAME(ocmap)  ((ocmap)->bom_oc->soc_cname.bv_val)
291         
292         struct berval           bom_keytbl;
293         struct berval           bom_keycol;
294         /* expected to return keyval of newly created entry */
295         char                    *bom_create_proc;
296         /* in case create_proc does not return the keyval of the newly
297          * created row */
298         char                    *bom_create_keyval;
299         /* supposed to expect keyval as parameter and delete 
300          * all the attributes as well */
301         char                    *bom_delete_proc;
302         /* flags whether delete_proc is a function (whether back-sql 
303          * should bind first parameter as output for return code) */
304         int                     bom_expect_return;
305         unsigned long           bom_id;
306         Avlnode                 *bom_attrs;
307         AttributeDescription    *bom_create_hint;
308 } backsql_oc_map_rec;
309
310 /*
311  * attributeType mapping structure
312  */
313 typedef struct backsql_at_map_rec {
314         /* Description of corresponding LDAP attribute type */
315         AttributeDescription    *bam_ad;
316         /* ObjectClass if bam_ad is objectClass */
317         ObjectClass             *bam_oc;
318
319         struct berval   bam_from_tbls;
320         struct berval   bam_join_where;
321         struct berval   bam_sel_expr;
322
323         /* TimesTen, or, if a uppercase function is defined,
324          * an uppercased version of bam_sel_expr */
325         struct berval   bam_sel_expr_u;
326
327         /* supposed to expect 2 binded values: entry keyval 
328          * and attr. value to add, like "add_name(?,?,?)" */
329         char            *bam_add_proc;
330         /* supposed to expect 2 binded values: entry keyval 
331          * and attr. value to delete */
332         char            *bam_delete_proc;
333         /* for optimization purposes attribute load query 
334          * is preconstructed from parts on schemamap load time */
335         char            *bam_query;
336         /* following flags are bitmasks (first bit used for add_proc, 
337          * second - for delete_proc) */
338         /* order of parameters for procedures above; 
339          * 1 means "data then keyval", 0 means "keyval then data" */
340         int             bam_param_order;
341         /* flags whether one or more of procedures is a function 
342          * (whether back-sql should bind first parameter as output 
343          * for return code) */
344         int             bam_expect_return;
345
346         /* next mapping for attribute */
347         struct backsql_at_map_rec       *bam_next;
348 } backsql_at_map_rec;
349
350 #define BACKSQL_AT_MAP_REC_INIT { NULL, NULL, BER_BVC(""), BER_BVC(""), BER_BVNULL, BER_BVNULL, NULL, NULL, NULL, 0, 0, NULL }
351
352 /* define to uppercase filters only if the matching rule requires it
353  * (currently broken) */
354 /* #define      BACKSQL_UPPERCASE_FILTER */
355
356 #define BACKSQL_AT_CANUPPERCASE(at)     ((at)->bam_sel_expr_u.bv_val)
357
358 /* defines to support bitmasks above */
359 #define BACKSQL_ADD     0x1
360 #define BACKSQL_DEL     0x2
361
362 #define BACKSQL_IS_ADD(x)       ( BACKSQL_ADD & (x) )
363 #define BACKSQL_IS_DEL(x)       ( BACKSQL_DEL & (x) )
364
365 #define BACKSQL_NCMP(v1,v2)     ber_bvcmp((v1),(v2))
366
367 #define BACKSQL_CONCAT
368 /*
369  * berbuf structure: a berval with a buffer size associated
370  */
371 typedef struct berbuf {
372         struct berval   bb_val;
373         ber_len_t       bb_len;
374 } BerBuffer;
375
376 #define BB_NULL         { { 0, NULL }, 0 }
377
378 typedef struct backsql_srch_info {
379         Operation               *bsi_op;
380         SlapReply               *bsi_rs;
381
382         unsigned                bsi_flags;
383 #define BSQL_SF_NONE                    0x0000U
384 #define BSQL_SF_ALL_USER                0x0001U
385 #define BSQL_SF_ALL_OPER                0x0002U
386 #define BSQL_SF_ALL_ATTRS               (BSQL_SF_ALL_USER|BSQL_SF_ALL_OPER)
387 #define BSQL_SF_FILTER_HASSUBORDINATE   0x0010U
388 #define BSQL_SF_FILTER_ENTRYUUID        0x0020U
389 #define BSQL_SF_FILTER_ENTRYCSN         0x0040U
390 #define BSQL_SF_RETURN_ENTRYUUID        (BSQL_SF_FILTER_ENTRYUUID << 8)
391
392         struct berval           *bsi_base_ndn;
393         int                     bsi_use_subtree_shortcut;
394         backsql_entryID         bsi_base_id;
395         int                     bsi_scope;
396 /* BACKSQL_SCOPE_BASE_LIKE can be set by API in ors_scope
397  * whenever the search base DN contains chars that cannot
398  * be mapped into the charset used in the RDBMS; so they're
399  * turned into '%' and an approximate ('LIKE') condition
400  * is used */
401 #define BACKSQL_SCOPE_BASE_LIKE         ( LDAP_SCOPE_BASE | 0x1000 )
402         Filter                  *bsi_filter;
403         int                     bsi_slimit,
404                                 bsi_tlimit;
405         time_t                  bsi_stoptime;
406
407         backsql_entryID         *bsi_id_list,
408                                 **bsi_id_listtail,
409                                 *bsi_c_eid;
410         int                     bsi_n_candidates;
411         int                     bsi_abandon;
412         int                     bsi_status;
413
414         backsql_oc_map_rec      *bsi_oc;
415         struct berbuf           bsi_sel,
416                                 bsi_from,
417                                 bsi_join_where,
418                                 bsi_flt_where;
419         ObjectClass             *bsi_filter_oc;
420         SQLHDBC                 bsi_dbh;
421         AttributeName           *bsi_attrs;
422
423         Entry                   *bsi_e;
424 } backsql_srch_info;
425
426 /*
427  * Backend private data structure
428  */
429 typedef struct {
430         char            *sql_dbhost;
431         int             sql_dbport;
432         char            *sql_dbuser;
433         char            *sql_dbpasswd;
434         char            *sql_dbname;
435
436         /*
437          * SQL condition for subtree searches differs in syntax:
438          * "LIKE CONCAT('%',?)" or "LIKE '%'+?" or "LIKE '%'||?"
439          * or smtg else 
440          */
441         struct berval   sql_subtree_cond;
442         struct berval   sql_children_cond;
443         char            *sql_oc_query,
444                         *sql_at_query;
445         char            *sql_insentry_stmt,
446                         *sql_delentry_stmt,
447                         *sql_delobjclasses_stmt,
448                         *sql_delreferrals_stmt;
449         char            *sql_id_query;
450         char            *sql_has_children_query;
451
452         MatchingRule    *sql_caseIgnoreMatch;
453         MatchingRule    *sql_telephoneNumberMatch;
454
455         struct berval   sql_upper_func;
456         struct berval   sql_upper_func_open;
457         struct berval   sql_upper_func_close;
458         BerVarray       sql_concat_func;
459
460         struct berval   sql_strcast_func;
461
462         unsigned int    sql_flags;
463 #define BSQLF_SCHEMA_LOADED             0x0001
464 #define BSQLF_UPPER_NEEDS_CAST          0x0002
465 #define BSQLF_CREATE_NEEDS_SELECT       0x0004
466 #define BSQLF_FAIL_IF_NO_MAPPING        0x0008
467 #define BSQLF_HAS_LDAPINFO_DN_RU        0x0010
468 #define BSQLF_DONTCHECK_LDAPINFO_DN_RU  0x0020
469 #define BSQLF_USE_REVERSE_DN            0x0040
470 #define BSQLF_ALLOW_ORPHANS             0x0080
471 #define BSQLF_USE_SUBTREE_SHORTCUT      0x0100
472
473 #define BACKSQL_SCHEMA_LOADED(si) \
474         ((si)->sql_flags & BSQLF_SCHEMA_LOADED)
475 #define BACKSQL_UPPER_NEEDS_CAST(si) \
476         ((si)->sql_flags & BSQLF_UPPER_NEEDS_CAST)
477 #define BACKSQL_CREATE_NEEDS_SELECT(si) \
478         ((si)->sql_flags & BSQLF_CREATE_NEEDS_SELECT)
479 #define BACKSQL_FAIL_IF_NO_MAPPING(si) \
480         ((si)->sql_flags & BSQLF_FAIL_IF_NO_MAPPING)
481 #define BACKSQL_HAS_LDAPINFO_DN_RU(si) \
482         ((si)->sql_flags & BSQLF_HAS_LDAPINFO_DN_RU)
483 #define BACKSQL_DONTCHECK_LDAPINFO_DN_RU(si) \
484         ((si)->sql_flags & BSQLF_DONTCHECK_LDAPINFO_DN_RU)
485 #define BACKSQL_USE_REVERSE_DN(si) \
486         ((si)->sql_flags & BSQLF_USE_REVERSE_DN)
487 #define BACKSQL_CANUPPERCASE(si) \
488         (!BER_BVISNULL( &(si)->sql_upper_func ))
489 #define BACKSQL_ALLOW_ORPHANS(si) \
490         ((si)->sql_flags & BSQLF_ALLOW_ORPHANS)
491 #define BACKSQL_USE_SUBTREE_SHORTCUT(si) \
492         ((si)->sql_flags & BSQLF_USE_SUBTREE_SHORTCUT)
493
494         Entry           *sql_baseObject;
495 #ifdef BACKSQL_ARBITRARY_KEY
496 #define BACKSQL_BASEOBJECT_IDSTR        "baseObject"
497 #define BACKSQL_BASEOBJECT_KEYVAL       BACKSQL_BASEOBJECT_IDSTR
498 #define BACKSQL_IS_BASEOBJECT_ID(id)    (bvmatch((id), &backsql_baseObject_bv))
499 #else /* ! BACKSQL_ARBITRARY_KEY */
500 #define BACKSQL_BASEOBJECT_ID           0
501 #define BACKSQL_BASEOBJECT_IDSTR        "0"
502 #define BACKSQL_BASEOBJECT_KEYVAL       0
503 #define BACKSQL_IS_BASEOBJECT_ID(id)    (*(id) == BACKSQL_BASEOBJECT_ID)
504 #endif /* ! BACKSQL_ARBITRARY_KEY */
505 #define BACKSQL_BASEOBJECT_OC           0
506         
507         Avlnode         *sql_db_conns;
508         Avlnode         *sql_oc_by_oc;
509         Avlnode         *sql_oc_by_id;
510         ldap_pvt_thread_mutex_t         sql_dbconn_mutex;
511         ldap_pvt_thread_mutex_t         sql_schema_mutex;
512         SQLHENV         sql_db_env;
513
514         backsql_api     *sql_api;
515 } backsql_info;
516
517 #define BACKSQL_SUCCESS( rc ) \
518         ( (rc) == SQL_SUCCESS || (rc) == SQL_SUCCESS_WITH_INFO )
519
520 #define BACKSQL_AVL_STOP                0
521 #define BACKSQL_AVL_CONTINUE            1
522
523 /* see ldap.h for the meaning of the macros and of the values */
524 #define BACKSQL_LEGAL_ERROR( rc ) \
525         ( LDAP_RANGE( (rc), 0x00, 0x0e ) \
526           || LDAP_ATTR_ERROR( (rc) ) \
527           || LDAP_NAME_ERROR( (rc) ) \
528           || LDAP_SECURITY_ERROR( (rc) ) \
529           || LDAP_SERVICE_ERROR( (rc) ) \
530           || LDAP_UPDATE_ERROR( (rc) ) )
531 #define BACKSQL_SANITIZE_ERROR( rc ) \
532         ( BACKSQL_LEGAL_ERROR( (rc) ) ? (rc) : LDAP_OTHER )
533
534 #endif /* __BACKSQL_H__ */
535