]> git.sur5r.net Git - openldap/blob - servers/slapd/slapi/plugin.c
Confusingly, make SLAPI_OPERATION_AUTHTYPE return a pointer to
[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         assert( be );
177         assert( ppFuncPtrs );
178
179         pCurrentPB = (Slapi_PBlock *)(be->be_pb);
180      
181         if ( pCurrentPB == NULL ) { 
182                 /*
183                  * LDAP_OTHER is returned if no plugins are installed
184                  */
185                 rc = LDAP_OTHER;
186                 goto done;
187         }
188
189         while ( pCurrentPB != NULL && rc == LDAP_SUCCESS ) {
190                 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
191                 if ( rc == LDAP_SUCCESS ) {
192                         if ( FuncPtr != NULL )  {
193                                 numPB++;
194                         }
195                         rc = slapi_pblock_get( pCurrentPB,
196                                         SLAPI_IBM_PBLOCK, &pCurrentPB );
197                 }
198         }
199
200         if ( rc != LDAP_SUCCESS ) {
201                 goto done;
202         }
203
204         if ( numPB == 0 ) {
205                 *ppFuncPtrs = NULL;
206                 rc = LDAP_SUCCESS;
207                 goto done;
208         }
209
210         *ppFuncPtrs = pTmpFuncPtr = 
211                 (SLAPI_FUNC *)ch_malloc( ( numPB + 1 ) * sizeof(SLAPI_FUNC) ); 
212         if ( ppFuncPtrs == NULL ) {
213                 rc = LDAP_NO_MEMORY;
214                 goto done;
215         }
216
217         pCurrentPB = (Slapi_PBlock *)(be->be_pb);
218         while ( pCurrentPB != NULL && rc == LDAP_SUCCESS )  {
219                 rc = slapi_pblock_get( pCurrentPB, functype, &FuncPtr );
220                 if ( rc == LDAP_SUCCESS ) {
221                         if ( FuncPtr != NULL )  {
222                                 *pTmpFuncPtr = FuncPtr;
223                                 pTmpFuncPtr++;
224                         } 
225                         rc = slapi_pblock_get( pCurrentPB,
226                                         SLAPI_IBM_PBLOCK, &pCurrentPB );
227                 }
228         }
229         *pTmpFuncPtr = NULL ;
230
231 done:
232         if ( rc != LDAP_SUCCESS && *ppFuncPtrs != NULL ) {
233                 ch_free( *ppFuncPtrs );
234                 *ppFuncPtrs = NULL;
235         }
236
237         return rc;
238 }
239               
240 /*********************************************************************
241  * Function Name:      createExtendedOp
242  *
243  * Description: Creates an extended operation structure and
244  *              initializes the fields
245  *
246  * Return value: A newly allocated structure or NULL
247  ********************************************************************/
248 ExtendedOp *
249 createExtendedOp()
250 {
251         ExtendedOp *ret;
252
253         ret = (ExtendedOp *)ch_malloc(sizeof(ExtendedOp));
254         if ( ret != NULL ) {
255                 ret->ext_oid.bv_val = NULL;
256                 ret->ext_oid.bv_len = 0;
257                 ret->ext_func = NULL;
258                 ret->ext_be = NULL;
259                 ret->ext_next = NULL;
260         }
261
262         return ret;
263 }
264
265
266 /*********************************************************************
267  * Function Name:      removeExtendedOp
268  *
269  * Description:        This routine removes the ExtendedOp structures 
270  *                                         asscoiated with a particular extended operation 
271  *                                         plugin.
272  *
273  * Input:              pBE - pointer to a backend structure
274  *                     opList - pointer to a linked list of extended
275  *                              operation structures
276  *                     pPB - pointer to a slapi parameter block
277  *
278  * Output:
279  *
280  * Return Value:       none
281  *
282  * Messages:           None
283  *********************************************************************/
284 void
285 removeExtendedOp(
286         Backend *pBE, 
287         ExtendedOp **opList, 
288         Slapi_PBlock *pPB )
289 {
290         ExtendedOp      *pTmpExtOp, *backExtOp;
291         char            **pTmpOIDs;
292         int             i;
293
294 #if 0
295         assert( pBE != NULL); /* unused */
296 #endif /* 0 */
297         assert( opList != NULL );
298         assert( pPB != NULL );
299
300         if ( *opList == NULL ) {
301                 return;
302         }
303
304         slapi_pblock_get( pPB, SLAPI_PLUGIN_EXT_OP_OIDLIST, &pTmpOIDs );
305         if ( pTmpOIDs == NULL ) {
306                 return;
307         }
308
309         for ( i = 0; pTmpOIDs[i] != NULL; i++ ) {
310                 backExtOp = NULL;
311                 pTmpExtOp = *opList;
312                 for ( ; pTmpExtOp != NULL; pTmpExtOp = pTmpExtOp->ext_next) {
313                         int     rc;
314                         rc = strcasecmp( pTmpExtOp->ext_oid.bv_val,
315                                         pTmpOIDs[ i ] );
316                         if ( rc == 0 ) {
317                                 if ( backExtOp == NULL ) {
318                                         *opList = pTmpExtOp->ext_next;
319                                 } else {
320                                         backExtOp->ext_next
321                                                 = pTmpExtOp->ext_next;
322                                 }
323
324                                 ch_free( pTmpExtOp );
325                                 break;
326                         }
327                         backExtOp = pTmpExtOp;
328                 }
329         }
330 }
331
332
333 /*********************************************************************
334  * Function Name:      newExtendedOp
335  *
336  * Description:        This routine creates a new ExtendedOp structure, loads
337  *                     in the extended op module and put the extended op function address
338  *                     in the structure. The function will not be executed in
339  *                     this routine.
340  *
341  * Input:              pBE - pointer to a backend structure
342  *                     opList - pointer to a linked list of extended
343  *                              operation structures
344  *                     pPB - pointer to a slapi parameter block
345  *
346  * Output:
347  *
348  * Return Value:       an LDAP return code
349  *
350  * Messages:           None
351  *********************************************************************/
352 int 
353 newExtendedOp(
354         Backend *pBE,   
355         ExtendedOp **opList, 
356         Slapi_PBlock *pPB )
357 {
358         ExtendedOp      *pTmpExtOp = NULL;
359         SLAPI_FUNC      tmpFunc;
360         char            **pTmpOIDs;
361         int             rc = LDAP_OTHER;
362         int             i;
363
364         if ( (*opList) == NULL ) { 
365                 *opList = createExtendedOp();
366                 if ( (*opList) == NULL ) {
367                         rc = LDAP_NO_MEMORY;
368                         goto error_return;
369                 }
370                 pTmpExtOp = *opList;
371                 
372         } else {                        /* Find the end of the list */
373                 for ( pTmpExtOp = *opList; pTmpExtOp->ext_next != NULL;
374                                 pTmpExtOp = pTmpExtOp->ext_next )
375                         ; /* EMPTY */
376                 pTmpExtOp->ext_next = createExtendedOp();
377                 if ( pTmpExtOp->ext_next == NULL ) {
378                         rc = LDAP_NO_MEMORY;
379                         goto error_return;
380                 }
381                 pTmpExtOp = pTmpExtOp->ext_next;
382         }
383
384         rc = slapi_pblock_get( pPB,SLAPI_PLUGIN_EXT_OP_OIDLIST, &pTmpOIDs );
385         if ( rc != LDAP_SUCCESS ) {
386                 rc = LDAP_OTHER;
387                 goto error_return;
388         }
389
390         rc = slapi_pblock_get(pPB,SLAPI_PLUGIN_EXT_OP_FN, &tmpFunc);
391         if ( rc != 0 ) {
392                 rc = LDAP_OTHER;
393                 goto error_return;
394         }
395
396         if ( (pTmpOIDs == NULL) || (tmpFunc == NULL) ) {
397                 rc = LDAP_OTHER;
398                 goto error_return;
399         }
400
401         for ( i = 0; pTmpOIDs[i] != NULL; i++ ) {
402                 pTmpExtOp->ext_oid.bv_val = pTmpOIDs[i];
403                 pTmpExtOp->ext_oid.bv_len = strlen( pTmpOIDs[i] );
404                 pTmpExtOp->ext_func = tmpFunc;
405                 pTmpExtOp->ext_be = pBE;
406                 if ( pTmpOIDs[i + 1] != NULL ) {
407                         pTmpExtOp->ext_next = createExtendedOp();
408                         if ( pTmpExtOp->ext_next == NULL ) {
409                                 rc = LDAP_NO_MEMORY;
410                                 break;
411                         }
412                         pTmpExtOp = pTmpExtOp->ext_next;
413                 }
414         }
415
416 error_return:
417         return rc;
418 }
419
420 /*********************************************************************
421  * Function Name:      getPluginFunc
422  *
423  * Description:        This routine gets the function address for a given function
424  *                     name.
425  *
426  * Input:
427  *                     funcName - name of the extended op function, ie. an OID.
428  *
429  * Output:             pFuncAddr - the function address of the requested function name.
430  *
431  * Return Values:      a pointer to a newly created ExtendOp structrue or
432  *                     NULL - function failed
433  *
434  * Messages:           None
435  *********************************************************************/
436 int 
437 getPluginFunc(
438         struct berval *reqoid,          
439         SLAPI_FUNC *pFuncAddr ) 
440 {
441         ExtendedOp      *pTmpExtOp;
442
443         assert( reqoid != NULL );
444         assert( pFuncAddr != NULL );
445
446         *pFuncAddr = NULL;
447
448         if ( pGExtendedOps == NULL ) {
449                 return LDAP_OTHER;
450         }
451
452         pTmpExtOp = pGExtendedOps;
453         while ( pTmpExtOp != NULL ) {
454                 int     rc;
455                 
456                 rc = strcasecmp( reqoid->bv_val, pTmpExtOp->ext_oid.bv_val );
457                 if ( rc == 0 ) {
458                         *pFuncAddr = pTmpExtOp->ext_func;
459                         break;
460                 }
461                 pTmpExtOp = pTmpExtOp->ext_next;
462         }
463
464         return ( *pFuncAddr == NULL ? 1 : 0 );
465 }
466
467 /***************************************************************************
468  * This function is similar to getPluginFunc above. except it returns one OID
469  * per call. It is called from root_dse_info (root_dse.c).
470  * The function is a modified version of get_supported_extop (file extended.c).
471  ***************************************************************************/
472 struct berval *
473 ns_get_supported_extop( int index )
474 {
475         ExtendedOp      *ext;
476
477         for ( ext = pGExtendedOps ; ext != NULL && --index >= 0;
478                         ext = ext->ext_next) {
479                 ; /* empty */
480         }
481
482         if ( ext == NULL ) {
483                 return NULL;
484         }
485
486         return &ext->ext_oid ;
487 }
488
489 /*********************************************************************
490  * Function Name:      loadPlugin
491  *
492  * Description:        This routine loads the specified DLL, gets and executes the init function
493  *                     if requested.
494  *
495  * Input:
496  *                     pPlugin - a pointer to a Slapi_PBlock struct which will be passed to
497  *                               the DLL init function.
498  *                     path - path name of the DLL to be load.
499  *                     initfunc - either the DLL initialization function or an OID of the
500  *                                loaded extended operation.
501  *                     doInit - if it is TRUE, execute the init function, otherwise, save the
502  *                              function address but not execute it.
503  *
504  * Output:             pInitFunc - the function address of the loaded function. This param
505  *                                 should be not be null if doInit is FALSE.
506  *                     pLdHandle - handle returned by lt_dlopen()
507  *
508  * Return Values:      LDAP_SUCCESS, LDAP_LOCAL_ERROR
509  *
510  * Messages:           None
511  *********************************************************************/
512
513 static int 
514 loadPlugin(
515         Slapi_PBlock    *pPlugin,
516         const char      *path,
517         const char      *initfunc, 
518         int             doInit,
519         SLAPI_FUNC      *pInitFunc,
520         lt_dlhandle     *pLdHandle ) 
521 {
522         int             rc = LDAP_SUCCESS;
523         SLAPI_FUNC      fpInitFunc = NULL;
524
525         assert( pLdHandle );
526
527         if ( lt_dlinit() ) {
528                 return LDAP_LOCAL_ERROR;
529         }
530
531         /* load in the module */
532         *pLdHandle = lt_dlopen( path );
533         if ( *pLdHandle == NULL ) {
534                 return LDAP_LOCAL_ERROR;
535         }
536
537         fpInitFunc = (SLAPI_FUNC)lt_dlsym( *pLdHandle, initfunc );
538         if ( fpInitFunc == NULL ) {
539                 lt_dlclose( *pLdHandle );
540                 return LDAP_LOCAL_ERROR;
541         }
542
543         if ( doInit == TRUE ) {
544                 rc = ( *fpInitFunc )( pPlugin );
545                 if ( rc != LDAP_SUCCESS ) {
546                         lt_dlclose( *pLdHandle );
547                 }
548
549         } else {
550                 *pInitFunc = fpInitFunc;
551         }
552
553         return rc;
554 }
555
556
557 int 
558 doPluginFNs(
559         Backend         *be,    
560         int             funcType, 
561         Slapi_PBlock    *pPB )
562 {
563
564         int rc = LDAP_SUCCESS;
565         SLAPI_FUNC *pGetPlugin = NULL, *tmpPlugin = NULL; 
566
567         rc = getAllPluginFuncs(be, funcType, &tmpPlugin );
568         if ( rc != LDAP_SUCCESS || tmpPlugin == NULL ) {
569                 return rc;
570         }
571
572         for ( pGetPlugin = tmpPlugin ; *pGetPlugin != NULL; pGetPlugin++ ) {
573                 /*
574                  * FIXME: we should provide here a sort of sandbox,
575                  * to protect from plugin faults; e.g. trap signals
576                  * and longjump here, marking the plugin as unsafe for
577                  * later executions ...
578                  */
579                 rc = (*pGetPlugin)(pPB);
580
581                 /*
582                  * Only non-postoperation plugins abort processing on
583                  * failure (confirmed with SLAPI specification).
584                  */
585                 if ( !SLAPI_PLUGIN_IS_POST_FN( funcType ) && rc != 0 ) {
586                         break;
587                 }
588         }
589
590         ch_free( tmpPlugin );
591
592         return rc;
593 }
594
595 int
596 netscape_plugin(
597         Backend         *be,            
598         const char      *fname, 
599         int             lineno, 
600         int             argc, 
601         char            **argv )
602 {
603         int             iType = -1;
604         int             numPluginArgc = 0;
605         char            **ppPluginArgv = NULL;
606
607         if ( argc < 4 ) {
608                 fprintf( stderr,
609                         "%s: line %d: missing arguments "
610                         "in \"plugin <plugin_type> <lib_path> "
611                         "<init_function> [<arguments>]\" line\n",
612                         fname, lineno );
613                 return 1;
614         }
615         
616         if ( strcasecmp( argv[1], "preoperation" ) == 0 ) {
617                 iType = SLAPI_PLUGIN_PREOPERATION;
618         } else if ( strcasecmp( argv[1], "postoperation" ) == 0 ) {
619                 iType = SLAPI_PLUGIN_POSTOPERATION;
620         } else if ( strcasecmp( argv[1], "extendedop" ) == 0 ) {
621                 iType = SLAPI_PLUGIN_EXTENDEDOP;
622         } else {
623                 fprintf( stderr, "%s: line %d: invalid plugin type \"%s\".\n",
624                                 fname, lineno, argv[1] );
625                 return 1;
626         }
627         
628         numPluginArgc = argc - 4;
629         if ( numPluginArgc > 0 ) {
630                 ppPluginArgv = &argv[4];
631         } else {
632                 ppPluginArgv = NULL;
633         }
634
635         if ( iType == SLAPI_PLUGIN_PREOPERATION ||
636                         iType == SLAPI_PLUGIN_EXTENDEDOP ||
637                         iType == SLAPI_PLUGIN_POSTOPERATION ) {
638                 int rc;
639                 Slapi_PBlock *pPlugin;
640
641                 pPlugin = newPlugin( iType, argv[2], argv[3], 
642                                         numPluginArgc, ppPluginArgv );
643                 if (pPlugin == NULL) {
644                         return 1;
645                 }
646
647                 if (iType == SLAPI_PLUGIN_EXTENDEDOP) {
648                         rc = newExtendedOp(be, &pGExtendedOps, pPlugin);
649                         if ( rc != LDAP_SUCCESS ) {
650                                 slapi_pblock_destroy( pPlugin );
651                                 return 1;
652                         }
653                 }
654
655                 rc = insertPlugin( be, pPlugin );
656                 if ( rc != LDAP_SUCCESS ) {
657                         if ( iType == SLAPI_PLUGIN_EXTENDEDOP ) {
658                                 removeExtendedOp( be, &pGExtendedOps, pPlugin );
659                         }
660                         slapi_pblock_destroy( pPlugin );
661                         return 1;
662                 }
663         }
664
665         return 0;
666 }
667
668 int
669 slapi_init(void)
670 {
671         if ( ldap_pvt_thread_mutex_init( &slapi_hn_mutex ) ) {
672                 return -1;
673         }
674         
675         if ( ldap_pvt_thread_mutex_init( &slapi_time_mutex ) ) {
676                 return -1;
677         }
678
679         if ( ldap_pvt_thread_mutex_init( &slapi_printmessage_mutex ) ) {
680                 return -1;
681         }
682
683         slapi_log_file = ch_strdup( LDAP_RUNDIR LDAP_DIRSEP "errors" );
684         if ( slapi_log_file == NULL ) {
685                 return -1;
686         }
687
688         return 0;
689 }
690