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