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