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