]> git.sur5r.net Git - openldap/blob - servers/slapd/backend.c
7e83933b21f2f0492b086fd3074ae9081951f8d4
[openldap] / servers / slapd / backend.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 /* backend.c - routines for dealing with back-end databases */
7
8
9 #include "portable.h"
10
11 #include <stdio.h>
12
13 #include <ac/string.h>
14 #include <ac/socket.h>
15
16 #include <sys/stat.h>
17
18 #include "slap.h"
19 #include "lutil.h"
20
21 #ifdef SLAPD_LDAP
22 #include "back-ldap/external.h"
23 #endif
24 #ifdef SLAPD_LDBM
25 #include "back-ldbm/external.h"
26 #endif
27 #ifdef SLAPD_BDB2
28 #include "back-bdb2/external.h"
29 #endif
30 #ifdef SLAPD_PASSWD
31 #include "back-passwd/external.h"
32 #endif
33 #ifdef SLAPD_PERL
34 #include "back-perl/external.h"
35 #endif
36 #ifdef SLAPD_SHELL
37 #include "back-shell/external.h"
38 #endif
39 #ifdef SLAPD_TCL
40 #include "back-tcl/external.h"
41 #endif
42
43 static BackendInfo binfo[] = {
44 #if defined(SLAPD_LDAP) && !defined(SLAPD_LDAP_DYNAMIC)
45         {"ldap",        ldap_back_initialize},
46 #endif
47 #if defined(SLAPD_LDBM) && !defined(SLAPD_LDBM_DYNAMIC)
48         {"ldbm",        ldbm_back_initialize},
49 #endif
50 #if defined(SLAPD_BDB2) && !defined(SLAPD_BDB2_DYNAMIC)
51         {"bdb2",        bdb2_back_initialize},
52 #endif
53 #if defined(SLAPD_PASSWD) && !defined(SLAPD_PASSWD_DYNAMIC)
54         {"passwd",      passwd_back_initialize},
55 #endif
56 #if defined(SLAPD_PERL) && !defined(SLAPD_PERL_DYNAMIC)
57         {"perl",        perl_back_initialize},
58 #endif
59 #if defined(SLAPD_SHELL) && !defined(SLAPD_SHELL_DYNAMIC)
60         {"shell",       shell_back_initialize},
61 #endif
62 #if defined(SLAPD_TCL) && !defined(SLAPD_TCL_DYNAMIC)
63         {"tcl",         tcl_back_initialize},
64 #endif
65         {NULL}
66 };
67
68 int                     nBackendInfo = 0;
69 BackendInfo     *backendInfo = NULL;
70
71 int                     nBackendDB = 0; 
72 BackendDB       *backendDB = NULL;
73
74 int backend_init(void)
75 {
76         int rc = -1;
77
78         if((nBackendInfo != 0) || (backendInfo != NULL)) {
79                 /* already initialized */
80                 Debug( LDAP_DEBUG_ANY,
81                         "backend_init: already initialized.\n", 0, 0, 0 );
82                 return -1;
83         }
84
85         for( ;
86                 binfo[nBackendInfo].bi_type != NULL;
87                 nBackendInfo++ )
88         {
89                 rc = binfo[nBackendInfo].bi_init( &binfo[nBackendInfo] );
90
91                 if(rc != 0) {
92                         Debug( LDAP_DEBUG_ANY,
93                                 "backend_init: initialized for type \"%s\"\n",
94                                         binfo[nBackendInfo].bi_type, 0, 0 );
95
96                         /* destroy those we've already inited */
97                         for( nBackendInfo--;
98                                 nBackendInfo >= 0 ;
99                                 nBackendInfo-- )
100                         { 
101                                 if ( binfo[nBackendInfo].bi_destroy ) {
102                                         binfo[nBackendInfo].bi_destroy(
103                                                 &binfo[nBackendInfo] );
104                                 }
105                         }
106                         return rc;
107                 }
108         }
109
110         if ( nBackendInfo > 0) {
111                 backendInfo = binfo;
112                 return 0;
113         }
114
115 #ifdef SLAPD_MODULES    
116         return 0;
117 #else
118         Debug( LDAP_DEBUG_ANY,
119                 "backend_init: failed\n",
120                 0, 0, 0 );
121
122         return rc;
123 #endif /* SLAPD_MODULES */
124 }
125
126 int backend_add(BackendInfo *aBackendInfo)
127 {
128    int rc = 0;
129
130    if ((rc = aBackendInfo->bi_init(aBackendInfo)) != 0) {
131       Debug( LDAP_DEBUG_ANY,
132              "backend_add: initialization for type \"%s\" failed\n",
133              aBackendInfo->bi_type, 0, 0 );
134       return rc;
135    }
136
137    /* now add the backend type to the Backend Info List */
138    {
139       BackendInfo *newBackendInfo = 0;
140
141       /* if backendInfo == binfo no deallocation of old backendInfo */
142       if (backendInfo == binfo) {
143          newBackendInfo = ch_calloc(nBackendInfo + 1, sizeof(BackendInfo));
144          memcpy(newBackendInfo, backendInfo, sizeof(BackendInfo) * 
145                 nBackendInfo);
146       } else {
147          newBackendInfo = ch_realloc(backendInfo, sizeof(BackendInfo) * 
148                                      (nBackendInfo + 1));
149       }
150       memcpy(&newBackendInfo[nBackendInfo], aBackendInfo, 
151              sizeof(BackendInfo));
152       backendInfo = newBackendInfo;
153       nBackendInfo++;
154
155       return 0;
156    }        
157 }
158
159 int backend_startup(Backend *be)
160 {
161         int i;
162         int rc = 0;
163
164         if( ! ( nBackendDB > 0 ) ) {
165                 /* no databases */
166                 Debug( LDAP_DEBUG_ANY,
167                         "backend_startup: %d databases to startup.\n",
168                         nBackendDB, 0, 0 );
169                 return 1;
170         }
171
172         if(be != NULL) {
173                 /* startup a specific backend database */
174                 Debug( LDAP_DEBUG_TRACE,
175                         "backend_startup: starting database\n",
176                         0, 0, 0 );
177
178                 if ( be->bd_info->bi_open ) {
179                         rc = be->bd_info->bi_open( be->bd_info );
180                 }
181
182                 if(rc != 0) {
183                         Debug( LDAP_DEBUG_ANY,
184                                 "backend_startup: bi_open failed!\n",
185                                 0, 0, 0 );
186                         return rc;
187                 }
188
189                 if ( be->bd_info->bi_db_open ) {
190                         rc = be->bd_info->bi_db_open( be );
191                 }
192
193                 if(rc != 0) {
194                         Debug( LDAP_DEBUG_ANY,
195                                 "backend_startup: bi_db_open failed!\n",
196                                 0, 0, 0 );
197                         return rc;
198                 }
199
200                 return rc;
201         }
202
203         /* open each backend type */
204         for( i = 0; i < nBackendInfo; i++ ) {
205                 if( backendInfo[i].bi_nDB == 0) {
206                         /* no database of this type, don't open */
207                         continue;
208                 }
209
210                 if( backendInfo[i].bi_open ) {
211                         rc = backendInfo[i].bi_open(
212                                 &backendInfo[i] );
213                 }
214
215                 if(rc != 0) {
216                         Debug( LDAP_DEBUG_ANY,
217                                 "backend_startup: bi_open %d failed!\n",
218                                 i, 0, 0 );
219                         return rc;
220                 }
221         }
222
223         /* open each backend database */
224         for( i = 0; i < nBackendDB; i++ ) {
225                 /* append global access controls */
226                 acl_append( &backendDB[i].be_acl, global_acl );
227
228                 if ( backendDB[i].bd_info->bi_db_open ) {
229                         rc = backendDB[i].bd_info->bi_db_open(
230                                 &backendDB[i] );
231                 }
232
233                 if(rc != 0) {
234                         Debug( LDAP_DEBUG_ANY,
235                                 "backend_startup: bi_db_open %d failed!\n",
236                                 i, 0, 0 );
237                         return rc;
238                 }
239         }
240
241         return rc;
242 }
243
244 int backend_num( Backend *be )
245 {
246         int i;
247
248         if( be == NULL ) return -1;
249
250         for( i = 0; i < nBackendDB; i++ ) {
251                 if( be == &backendDB[i] ) return i;
252         }
253         return -1;
254 }
255
256 int backend_shutdown( Backend *be )
257 {
258         int i;
259         int rc = 0;
260
261         if( be != NULL ) {
262                 /* shutdown a specific backend database */
263
264                 if ( be->bd_info->bi_nDB == 0 ) {
265                         /* no database of this type, we never opened it */
266                         return 0;
267                 }
268
269                 if ( be->bd_info->bi_db_close ) {
270                         be->bd_info->bi_db_close( be );
271                 }
272
273                 if( be->bd_info->bi_close ) {
274                         be->bd_info->bi_close( be->bd_info );
275                 }
276
277                 return 0;
278         }
279
280         /* close each backend database */
281         for( i = 0; i < nBackendDB; i++ ) {
282                 if ( backendDB[i].bd_info->bi_db_close ) {
283                         backendDB[i].bd_info->bi_db_close(
284                                 &backendDB[i] );
285                 }
286
287                 if(rc != 0) {
288                         Debug( LDAP_DEBUG_ANY,
289                                 "backend_close: bi_close %s failed!\n",
290                                 backendDB[i].be_type, 0, 0 );
291                 }
292         }
293
294         /* close each backend type */
295         for( i = 0; i < nBackendInfo; i++ ) {
296                 if( backendInfo[i].bi_nDB == 0 ) {
297                         /* no database of this type */
298                         continue;
299                 }
300
301                 if( backendInfo[i].bi_close ) {
302                         backendInfo[i].bi_close(
303                                 &backendInfo[i] );
304                 }
305         }
306
307         return 0;
308 }
309
310 int backend_destroy(void)
311 {
312         int i;
313
314         /* destroy each backend database */
315         for( i = 0; i < nBackendDB; i++ ) {
316                 if ( backendDB[i].bd_info->bi_db_destroy ) {
317                         backendDB[i].bd_info->bi_db_destroy(
318                                 &backendDB[i] );
319                 }
320         }
321
322         /* destroy each backend type */
323         for( i = 0; i < nBackendInfo; i++ ) {
324                 if( backendInfo[i].bi_destroy ) {
325                         backendInfo[i].bi_destroy(
326                                 &backendInfo[i] );
327                 }
328         }
329
330 #ifdef SLAPD_MODULES
331         if (backendInfo != binfo) {
332            free(backendInfo);
333         }
334 #endif /* SLAPD_MODULES */
335
336         nBackendInfo = 0;
337         backendInfo = NULL;
338
339         return 0;
340 }
341
342 BackendInfo* backend_info(const char *type)
343 {
344         int i;
345
346         /* search for the backend type */
347         for( i = 0; i < nBackendInfo; i++ ) {
348                 if( strcasecmp(backendInfo[i].bi_type, type) == 0 ) {
349                         return &backendInfo[i];
350                 }
351         }
352
353         return NULL;
354 }
355
356
357 BackendDB *
358 backend_db_init(
359     const char  *type
360 )
361 {
362         Backend *be;
363         BackendInfo *bi = backend_info(type);
364         int     rc = 0;
365
366         if( bi == NULL ) {
367                 fprintf( stderr, "Unrecognized database type (%s)\n", type );
368                 return NULL;
369         }
370
371         backendDB = (BackendDB *) ch_realloc(
372                         (char *) backendDB,
373                     (nBackendDB + 1) * sizeof(Backend) );
374
375         memset( &backendDB[nbackends], '\0', sizeof(Backend) );
376
377         be = &backends[nbackends++];
378
379         be->bd_info = bi;
380         be->be_sizelimit = defsize;
381         be->be_timelimit = deftime;
382         be->be_dfltaccess = global_default_access;
383
384         /* assign a default depth limit for alias deref */
385         be->be_max_deref_depth = SLAPD_DEFAULT_MAXDEREFDEPTH; 
386
387         be->be_realm = global_realm != NULL
388                 ? ch_strdup( global_realm ) : NULL;
389
390         if(bi->bi_db_init) {
391                 rc = bi->bi_db_init( be );
392         }
393
394         if(rc != 0) {
395                 fprintf( stderr, "database init failed (%s)\n", type );
396                 nbackends--;
397                 return NULL;
398         }
399
400         bi->bi_nDB++;
401         return( be );
402 }
403
404 void
405 be_db_close( void )
406 {
407         int     i;
408
409         for ( i = 0; i < nbackends; i++ ) {
410                 if ( backends[i].bd_info->bi_db_close ) {
411                         (*backends[i].bd_info->bi_db_close)( &backends[i] );
412                 }
413         }
414 }
415
416 Backend *
417 select_backend( const char * dn )
418 {
419         int     i, j, len, dnlen;
420
421         dnlen = strlen( dn );
422         for ( i = 0; i < nbackends; i++ ) {
423                 for ( j = 0; backends[i].be_nsuffix != NULL &&
424                     backends[i].be_nsuffix[j] != NULL; j++ )
425                 {
426                         len = strlen( backends[i].be_nsuffix[j] );
427
428                         if ( len > dnlen ) {
429                                 continue;
430                         }
431
432                         if ( strcmp( backends[i].be_nsuffix[j],
433                             dn + (dnlen - len) ) == 0 ) {
434                                 return( &backends[i] );
435                         }
436                 }
437         }
438
439 #ifdef LDAP_ALLOW_NULL_SEARCH_BASE
440         /* Add greg@greg.rim.or.jp
441          * It's quick hack for cheap client
442          * Some browser offer a NULL base at ldap_search
443          *
444          * Should only be used as a last resort. -Kdz
445          */
446         if(dnlen == 0) {
447                 Debug( LDAP_DEBUG_TRACE,
448                         "select_backend: use default backend\n", 0, 0, 0 );
449                 return( &backends[0] );
450         }
451 #endif /* LDAP_ALLOW_NULL_SEARCH_BASE */
452
453         return( NULL );
454 }
455
456 int
457 be_issuffix(
458     Backend     *be,
459     const char  *suffix
460 )
461 {
462         int     i;
463
464         for ( i = 0; be->be_nsuffix != NULL && be->be_nsuffix[i] != NULL; i++ ) {
465                 if ( strcmp( be->be_nsuffix[i], suffix ) == 0 ) {
466                         return( 1 );
467                 }
468         }
469
470         return( 0 );
471 }
472
473 int
474 be_isroot( Backend *be, const char *ndn )
475 {
476         int rc;
477
478         if ( ndn == NULL || be->be_root_ndn == NULL ) {
479                 return( 0 );
480         }
481
482         rc = strcmp( be->be_root_ndn, ndn ) ? 0 : 1;
483
484         return(rc);
485 }
486
487 char *
488 be_root_dn( Backend *be )
489 {
490         if ( be->be_root_dn == NULL ) {
491                 return( "" );
492         }
493
494         return be->be_root_dn;
495 }
496
497 int
498 be_isroot_pw( Backend *be, const char *ndn, struct berval *cred )
499 {
500         int result;
501
502         if ( ! be_isroot( be, ndn ) ) {
503                 return( 0 );
504         }
505
506 #ifdef SLAPD_CRYPT
507         ldap_pvt_thread_mutex_lock( &crypt_mutex );
508 #endif
509
510         result = lutil_passwd( cred->bv_val, be->be_root_pw, NULL );
511
512 #ifdef SLAPD_CRYPT
513         ldap_pvt_thread_mutex_unlock( &crypt_mutex );
514 #endif
515
516         return result == 0;
517 }
518
519 int
520 be_entry_release_rw( Backend *be, Entry *e, int rw )
521 {
522         if ( be->be_release ) {
523                 /* free and release entry from backend */
524                 return be->be_release( be, e, rw );
525         } else {
526                 /* free entry */
527                 entry_free( e );
528                 return 0;
529         }
530 }
531
532 int
533 backend_unbind(
534         Connection   *conn,
535         Operation    *op
536 )
537 {
538         int     i;
539
540         for ( i = 0; i < nbackends; i++ ) {
541                 if ( backends[i].be_unbind ) {
542                         (*backends[i].be_unbind)( &backends[i], conn, op );
543                 }
544         }
545
546         return 0;
547 }
548
549 int
550 backend_connection_init(
551         Connection   *conn
552 )
553 {
554         int     i;
555
556         for ( i = 0; i < nbackends; i++ ) {
557                 if ( backends[i].be_connection_init ) {
558                         (*backends[i].be_connection_init)( &backends[i], conn);
559                 }
560         }
561
562         return 0;
563 }
564
565 int
566 backend_connection_destroy(
567         Connection   *conn
568 )
569 {
570         int     i;
571
572         for ( i = 0; i < nbackends; i++ ) {
573                 if ( backends[i].be_connection_destroy ) {
574                         (*backends[i].be_connection_destroy)( &backends[i], conn);
575                 }
576         }
577
578         return 0;
579 }
580
581 int 
582 backend_group(
583         Backend *be,
584         Entry   *target,
585         const char      *gr_ndn,
586         const char      *op_ndn,
587         const char      *objectclassValue,
588         const char      *groupattrName
589 )
590 {
591         if (be->be_group)
592                 return( be->be_group(be, target, gr_ndn, op_ndn,
593                         objectclassValue, groupattrName) );
594         else
595                 return(1);
596 }
597
598 #ifdef SLAPD_SCHEMA_DN
599 Attribute *backend_subschemasubentry( Backend *be )
600 {
601         /* should be backend specific */
602         static struct berval ss_val = {
603                 sizeof(SLAPD_SCHEMA_DN)-1,
604                 SLAPD_SCHEMA_DN };
605         static struct berval *ss_vals[2] = { &ss_val, NULL };
606         static Attribute ss_attr = {
607                 "subschemasubentry",
608                 ss_vals,
609                 SYNTAX_DN | SYNTAX_CIS,
610                 NULL
611         };
612
613         return &ss_attr;
614 }
615 #endif