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