]> git.sur5r.net Git - openldap/blob - servers/slapd/slapi/plugin.c
SLAPI plugins are no longer global; global SLAPI plugins should be
[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
265 done:
266         if ( rc != LDAP_SUCCESS && *ppFuncPtrs != NULL ) {
267                 ch_free( *ppFuncPtrs );
268                 *ppFuncPtrs = NULL;
269         }
270
271         return rc;
272 }
273
274 /*********************************************************************
275  * Function Name:      createExtendedOp
276  *
277  * Description: Creates an extended operation structure and
278  *              initializes the fields
279  *
280  * Return value: A newly allocated structure or NULL
281  ********************************************************************/
282 ExtendedOp *
283 createExtendedOp()
284 {
285         ExtendedOp *ret;
286
287         ret = (ExtendedOp *)ch_malloc(sizeof(ExtendedOp));
288         if ( ret != NULL ) {
289                 ret->ext_oid.bv_val = NULL;
290                 ret->ext_oid.bv_len = 0;
291                 ret->ext_func = NULL;
292                 ret->ext_be = NULL;
293                 ret->ext_next = NULL;
294         }
295
296         return ret;
297 }
298
299
300 /*********************************************************************
301  * Function Name:      slapi_int_unregister_extop
302  *
303  * Description:        This routine removes the ExtendedOp structures 
304  *                                         asscoiated with a particular extended operation 
305  *                                         plugin.
306  *
307  * Input:              pBE - pointer to a backend structure
308  *                     opList - pointer to a linked list of extended
309  *                              operation structures
310  *                     pPB - pointer to a slapi parameter block
311  *
312  * Output:
313  *
314  * Return Value:       none
315  *
316  * Messages:           None
317  *********************************************************************/
318 void
319 slapi_int_unregister_extop(
320         Backend *pBE, 
321         ExtendedOp **opList, 
322         Slapi_PBlock *pPB )
323 {
324         ExtendedOp      *pTmpExtOp, *backExtOp;
325         char            **pTmpOIDs;
326         int             i;
327
328 #if 0
329         assert( pBE != NULL); /* unused */
330 #endif /* 0 */
331         assert( opList != NULL );
332         assert( pPB != NULL );
333
334         if ( *opList == NULL ) {
335                 return;
336         }
337
338         slapi_pblock_get( pPB, SLAPI_PLUGIN_EXT_OP_OIDLIST, &pTmpOIDs );
339         if ( pTmpOIDs == NULL ) {
340                 return;
341         }
342
343         for ( i = 0; pTmpOIDs[i] != NULL; i++ ) {
344                 backExtOp = NULL;
345                 pTmpExtOp = *opList;
346                 for ( ; pTmpExtOp != NULL; pTmpExtOp = pTmpExtOp->ext_next) {
347                         int     rc;
348                         rc = strcasecmp( pTmpExtOp->ext_oid.bv_val,
349                                         pTmpOIDs[ i ] );
350                         if ( rc == 0 ) {
351                                 if ( backExtOp == NULL ) {
352                                         *opList = pTmpExtOp->ext_next;
353                                 } else {
354                                         backExtOp->ext_next
355                                                 = pTmpExtOp->ext_next;
356                                 }
357
358                                 ch_free( pTmpExtOp );
359                                 break;
360                         }
361                         backExtOp = pTmpExtOp;
362                 }
363         }
364 }
365
366
367 /*********************************************************************
368  * Function Name:      slapi_int_register_extop
369  *
370  * Description:        This routine creates a new ExtendedOp structure, loads
371  *                     in the extended op module and put the extended op function address
372  *                     in the structure. The function will not be executed in
373  *                     this routine.
374  *
375  * Input:              pBE - pointer to a backend structure
376  *                     opList - pointer to a linked list of extended
377  *                              operation structures
378  *                     pPB - pointer to a slapi parameter block
379  *
380  * Output:
381  *
382  * Return Value:       an LDAP return code
383  *
384  * Messages:           None
385  *********************************************************************/
386 int 
387 slapi_int_register_extop(
388         Backend *pBE,   
389         ExtendedOp **opList, 
390         Slapi_PBlock *pPB )
391 {
392         ExtendedOp      *pTmpExtOp = NULL;
393         SLAPI_FUNC      tmpFunc;
394         char            **pTmpOIDs;
395         int             rc = LDAP_OTHER;
396         int             i;
397
398         if ( (*opList) == NULL ) { 
399                 *opList = createExtendedOp();
400                 if ( (*opList) == NULL ) {
401                         rc = LDAP_NO_MEMORY;
402                         goto error_return;
403                 }
404                 pTmpExtOp = *opList;
405                 
406         } else {                        /* Find the end of the list */
407                 for ( pTmpExtOp = *opList; pTmpExtOp->ext_next != NULL;
408                                 pTmpExtOp = pTmpExtOp->ext_next )
409                         ; /* EMPTY */
410                 pTmpExtOp->ext_next = createExtendedOp();
411                 if ( pTmpExtOp->ext_next == NULL ) {
412                         rc = LDAP_NO_MEMORY;
413                         goto error_return;
414                 }
415                 pTmpExtOp = pTmpExtOp->ext_next;
416         }
417
418         rc = slapi_pblock_get( pPB,SLAPI_PLUGIN_EXT_OP_OIDLIST, &pTmpOIDs );
419         if ( rc != 0 ) {
420                 rc = LDAP_OTHER;
421                 goto error_return;
422         }
423
424         rc = slapi_pblock_get(pPB,SLAPI_PLUGIN_EXT_OP_FN, &tmpFunc);
425         if ( rc != 0 ) {
426                 rc = LDAP_OTHER;
427                 goto error_return;
428         }
429
430         if ( (pTmpOIDs == NULL) || (tmpFunc == NULL) ) {
431                 rc = LDAP_OTHER;
432                 goto error_return;
433         }
434
435         for ( i = 0; pTmpOIDs[i] != NULL; i++ ) {
436                 pTmpExtOp->ext_oid.bv_val = pTmpOIDs[i];
437                 pTmpExtOp->ext_oid.bv_len = strlen( pTmpOIDs[i] );
438                 pTmpExtOp->ext_func = tmpFunc;
439                 pTmpExtOp->ext_be = pBE;
440                 if ( pTmpOIDs[i + 1] != NULL ) {
441                         pTmpExtOp->ext_next = createExtendedOp();
442                         if ( pTmpExtOp->ext_next == NULL ) {
443                                 rc = LDAP_NO_MEMORY;
444                                 break;
445                         }
446                         pTmpExtOp = pTmpExtOp->ext_next;
447                 }
448         }
449
450 error_return:
451         return rc;
452 }
453
454 /*********************************************************************
455  * Function Name:      slapi_int_get_extop_plugin
456  *
457  * Description:        This routine gets the function address for a given function
458  *                     name.
459  *
460  * Input:
461  *                     funcName - name of the extended op function, ie. an OID.
462  *
463  * Output:             pFuncAddr - the function address of the requested function name.
464  *
465  * Return Values:      a pointer to a newly created ExtendOp structrue or
466  *                     NULL - function failed
467  *
468  * Messages:           None
469  *********************************************************************/
470 int 
471 slapi_int_get_extop_plugin(
472         struct berval *reqoid,          
473         SLAPI_FUNC *pFuncAddr ) 
474 {
475         ExtendedOp      *pTmpExtOp;
476
477         assert( reqoid != NULL );
478         assert( pFuncAddr != NULL );
479
480         *pFuncAddr = NULL;
481
482         if ( pGExtendedOps == NULL ) {
483                 return LDAP_OTHER;
484         }
485
486         pTmpExtOp = pGExtendedOps;
487         while ( pTmpExtOp != NULL ) {
488                 int     rc;
489                 
490                 rc = strcasecmp( reqoid->bv_val, pTmpExtOp->ext_oid.bv_val );
491                 if ( rc == 0 ) {
492                         *pFuncAddr = pTmpExtOp->ext_func;
493                         break;
494                 }
495                 pTmpExtOp = pTmpExtOp->ext_next;
496         }
497
498         return ( *pFuncAddr == NULL ? 1 : 0 );
499 }
500
501 /***************************************************************************
502  * This function is similar to slapi_int_get_extop_plugin above. except it returns one OID
503  * per call. It is called from root_dse_info (root_dse.c).
504  * The function is a modified version of get_supported_extop (file extended.c).
505  ***************************************************************************/
506 struct berval *
507 slapi_int_get_supported_extop( int index )
508 {
509         ExtendedOp      *ext;
510
511         for ( ext = pGExtendedOps ; ext != NULL && --index >= 0;
512                         ext = ext->ext_next) {
513                 ; /* empty */
514         }
515
516         if ( ext == NULL ) {
517                 return NULL;
518         }
519
520         return &ext->ext_oid ;
521 }
522
523 /*********************************************************************
524  * Function Name:      slapi_int_load_plugin
525  *
526  * Description:        This routine loads the specified DLL, gets and executes the init function
527  *                     if requested.
528  *
529  * Input:
530  *                     pPlugin - a pointer to a Slapi_PBlock struct which will be passed to
531  *                               the DLL init function.
532  *                     path - path name of the DLL to be load.
533  *                     initfunc - either the DLL initialization function or an OID of the
534  *                                loaded extended operation.
535  *                     doInit - if it is TRUE, execute the init function, otherwise, save the
536  *                              function address but not execute it.
537  *
538  * Output:             pInitFunc - the function address of the loaded function. This param
539  *                                 should be not be null if doInit is FALSE.
540  *                     pLdHandle - handle returned by lt_dlopen()
541  *
542  * Return Values:      LDAP_SUCCESS, LDAP_LOCAL_ERROR
543  *
544  * Messages:           None
545  *********************************************************************/
546
547 static int 
548 slapi_int_load_plugin(
549         Slapi_PBlock    *pPlugin,
550         const char      *path,
551         const char      *initfunc, 
552         int             doInit,
553         SLAPI_FUNC      *pInitFunc,
554         lt_dlhandle     *pLdHandle ) 
555 {
556         int             rc = LDAP_SUCCESS;
557         SLAPI_FUNC      fpInitFunc = NULL;
558
559         assert( pLdHandle != NULL );
560
561         if ( lt_dlinit() ) {
562                 return LDAP_LOCAL_ERROR;
563         }
564
565         /* load in the module */
566         *pLdHandle = lt_dlopen( path );
567         if ( *pLdHandle == NULL ) {
568                 return LDAP_LOCAL_ERROR;
569         }
570
571         fpInitFunc = (SLAPI_FUNC)lt_dlsym( *pLdHandle, initfunc );
572         if ( fpInitFunc == NULL ) {
573                 lt_dlclose( *pLdHandle );
574                 return LDAP_LOCAL_ERROR;
575         }
576
577         if ( doInit ) {
578                 rc = ( *fpInitFunc )( pPlugin );
579                 if ( rc != LDAP_SUCCESS ) {
580                         lt_dlclose( *pLdHandle );
581                 }
582
583         } else {
584                 *pInitFunc = fpInitFunc;
585         }
586
587         return rc;
588 }
589
590 /*
591  * Special support for computed attribute plugins
592  */
593 int 
594 slapi_int_call_plugins(
595         Backend         *be,    
596         int             funcType, 
597         Slapi_PBlock    *pPB )
598 {
599
600         int rc = 0;
601         SLAPI_FUNC *pGetPlugin = NULL, *tmpPlugin = NULL; 
602
603         if ( pPB == NULL ) {
604                 return 1;
605         }
606
607         rc = slapi_int_get_plugins( be, funcType, &tmpPlugin );
608         if ( rc != LDAP_SUCCESS || tmpPlugin == NULL ) {
609                 /* Nothing to do, front-end should ignore. */
610                 return 1;
611         }
612
613         for ( pGetPlugin = tmpPlugin ; *pGetPlugin != NULL; pGetPlugin++ ) {
614                 /*
615                  * FIXME: we should provide here a sort of sandbox,
616                  * to protect from plugin faults; e.g. trap signals
617                  * and longjump here, marking the plugin as unsafe for
618                  * later executions ...
619                  */
620                 rc = (*pGetPlugin)(pPB);
621
622                 /*
623                  * Only non-postoperation plugins abort processing on
624                  * failure (confirmed with SLAPI specification).
625                  */
626                 if ( !SLAPI_PLUGIN_IS_POST_FN( funcType ) && rc != 0 ) {
627                         /*
628                          * Plugins generally return negative error codes
629                          * to indicate failure, although in the case of
630                          * bind plugins they may return SLAPI_BIND_xxx
631                          */
632                         break;
633                 }
634         }
635
636         slapi_ch_free( (void **)&tmpPlugin );
637
638         return rc;
639 }
640
641 int
642 slapi_int_read_config(
643         Backend         *be,            
644         const char      *fname, 
645         int             lineno, 
646         int             argc, 
647         char            **argv )
648 {
649         int             iType = -1;
650         int             numPluginArgc = 0;
651
652         if ( argc < 4 ) {
653                 fprintf( stderr,
654                         "%s: line %d: missing arguments "
655                         "in \"plugin <plugin_type> <lib_path> "
656                         "<init_function> [<arguments>]\" line\n",
657                         fname, lineno );
658                 return 1;
659         }
660
661         /* automatically instantiate overlay if necessary */
662         if ( !overlay_is_inst( be, SLAPI_OVERLAY_NAME ) ) {
663                 if ( overlay_config( be, SLAPI_OVERLAY_NAME ) != 0 ) {
664                         fprintf( stderr, "Failed to instantiate SLAPI overlay\n");
665                         return -1;
666                 }
667         }
668         
669         if ( strcasecmp( argv[1], "preoperation" ) == 0 ) {
670                 iType = SLAPI_PLUGIN_PREOPERATION;
671         } else if ( strcasecmp( argv[1], "postoperation" ) == 0 ) {
672                 iType = SLAPI_PLUGIN_POSTOPERATION;
673         } else if ( strcasecmp( argv[1], "extendedop" ) == 0 ) {
674                 iType = SLAPI_PLUGIN_EXTENDEDOP;
675         } else if ( strcasecmp( argv[1], "object" ) == 0 ) {
676                 iType = SLAPI_PLUGIN_OBJECT;
677         } else {
678                 fprintf( stderr, "%s: line %d: invalid plugin type \"%s\".\n",
679                                 fname, lineno, argv[1] );
680                 return 1;
681         }
682         
683         numPluginArgc = argc - 4;
684
685         if ( iType == SLAPI_PLUGIN_PREOPERATION ||
686                         iType == SLAPI_PLUGIN_EXTENDEDOP ||
687                         iType == SLAPI_PLUGIN_POSTOPERATION ||
688                         iType == SLAPI_PLUGIN_OBJECT ) {
689                 int rc;
690                 Slapi_PBlock *pPlugin;
691
692                 pPlugin = plugin_pblock_new( iType, numPluginArgc, argv );
693                 if (pPlugin == NULL) {
694                         return 1;
695                 }
696
697                 if (iType == SLAPI_PLUGIN_EXTENDEDOP) {
698                         rc = slapi_int_register_extop(be, &pGExtendedOps, pPlugin);
699                         if ( rc != LDAP_SUCCESS ) {
700                                 slapi_pblock_destroy( pPlugin );
701                                 return 1;
702                         }
703                 }
704
705                 rc = slapi_int_register_plugin( be, pPlugin );
706                 if ( rc != LDAP_SUCCESS ) {
707                         if ( iType == SLAPI_PLUGIN_EXTENDEDOP ) {
708                                 slapi_int_unregister_extop( be, &pGExtendedOps, pPlugin );
709                         }
710                         slapi_pblock_destroy( pPlugin );
711                         return 1;
712                 }
713         }
714
715         return 0;
716 }
717
718 void
719 slapi_int_plugin_unparse(
720         Backend *be,
721         BerVarray *out
722 )
723 {
724         Slapi_PBlock *pp;
725         int i, j;
726         char **argv, ibuf[32], *ptr;
727         struct berval idx, bv;
728
729         *out = NULL;
730         idx.bv_val = ibuf;
731         i = 0;
732
733         for ( pp = be->be_pb;
734               pp != NULL;
735               slapi_pblock_get( pp, SLAPI_IBM_PBLOCK, &pp ) )
736         {
737                 slapi_pblock_get( pp, SLAPI_X_CONFIG_ARGV, &argv );
738                 if ( argv == NULL ) /* could be dynamic plugin */
739                         continue;
740                 idx.bv_len = sprintf( idx.bv_val, "{%d}", i );
741                 bv.bv_len = idx.bv_len;
742                 for (j=1; argv[j]; j++) {
743                         bv.bv_len += strlen(argv[j]);
744                         if ( j ) bv.bv_len++;
745                 }
746                 bv.bv_val = ch_malloc( bv.bv_len + 1 );
747                 ptr = lutil_strcopy( bv.bv_val, ibuf );
748                 for (j=1; argv[j]; j++) {
749                         if ( j ) *ptr++ = ' ';
750                         ptr = lutil_strcopy( ptr, argv[j] );
751                 }
752                 ber_bvarray_add( out, &bv );
753         }
754 }
755
756 int
757 slapi_int_initialize(void)
758 {
759         if ( ldap_pvt_thread_mutex_init( &slapi_hn_mutex ) ) {
760                 return -1;
761         }
762         
763         if ( ldap_pvt_thread_mutex_init( &slapi_time_mutex ) ) {
764                 return -1;
765         }
766
767         if ( ldap_pvt_thread_mutex_init( &slapi_printmessage_mutex ) ) {
768                 return -1;
769         }
770
771         slapi_log_file = ch_strdup( LDAP_RUNDIR LDAP_DIRSEP "errors" );
772         if ( slapi_log_file == NULL ) {
773                 return -1;
774         }
775
776         if ( slapi_int_init_object_extensions() != 0 ) {
777                 return -1;
778         }
779
780         return slapi_int_overlay_init();
781 }