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