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