]> git.sur5r.net Git - openldap/blob - servers/slapd/backend.c
b57bd3684da0c0545259c9d088efddf689486553
[openldap] / servers / slapd / backend.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2000 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_DNSSRV
22 #include "back-dnssrv/external.h"
23 #endif
24 #ifdef SLAPD_LDAP
25 #include "back-ldap/external.h"
26 #endif
27 #ifdef SLAPD_LDBM
28 #include "back-ldbm/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_DNSSRV) && !defined(SLAPD_DNSSRV_DYNAMIC)
51         {"dnssrv",      dnssrv_back_initialize},
52 #endif
53 #if defined(SLAPD_LDAP) && !defined(SLAPD_LDAP_DYNAMIC)
54         {"ldap",        ldap_back_initialize},
55 #endif
56 #if defined(SLAPD_LDBM) && !defined(SLAPD_LDBM_DYNAMIC)
57         {"ldbm",        ldbm_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          AC_MEMCPY(newBackendInfo, backendInfo, sizeof(BackendInfo) * 
157                 nBackendInfo);
158       } else {
159          newBackendInfo = ch_realloc(backendInfo, sizeof(BackendInfo) * 
160                                      (nBackendInfo + 1));
161       }
162       AC_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         return( NULL );
452 }
453
454 int
455 be_issuffix(
456     Backend     *be,
457     const char  *suffix
458 )
459 {
460         int     i;
461
462         for ( i = 0; be->be_nsuffix != NULL && be->be_nsuffix[i] != NULL; i++ ) {
463                 if ( strcmp( be->be_nsuffix[i], suffix ) == 0 ) {
464                         return( 1 );
465                 }
466         }
467
468         return( 0 );
469 }
470
471 int
472 be_isroot( Backend *be, const char *ndn )
473 {
474         int rc;
475
476         if ( ndn == NULL || *ndn == '\0' ) {
477                 return( 0 );
478         }
479
480         if ( be->be_root_ndn == NULL || *be->be_root_ndn == '\0' ) {
481                 return( 0 );
482         }
483
484         rc = strcmp( be->be_root_ndn, ndn ) ? 0 : 1;
485
486         return(rc);
487 }
488
489 char *
490 be_root_dn( Backend *be )
491 {
492         if ( be->be_root_dn == NULL ) {
493                 return( "" );
494         }
495
496         return be->be_root_dn;
497 }
498
499 int
500 be_isroot_pw( Backend *be, const char *ndn, struct berval *cred )
501 {
502         int result;
503
504         if ( ! be_isroot( be, ndn ) ) {
505                 return 0;
506         }
507
508         if( be->be_root_pw.bv_len == 0 ) {
509                 return 0;
510         }
511
512 #ifdef SLAPD_CRYPT
513         ldap_pvt_thread_mutex_lock( &crypt_mutex );
514 #endif
515
516         result = lutil_passwd( &be->be_root_pw, cred, NULL );
517
518 #ifdef SLAPD_CRYPT
519         ldap_pvt_thread_mutex_unlock( &crypt_mutex );
520 #endif
521
522         return result == 0;
523 }
524
525 int
526 be_entry_release_rw( Backend *be, Entry *e, int rw )
527 {
528         if ( be->be_release ) {
529                 /* free and release entry from backend */
530                 return be->be_release( be, e, rw );
531         } else {
532                 /* free entry */
533                 entry_free( e );
534                 return 0;
535         }
536 }
537
538 int
539 backend_unbind(
540         Connection   *conn,
541         Operation    *op
542 )
543 {
544         int     i;
545
546         for ( i = 0; i < nbackends; i++ ) {
547                 if ( backends[i].be_unbind ) {
548                         (*backends[i].be_unbind)( &backends[i], conn, op );
549                 }
550         }
551
552         return 0;
553 }
554
555 int
556 backend_connection_init(
557         Connection   *conn
558 )
559 {
560         int     i;
561
562         for ( i = 0; i < nbackends; i++ ) {
563                 if ( backends[i].be_connection_init ) {
564                         (*backends[i].be_connection_init)( &backends[i], conn);
565                 }
566         }
567
568         return 0;
569 }
570
571 int
572 backend_connection_destroy(
573         Connection   *conn
574 )
575 {
576         int     i;
577
578         for ( i = 0; i < nbackends; i++ ) {
579                 if ( backends[i].be_connection_destroy ) {
580                         (*backends[i].be_connection_destroy)( &backends[i], conn);
581                 }
582         }
583
584         return 0;
585 }
586
587 int
588 backend_check_controls(
589         Backend *be,
590         Connection *conn,
591         Operation *op,
592         const char **text )
593 {
594         LDAPControl **ctrls;
595         ctrls = op->o_ctrls;
596         if( ctrls == NULL ) {
597                 return LDAP_SUCCESS;
598         }
599
600         for( ; *ctrls != NULL ; ctrls++ ) {
601                 if( (*ctrls)->ldctl_iscritical &&
602                         !charray_inlist( be->be_controls, (*ctrls)->ldctl_oid ) )
603                 {
604                         *text = "control unavailable in NamingContext";
605                         return LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
606                 }
607         }
608
609         return LDAP_SUCCESS;
610 }
611
612 int backend_check_referrals(
613         Backend *be,
614         Connection *conn,
615         Operation *op,
616         const char *dn,
617         const char *ndn )
618 {
619         int rc = LDAP_SUCCESS;
620
621         if( be->be_chk_referrals ) {
622                 const char *text;
623
624                 rc = be->be_chk_referrals( be,
625                         conn, op, dn, ndn, &text );
626
627                 if( rc != LDAP_SUCCESS && rc != LDAP_REFERRAL ) {
628                         send_ldap_result( conn, op, rc,
629                                 NULL, text, NULL, NULL );
630                 }
631         }
632
633         return rc;
634 }
635
636 int 
637 backend_group(
638         Backend *be,
639         Entry   *target,
640         const char      *gr_ndn,
641         const char      *op_ndn,
642         ObjectClass *group_oc,
643         AttributeDescription *group_at
644 )
645 {
646         if( strcmp( target->e_ndn, gr_ndn ) != 0 ) {
647                 /* we won't attempt to send it to a different backend */
648                 
649                 be = select_backend(gr_ndn);
650
651                 if (be == NULL) {
652                         return LDAP_NO_SUCH_OBJECT;
653                 }
654         } 
655
656         if( be->be_group ) {
657                 return be->be_group( be, target, gr_ndn, op_ndn,
658                         group_oc, group_at );
659         }
660
661         return LDAP_UNWILLING_TO_PERFORM;
662 }
663
664 int 
665 backend_attribute(
666         Backend *be,
667         Connection *conn,
668         Operation *op,
669         Entry   *target,
670         const char      *e_ndn,
671         AttributeDescription *entry_at,
672         struct berval ***vals
673 )
674 {
675         if( target == NULL || strcmp( target->e_ndn, e_ndn ) != 0 ) {
676                 /* we won't attempt to send it to a different backend */
677                 
678                 be = select_backend(e_ndn);
679
680                 if (be == NULL) {
681                         return LDAP_NO_SUCH_OBJECT;
682                 }
683         } 
684
685         if( be->be_attribute ) {
686                 return be->be_attribute( be, conn, op, target, e_ndn,
687                         entry_at, vals );
688         }
689
690         return LDAP_UNWILLING_TO_PERFORM;
691 }
692
693 Attribute *backend_operational(
694         Backend *be,
695         Entry *e )
696 {
697         Attribute *a = NULL;
698
699 #ifdef SLAPD_SCHEMA_DN
700         a = ch_malloc( sizeof( Attribute ) );
701         a->a_desc = ad_dup( slap_schema.si_ad_subschemaSubentry );
702
703         /* Should be backend specific */
704         a->a_vals = ch_malloc( 2 * sizeof( struct berval * ) );
705         a->a_vals[0] = ber_bvstrdup( SLAPD_SCHEMA_DN );
706         a->a_vals[1] = NULL;
707
708         a->a_next = NULL;
709 #endif
710
711         return a;
712 }