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