]> git.sur5r.net Git - openldap/blob - servers/slapd/slapi/plugin.c
terminate function array in slapi_int_get_plugins()
[openldap] / servers / slapd / slapi / plugin.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 2002-2005 The OpenLDAP Foundation.
5  * Portions Copyright 1997,2002-2003 IBM Corporation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 /* ACKNOWLEDGEMENTS:
17  * This work was initially developed by IBM Corporation for use in
18  * IBM products and subsequently ported to OpenLDAP Software by
19  * Steve Omrani.  Additional significant contributors include:
20  *    Luke Howard
21  */
22
23 #include "portable.h"
24 #include <ldap_pvt_thread.h>
25 #include <slap.h>
26 #include <slapi.h>
27 #include <lutil.h>
28
29 /*
30  * Note: if ltdl.h is not available, slapi should not be compiled
31  */
32 #include <ltdl.h>
33
34 static int slapi_int_load_plugin( Slapi_PBlock *, const char *, const char *, int, 
35         SLAPI_FUNC *, lt_dlhandle * );
36
37 /* pointer to link list of extended objects */
38 static ExtendedOp *pGExtendedOps = NULL;
39
40 /*********************************************************************
41  * Function Name:      plugin_pblock_new
42  *
43  * Description:        This routine creates a new Slapi_PBlock structure,
44  *                     loads in the plugin module and executes the init
45  *                     function provided by the module.
46  *
47  * Input:              type - type of the plugin, such as SASL, database, etc.
48  *                     path - the loadpath to load the module in
49  *                     initfunc - name of the plugin function to execute first
50  *                     argc - number of arguements
51  *                     argv[] - an array of char pointers point to
52  *                              the arguments passed in via
53  *                              the configuration file.
54  *
55  * Output:             
56  *
57  * Return Values:      a pointer to a newly created Slapi_PBlock structrue or
58  *                     NULL - function failed 
59  *
60  * Messages:           None
61  *********************************************************************/
62
63 static Slapi_PBlock *
64 plugin_pblock_new(
65         int type, 
66         int argc, 
67         char *argv[] ) 
68 {
69         Slapi_PBlock    *pPlugin = NULL; 
70         Slapi_PluginDesc *pPluginDesc = NULL;
71         lt_dlhandle     hdLoadHandle;
72         int             rc;
73         char **av2 = NULL, **ppPluginArgv;
74         char *path = argv[2];
75         char *initfunc = argv[3];
76
77         pPlugin = slapi_pblock_new();
78         if ( pPlugin == NULL ) {
79                 rc = LDAP_NO_MEMORY;
80                 goto done;
81         }
82
83         rc = slapi_pblock_set( pPlugin, SLAPI_PLUGIN_TYPE, (void *)type );
84         if ( rc != 0 ) {
85                 goto done;
86         }
87
88         rc = slapi_pblock_set( pPlugin, SLAPI_PLUGIN_ARGC, (void *)argc );
89         if ( rc != 0 ) {
90                 goto done;
91         }
92
93         av2 = ldap_charray_dup( argv );
94         if ( av2 == NULL ) {
95                 rc = LDAP_NO_MEMORY;
96                 goto done;
97         }
98
99         if ( argc > 0 ) {
100                 ppPluginArgv = &av2[4];
101         } else {
102                 ppPluginArgv = NULL;
103         }
104         rc = slapi_pblock_set( pPlugin, SLAPI_PLUGIN_ARGV, (void *)ppPluginArgv );
105         if ( rc != 0 ) { 
106                 goto done;
107         }
108
109         rc = slapi_pblock_set( pPlugin, SLAPI_X_CONFIG_ARGV, (void *)av2 );
110         if ( rc != 0 ) { 
111                 goto done;
112         }
113
114         rc = slapi_int_load_plugin( pPlugin, path, initfunc, 1, NULL, &hdLoadHandle );
115         if ( rc != 0 ) {
116                 goto done;
117         }
118
119         if ( slapi_pblock_get( pPlugin, SLAPI_PLUGIN_DESCRIPTION, (void **)&pPluginDesc ) == 0 &&
120              pPluginDesc != NULL ) {
121                 slapi_log_error(SLAPI_LOG_TRACE, "plugin_pblock_new",
122                                 "Registered plugin %s %s [%s] (%s)\n",
123                                 pPluginDesc->spd_id,
124                                 pPluginDesc->spd_version,
125                                 pPluginDesc->spd_vendor,
126                                 pPluginDesc->spd_description);
127         }
128
129 done:
130         if ( rc != 0 && pPlugin != NULL ) {
131                 slapi_pblock_destroy( pPlugin );
132                 pPlugin = NULL;
133                 if ( av2 != NULL ) {
134                         ldap_charray_free( av2 );
135                 }
136         }
137
138         return pPlugin;
139
140
141 /*********************************************************************
142  * Function Name:      slapi_int_register_plugin
143  *
144  * Description:        insert the slapi_pblock structure to the end of the plugin
145  *                     list 
146  *
147  * Input:              a pointer to a plugin slapi_pblock structure to be added to 
148  *                     the list
149  *
150  * Output:             none
151  *
152  * Return Values:      LDAP_SUCCESS - successfully inserted.
153  *                     LDAP_LOCAL_ERROR.
154  *
155  * Messages:           None
156  *********************************************************************/
157 int 
158 slapi_int_register_plugin(
159         Backend *be, 
160         Slapi_PBlock *pPB )
161
162         Slapi_PBlock *pTmpPB;
163         Slapi_PBlock *pSavePB;
164         int    rc = LDAP_SUCCESS;
165
166         assert( be != NULL );
167
168         pTmpPB = (Slapi_PBlock *)be->be_pb;
169         if ( pTmpPB == NULL ) {
170                 be->be_pb = (void *)pPB;
171         } else {
172                 while ( pTmpPB != NULL && rc == LDAP_SUCCESS ) {
173                         pSavePB = pTmpPB;
174                         rc = slapi_pblock_get( pTmpPB, SLAPI_IBM_PBLOCK, &pTmpPB );
175                 }
176
177                 if ( rc == LDAP_SUCCESS ) { 
178                         rc = slapi_pblock_set( pSavePB, SLAPI_IBM_PBLOCK, (void *)pPB ); 
179                 }
180         }
181      
182         return ( rc != LDAP_SUCCESS ) ? LDAP_OTHER : LDAP_SUCCESS;
183 }
184        
185 /*********************************************************************
186  * Function Name:      slapi_int_get_plugins
187  *
188  * Description:        get the desired type of function pointers defined 
189  *                     in all the plugins 
190  *
191  * Input:              the type of the functions to get, such as pre-operation,etc.
192  *
193  * Output:             none
194  *
195  * Return Values:      this routine returns a pointer to an array of function
196  *                     pointers containing backend-specific plugin functions
197  *                     followed by global plugin functions
198  *
199  * Messages:           None
200  *********************************************************************/
201 int 
202 slapi_int_get_plugins(
203         Backend *be,            
204         int functype, 
205         SLAPI_FUNC **ppFuncPtrs )
206 {
207  
208         Slapi_PBlock    *pCurrentPB; 
209         SLAPI_FUNC      FuncPtr;
210         SLAPI_FUNC      *pTmpFuncPtr;
211         int             numPB = 0;
212         int             rc = LDAP_SUCCESS;
213
214         assert( ppFuncPtrs != NULL );
215
216         if ( be == NULL ) {
217                 goto done;
218         }
219
220         pCurrentPB = (Slapi_PBlock *)be->be_pb;
221
222         while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
223                 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
224                 if ( rc == LDAP_SUCCESS ) {
225                         if ( FuncPtr != NULL )  {
226                                 numPB++;
227                         }
228                         rc = slapi_pblock_get( pCurrentPB,
229                                 SLAPI_IBM_PBLOCK, &pCurrentPB );
230                 }
231         }
232
233         if ( numPB == 0 ) {
234                 *ppFuncPtrs = NULL;
235                 rc = LDAP_SUCCESS;
236                 goto done;
237         }
238
239         /*
240          * Now, build the function pointer array of backend-specific
241          * plugins followed by global plugins.
242          */
243         *ppFuncPtrs = pTmpFuncPtr = 
244                 (SLAPI_FUNC *)ch_malloc( ( numPB + 1 ) * sizeof(SLAPI_FUNC) ); 
245         if ( ppFuncPtrs == NULL ) {
246                 rc = LDAP_NO_MEMORY;
247                 goto done;
248         }
249
250         pCurrentPB = (Slapi_PBlock *)be->be_pb;
251
252         while ( pCurrentPB != NULL && rc == LDAP_SUCCESS )  {
253                 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
254                 if ( rc == LDAP_SUCCESS ) {
255                         if ( FuncPtr != NULL )  {
256                                 *pTmpFuncPtr = FuncPtr;
257                                 pTmpFuncPtr++;
258                         } 
259                         rc = slapi_pblock_get( pCurrentPB,
260                                         SLAPI_IBM_PBLOCK, &pCurrentPB );
261                 }
262         }
263
264         *pTmpFuncPtr = NULL;
265
266
267 done:
268         if ( rc != LDAP_SUCCESS && *ppFuncPtrs != NULL ) {
269                 ch_free( *ppFuncPtrs );
270                 *ppFuncPtrs = NULL;
271         }
272
273         return rc;
274 }
275
276 /*********************************************************************
277  * Function Name:      createExtendedOp
278  *
279  * Description: Creates an extended operation structure and
280  *              initializes the fields
281  *
282  * Return value: A newly allocated structure or NULL
283  ********************************************************************/
284 ExtendedOp *
285 createExtendedOp()
286 {
287         ExtendedOp *ret;
288
289         ret = (ExtendedOp *)ch_malloc(sizeof(ExtendedOp));
290         if ( ret != NULL ) {
291                 ret->ext_oid.bv_val = NULL;
292                 ret->ext_oid.bv_len = 0;
293                 ret->ext_func = NULL;
294                 ret->ext_be = NULL;
295                 ret->ext_next = NULL;
296         }
297
298         return ret;
299 }
300
301
302 /*********************************************************************
303  * Function Name:      slapi_int_unregister_extop
304  *
305  * Description:        This routine removes the ExtendedOp structures 
306  *                                         asscoiated with a particular extended operation 
307  *                                         plugin.
308  *
309  * Input:              pBE - pointer to a backend structure
310  *                     opList - pointer to a linked list of extended
311  *                              operation structures
312  *                     pPB - pointer to a slapi parameter block
313  *
314  * Output:
315  *
316  * Return Value:       none
317  *
318  * Messages:           None
319  *********************************************************************/
320 void
321 slapi_int_unregister_extop(
322         Backend *pBE, 
323         ExtendedOp **opList, 
324         Slapi_PBlock *pPB )
325 {
326         ExtendedOp      *pTmpExtOp, *backExtOp;
327         char            **pTmpOIDs;
328         int             i;
329
330 #if 0
331         assert( pBE != NULL); /* unused */
332 #endif /* 0 */
333         assert( opList != NULL );
334         assert( pPB != NULL );
335
336         if ( *opList == NULL ) {
337                 return;
338         }
339
340         slapi_pblock_get( pPB, SLAPI_PLUGIN_EXT_OP_OIDLIST, &pTmpOIDs );
341         if ( pTmpOIDs == NULL ) {
342                 return;
343         }
344
345         for ( i = 0; pTmpOIDs[i] != NULL; i++ ) {
346                 backExtOp = NULL;
347                 pTmpExtOp = *opList;
348                 for ( ; pTmpExtOp != NULL; pTmpExtOp = pTmpExtOp->ext_next) {
349                         int     rc;
350                         rc = strcasecmp( pTmpExtOp->ext_oid.bv_val,
351                                         pTmpOIDs[ i ] );
352                         if ( rc == 0 ) {
353                                 if ( backExtOp == NULL ) {
354                                         *opList = pTmpExtOp->ext_next;
355                                 } else {
356                                         backExtOp->ext_next
357                                                 = pTmpExtOp->ext_next;
358                                 }
359
360                                 ch_free( pTmpExtOp );
361                                 break;
362                         }
363                         backExtOp = pTmpExtOp;
364                 }
365         }
366 }
367
368
369 /*********************************************************************
370  * Function Name:      slapi_int_register_extop
371  *
372  * Description:        This routine creates a new ExtendedOp structure, loads
373  *                     in the extended op module and put the extended op function address
374  *                     in the structure. The function will not be executed in
375  *                     this routine.
376  *
377  * Input:              pBE - pointer to a backend structure
378  *                     opList - pointer to a linked list of extended
379  *                              operation structures
380  *                     pPB - pointer to a slapi parameter block
381  *
382  * Output:
383  *
384  * Return Value:       an LDAP return code
385  *
386  * Messages:           None
387  *********************************************************************/
388 int 
389 slapi_int_register_extop(
390         Backend *pBE,   
391         ExtendedOp **opList, 
392         Slapi_PBlock *pPB )
393 {
394         ExtendedOp      *pTmpExtOp = NULL;
395         SLAPI_FUNC      tmpFunc;
396         char            **pTmpOIDs;
397         int             rc = LDAP_OTHER;
398         int             i;
399
400         if ( (*opList) == NULL ) { 
401                 *opList = createExtendedOp();
402                 if ( (*opList) == NULL ) {
403                         rc = LDAP_NO_MEMORY;
404                         goto error_return;
405                 }
406                 pTmpExtOp = *opList;
407                 
408         } else {                        /* Find the end of the list */
409                 for ( pTmpExtOp = *opList; pTmpExtOp->ext_next != NULL;
410                                 pTmpExtOp = pTmpExtOp->ext_next )
411                         ; /* EMPTY */
412                 pTmpExtOp->ext_next = createExtendedOp();
413                 if ( pTmpExtOp->ext_next == NULL ) {
414                         rc = LDAP_NO_MEMORY;
415                         goto error_return;
416                 }
417                 pTmpExtOp = pTmpExtOp->ext_next;
418         }
419
420         rc = slapi_pblock_get( pPB,SLAPI_PLUGIN_EXT_OP_OIDLIST, &pTmpOIDs );
421         if ( rc != 0 ) {
422                 rc = LDAP_OTHER;
423                 goto error_return;
424         }
425
426         rc = slapi_pblock_get(pPB,SLAPI_PLUGIN_EXT_OP_FN, &tmpFunc);
427         if ( rc != 0 ) {
428                 rc = LDAP_OTHER;
429                 goto error_return;
430         }
431
432         if ( (pTmpOIDs == NULL) || (tmpFunc == NULL) ) {
433                 rc = LDAP_OTHER;
434                 goto error_return;
435         }
436
437         for ( i = 0; pTmpOIDs[i] != NULL; i++ ) {
438                 pTmpExtOp->ext_oid.bv_val = pTmpOIDs[i];
439                 pTmpExtOp->ext_oid.bv_len = strlen( pTmpOIDs[i] );
440                 pTmpExtOp->ext_func = tmpFunc;
441                 pTmpExtOp->ext_be = pBE;
442                 if ( pTmpOIDs[i + 1] != NULL ) {
443                         pTmpExtOp->ext_next = createExtendedOp();
444                         if ( pTmpExtOp->ext_next == NULL ) {
445                                 rc = LDAP_NO_MEMORY;
446                                 break;
447                         }
448                         pTmpExtOp = pTmpExtOp->ext_next;
449                 }
450         }
451
452 error_return:
453         return rc;
454 }
455
456 /*********************************************************************
457  * Function Name:      slapi_int_get_extop_plugin
458  *
459  * Description:        This routine gets the function address for a given function
460  *                     name.
461  *
462  * Input:
463  *                     funcName - name of the extended op function, ie. an OID.
464  *
465  * Output:             pFuncAddr - the function address of the requested function name.
466  *
467  * Return Values:      a pointer to a newly created ExtendOp structrue or
468  *                     NULL - function failed
469  *
470  * Messages:           None
471  *********************************************************************/
472 int 
473 slapi_int_get_extop_plugin(
474         struct berval *reqoid,          
475         SLAPI_FUNC *pFuncAddr ) 
476 {
477         ExtendedOp      *pTmpExtOp;
478
479         assert( reqoid != NULL );
480         assert( pFuncAddr != NULL );
481
482         *pFuncAddr = NULL;
483
484         if ( pGExtendedOps == NULL ) {
485                 return LDAP_OTHER;
486         }
487
488         pTmpExtOp = pGExtendedOps;
489         while ( pTmpExtOp != NULL ) {
490                 int     rc;
491                 
492                 rc = strcasecmp( reqoid->bv_val, pTmpExtOp->ext_oid.bv_val );
493                 if ( rc == 0 ) {
494                         *pFuncAddr = pTmpExtOp->ext_func;
495                         break;
496                 }
497                 pTmpExtOp = pTmpExtOp->ext_next;
498         }
499
500         return ( *pFuncAddr == NULL ? 1 : 0 );
501 }
502
503 /***************************************************************************
504  * This function is similar to slapi_int_get_extop_plugin above. except it returns one OID
505  * per call. It is called from root_dse_info (root_dse.c).
506  * The function is a modified version of get_supported_extop (file extended.c).
507  ***************************************************************************/
508 struct berval *
509 slapi_int_get_supported_extop( int index )
510 {
511         ExtendedOp      *ext;
512
513         for ( ext = pGExtendedOps ; ext != NULL && --index >= 0;
514                         ext = ext->ext_next) {
515                 ; /* empty */
516         }
517
518         if ( ext == NULL ) {
519                 return NULL;
520         }
521
522         return &ext->ext_oid ;
523 }
524
525 /*********************************************************************
526  * Function Name:      slapi_int_load_plugin
527  *
528  * Description:        This routine loads the specified DLL, gets and executes the init function
529  *                     if requested.
530  *
531  * Input:
532  *                     pPlugin - a pointer to a Slapi_PBlock struct which will be passed to
533  *                               the DLL init function.
534  *                     path - path name of the DLL to be load.
535  *                     initfunc - either the DLL initialization function or an OID of the
536  *                                loaded extended operation.
537  *                     doInit - if it is TRUE, execute the init function, otherwise, save the
538  *                              function address but not execute it.
539  *
540  * Output:             pInitFunc - the function address of the loaded function. This param
541  *                                 should be not be null if doInit is FALSE.
542  *                     pLdHandle - handle returned by lt_dlopen()
543  *
544  * Return Values:      LDAP_SUCCESS, LDAP_LOCAL_ERROR
545  *
546  * Messages:           None
547  *********************************************************************/
548
549 static int 
550 slapi_int_load_plugin(
551         Slapi_PBlock    *pPlugin,
552         const char      *path,
553         const char      *initfunc, 
554         int             doInit,
555         SLAPI_FUNC      *pInitFunc,
556         lt_dlhandle     *pLdHandle ) 
557 {
558         int             rc = LDAP_SUCCESS;
559         SLAPI_FUNC      fpInitFunc = NULL;
560
561         assert( pLdHandle != NULL );
562
563         if ( lt_dlinit() ) {
564                 return LDAP_LOCAL_ERROR;
565         }
566
567         /* load in the module */
568         *pLdHandle = lt_dlopen( path );
569         if ( *pLdHandle == NULL ) {
570                 return LDAP_LOCAL_ERROR;
571         }
572
573         fpInitFunc = (SLAPI_FUNC)lt_dlsym( *pLdHandle, initfunc );
574         if ( fpInitFunc == NULL ) {
575                 lt_dlclose( *pLdHandle );
576                 return LDAP_LOCAL_ERROR;
577         }
578
579         if ( doInit ) {
580                 rc = ( *fpInitFunc )( pPlugin );
581                 if ( rc != LDAP_SUCCESS ) {
582                         lt_dlclose( *pLdHandle );
583                 }
584
585         } else {
586                 *pInitFunc = fpInitFunc;
587         }
588
589         return rc;
590 }
591
592 /*
593  * Special support for computed attribute plugins
594  */
595 int 
596 slapi_int_call_plugins(
597         Backend         *be,    
598         int             funcType, 
599         Slapi_PBlock    *pPB )
600 {
601
602         int rc = 0;
603         SLAPI_FUNC *pGetPlugin = NULL, *tmpPlugin = NULL; 
604
605         if ( pPB == NULL ) {
606                 return 1;
607         }
608
609         rc = slapi_int_get_plugins( be, funcType, &tmpPlugin );
610         if ( rc != LDAP_SUCCESS || tmpPlugin == NULL ) {
611                 /* Nothing to do, front-end should ignore. */
612                 return 1;
613         }
614
615         for ( pGetPlugin = tmpPlugin ; *pGetPlugin != NULL; pGetPlugin++ ) {
616                 /*
617                  * FIXME: we should provide here a sort of sandbox,
618                  * to protect from plugin faults; e.g. trap signals
619                  * and longjump here, marking the plugin as unsafe for
620                  * later executions ...
621                  */
622                 rc = (*pGetPlugin)(pPB);
623
624                 /*
625                  * Only non-postoperation plugins abort processing on
626                  * failure (confirmed with SLAPI specification).
627                  */
628                 if ( !SLAPI_PLUGIN_IS_POST_FN( funcType ) && rc != 0 ) {
629                         /*
630                          * Plugins generally return negative error codes
631                          * to indicate failure, although in the case of
632                          * bind plugins they may return SLAPI_BIND_xxx
633                          */
634                         break;
635                 }
636         }
637
638         slapi_ch_free( (void **)&tmpPlugin );
639
640         return rc;
641 }
642
643 int
644 slapi_int_read_config(
645         Backend         *be,            
646         const char      *fname, 
647         int             lineno, 
648         int             argc, 
649         char            **argv )
650 {
651         int             iType = -1;
652         int             numPluginArgc = 0;
653
654         if ( argc < 4 ) {
655                 fprintf( stderr,
656                         "%s: line %d: missing arguments "
657                         "in \"plugin <plugin_type> <lib_path> "
658                         "<init_function> [<arguments>]\" line\n",
659                         fname, lineno );
660                 return 1;
661         }
662
663         /* automatically instantiate overlay if necessary */
664         if ( !overlay_is_inst( be, SLAPI_OVERLAY_NAME ) ) {
665                 if ( overlay_config( be, SLAPI_OVERLAY_NAME ) != 0 ) {
666                         fprintf( stderr, "Failed to instantiate SLAPI overlay\n");
667                         return -1;
668                 }
669         }
670         
671         if ( strcasecmp( argv[1], "preoperation" ) == 0 ) {
672                 iType = SLAPI_PLUGIN_PREOPERATION;
673         } else if ( strcasecmp( argv[1], "postoperation" ) == 0 ) {
674                 iType = SLAPI_PLUGIN_POSTOPERATION;
675         } else if ( strcasecmp( argv[1], "extendedop" ) == 0 ) {
676                 iType = SLAPI_PLUGIN_EXTENDEDOP;
677         } else if ( strcasecmp( argv[1], "object" ) == 0 ) {
678                 iType = SLAPI_PLUGIN_OBJECT;
679         } else {
680                 fprintf( stderr, "%s: line %d: invalid plugin type \"%s\".\n",
681                                 fname, lineno, argv[1] );
682                 return 1;
683         }
684         
685         numPluginArgc = argc - 4;
686
687         if ( iType == SLAPI_PLUGIN_PREOPERATION ||
688                         iType == SLAPI_PLUGIN_EXTENDEDOP ||
689                         iType == SLAPI_PLUGIN_POSTOPERATION ||
690                         iType == SLAPI_PLUGIN_OBJECT ) {
691                 int rc;
692                 Slapi_PBlock *pPlugin;
693
694                 pPlugin = plugin_pblock_new( iType, numPluginArgc, argv );
695                 if (pPlugin == NULL) {
696                         return 1;
697                 }
698
699                 if (iType == SLAPI_PLUGIN_EXTENDEDOP) {
700                         rc = slapi_int_register_extop(be, &pGExtendedOps, pPlugin);
701                         if ( rc != LDAP_SUCCESS ) {
702                                 slapi_pblock_destroy( pPlugin );
703                                 return 1;
704                         }
705                 }
706
707                 rc = slapi_int_register_plugin( be, pPlugin );
708                 if ( rc != LDAP_SUCCESS ) {
709                         if ( iType == SLAPI_PLUGIN_EXTENDEDOP ) {
710                                 slapi_int_unregister_extop( be, &pGExtendedOps, pPlugin );
711                         }
712                         slapi_pblock_destroy( pPlugin );
713                         return 1;
714                 }
715         }
716
717         return 0;
718 }
719
720 void
721 slapi_int_plugin_unparse(
722         Backend *be,
723         BerVarray *out
724 )
725 {
726         Slapi_PBlock *pp;
727         int i, j;
728         char **argv, ibuf[32], *ptr;
729         struct berval idx, bv;
730
731         *out = NULL;
732         idx.bv_val = ibuf;
733         i = 0;
734
735         for ( pp = be->be_pb;
736               pp != NULL;
737               slapi_pblock_get( pp, SLAPI_IBM_PBLOCK, &pp ) )
738         {
739                 slapi_pblock_get( pp, SLAPI_X_CONFIG_ARGV, &argv );
740                 if ( argv == NULL ) /* could be dynamic plugin */
741                         continue;
742                 idx.bv_len = sprintf( idx.bv_val, "{%d}", i );
743                 bv.bv_len = idx.bv_len;
744                 for (j=1; argv[j]; j++) {
745                         bv.bv_len += strlen(argv[j]);
746                         if ( j ) bv.bv_len++;
747                 }
748                 bv.bv_val = ch_malloc( bv.bv_len + 1 );
749                 ptr = lutil_strcopy( bv.bv_val, ibuf );
750                 for (j=1; argv[j]; j++) {
751                         if ( j ) *ptr++ = ' ';
752                         ptr = lutil_strcopy( ptr, argv[j] );
753                 }
754                 ber_bvarray_add( out, &bv );
755         }
756 }
757
758 int
759 slapi_int_initialize(void)
760 {
761         if ( ldap_pvt_thread_mutex_init( &slapi_hn_mutex ) ) {
762                 return -1;
763         }
764         
765         if ( ldap_pvt_thread_mutex_init( &slapi_time_mutex ) ) {
766                 return -1;
767         }
768
769         if ( ldap_pvt_thread_mutex_init( &slapi_printmessage_mutex ) ) {
770                 return -1;
771         }
772
773         slapi_log_file = ch_strdup( LDAP_RUNDIR LDAP_DIRSEP "errors" );
774         if ( slapi_log_file == NULL ) {
775                 return -1;
776         }
777
778         if ( slapi_int_init_object_extensions() != 0 ) {
779                 return -1;
780         }
781
782         return slapi_int_overlay_init();
783 }