]> git.sur5r.net Git - openldap/blob - servers/slapd/back-monitor/database.c
e304c09e45b6579fd5a01ed95a7c1ea3bf2fc4cc
[openldap] / servers / slapd / back-monitor / database.c
1 /* database.c - deals with database subsystem */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2001-2004 The OpenLDAP Foundation.
6  * Portions Copyright 2001-2003 Pierangelo Masarati.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* ACKNOWLEDGEMENTS:
18  * This work was initially developed by Pierangelo Masarati for inclusion
19  * in OpenLDAP Software.
20  */
21
22 #include "portable.h"
23
24 #include <stdio.h>
25 #include <ac/string.h>
26
27 #include "slap.h"
28 #include "back-monitor.h"
29
30 #if defined(LDAP_SLAPI)
31 #include "slapi.h"
32 static int monitor_back_add_plugin( Backend *be, Entry *e );
33 #endif /* defined(LDAP_SLAPI) */
34
35 #if defined(SLAPD_LDAP) 
36 #include "../back-ldap/back-ldap.h"
37 #endif /* defined(SLAPD_LDAP) */
38
39 static struct restricted_ops_t {
40         struct berval   op;
41         unsigned int    tag;
42 } restricted_ops[] = {
43         { BER_BVC( "add" ),                     SLAP_RESTRICT_OP_ADD },
44         { BER_BVC( "bind" ),                    SLAP_RESTRICT_OP_BIND },
45         { BER_BVC( "compare" ),                 SLAP_RESTRICT_OP_COMPARE },
46         { BER_BVC( "delete" ),                  SLAP_RESTRICT_OP_DELETE },
47         { BER_BVC( "extended" ),                SLAP_RESTRICT_OP_EXTENDED },
48         { BER_BVC( "modify" ),                  SLAP_RESTRICT_OP_MODIFY },
49         { BER_BVC( "rename" ),                  SLAP_RESTRICT_OP_RENAME },
50         { BER_BVC( "search" ),                  SLAP_RESTRICT_OP_SEARCH },
51         { BER_BVNULL,                           0 }
52 }, restricted_exops[] = {
53         { BER_BVC( LDAP_EXOP_START_TLS ),       SLAP_RESTRICT_EXOP_START_TLS },
54         { BER_BVC( LDAP_EXOP_MODIFY_PASSWD ),   SLAP_RESTRICT_EXOP_MODIFY_PASSWD },
55         { BER_BVC( LDAP_EXOP_X_WHO_AM_I ),      SLAP_RESTRICT_EXOP_WHOAMI },
56         { BER_BVC( LDAP_EXOP_X_CANCEL ),        SLAP_RESTRICT_EXOP_CANCEL },
57         { BER_BVNULL,                           0 }
58 };
59
60 static int
61 init_readOnly( struct monitorinfo *mi, Entry *e, slap_mask_t restrictops )
62 {
63         struct berval   *tf = ( ( restrictops & SLAP_RESTRICT_OP_MASK ) == SLAP_RESTRICT_OP_WRITES ) ?
64                 (struct berval *)&slap_true_bv : (struct berval *)&slap_false_bv;
65
66         return attr_merge_one( e, mi->mi_ad_readOnly, tf, NULL );
67 }
68
69 static int
70 init_restrictedOperation( struct monitorinfo *mi, Entry *e, slap_mask_t restrictops )
71 {
72         int     i, rc;
73
74         for ( i = 0; restricted_ops[ i ].op.bv_val; i++ ) {
75                 if ( restrictops & restricted_ops[ i ].tag ) {
76                         rc = attr_merge_one( e, mi->mi_ad_restrictedOperation,
77                                         &restricted_ops[ i ].op, NULL );
78                         if ( rc ) {
79                                 return rc;
80                         }
81                 }
82         }
83
84         for ( i = 0; restricted_exops[ i ].op.bv_val; i++ ) {
85                 if ( restrictops & restricted_exops[ i ].tag ) {
86                         rc = attr_merge_one( e, mi->mi_ad_restrictedOperation,
87                                         &restricted_exops[ i ].op, NULL );
88                         if ( rc ) {
89                                 return rc;
90                         }
91                 }
92         }
93
94         return LDAP_SUCCESS;
95 }
96
97 int
98 monitor_subsys_database_init(
99         BackendDB       *be
100 )
101 {
102         struct monitorinfo      *mi;
103         Entry                   *e_database, **ep;
104         int                     i;
105         struct monitorentrypriv *mp;
106
107         assert( be != NULL );
108
109         mi = ( struct monitorinfo * )be->be_private;
110
111         if ( monitor_cache_get( mi, 
112                                 &monitor_subsys[SLAPD_MONITOR_DATABASE].mss_ndn, 
113                                 &e_database ) )
114         {
115                 Debug( LDAP_DEBUG_ANY,
116                         "monitor_subsys_database_init: "
117                         "unable to get entry \"%s\"\n",
118                         monitor_subsys[SLAPD_MONITOR_DATABASE].mss_ndn.bv_val, 0, 0 );
119                 return( -1 );
120         }
121
122         (void)init_readOnly( mi, e_database, frontendDB->be_restrictops );
123         (void)init_restrictedOperation( mi, e_database, frontendDB->be_restrictops );
124
125         mp = ( struct monitorentrypriv * )e_database->e_private;
126         mp->mp_children = NULL;
127         ep = &mp->mp_children;
128
129         for ( i = 0; i < nBackendDB; i++ ) {
130                 char            buf[ BACKMONITOR_BUFSIZE ];
131                 int             j;
132                 slap_overinfo   *oi = NULL;
133                 BackendInfo     *bi;
134                 Entry           *e;
135
136                 be = &backendDB[i];
137
138                 bi = be->bd_info;
139
140                 if ( strcmp( be->bd_info->bi_type, "over" ) == 0 ) {
141                         oi = (slap_overinfo *)be->bd_info->bi_private;
142                         bi = oi->oi_orig;
143                 }
144
145                 /* Subordinates are not exposed as their own naming context */
146                 if ( SLAP_GLUE_SUBORDINATE( be ) ) {
147                         continue;
148                 }
149
150                 snprintf( buf, sizeof( buf ),
151                                 "dn: cn=Database %d,%s\n"
152                                 "objectClass: %s\n"
153                                 "structuralObjectClass: %s\n"
154                                 "cn: Database %d\n"
155                                 "description: This object contains the type of the database.\n"
156                                 "%s: %s\n"
157                                 "creatorsName: %s\n"
158                                 "modifiersName: %s\n"
159                                 "createTimestamp: %s\n"
160                                 "modifyTimestamp: %s\n",
161                                 i,
162                                 monitor_subsys[SLAPD_MONITOR_DATABASE].mss_dn.bv_val,
163                                 mi->mi_oc_monitoredObject->soc_cname.bv_val,
164                                 mi->mi_oc_monitoredObject->soc_cname.bv_val,
165                                 i,
166                                 mi->mi_ad_monitoredInfo->ad_cname.bv_val,
167                                 bi->bi_type,
168                                 mi->mi_creatorsName.bv_val,
169                                 mi->mi_creatorsName.bv_val,
170                                 mi->mi_startTime.bv_val,
171                                 mi->mi_startTime.bv_val );
172                 
173                 e = str2entry( buf );
174                 if ( e == NULL ) {
175                         Debug( LDAP_DEBUG_ANY,
176                                 "monitor_subsys_database_init: "
177                                 "unable to create entry \"cn=Database %d,%s\"\n",
178                                 i, monitor_subsys[SLAPD_MONITOR_DATABASE].mss_ndn.bv_val, 0 );
179                         return( -1 );
180                 }
181                 
182                 if ( SLAP_MONITOR(be) ) {
183                         attr_merge( e, slap_schema.si_ad_monitorContext,
184                                         be->be_suffix, be->be_nsuffix );
185                         attr_merge( e_database, slap_schema.si_ad_monitorContext,
186                                         be->be_suffix, be->be_nsuffix );
187                 } else {
188                         attr_merge( e, slap_schema.si_ad_namingContexts,
189                                         be->be_suffix, be->be_nsuffix );
190                         attr_merge( e_database, slap_schema.si_ad_namingContexts,
191                                         be->be_suffix, be->be_nsuffix );
192                 }
193
194                 (void)init_readOnly( mi, e, be->be_restrictops );
195                 (void)init_restrictedOperation( mi, e, be->be_restrictops );
196
197                 if ( oi != NULL ) {
198                         slap_overinst *on = oi->oi_list;
199
200                         for ( ; on; on = on->on_next ) {
201                                 struct berval           bv;
202                                 slap_overinst           *on2;
203                                 
204                                 bv.bv_val = on->on_bi.bi_type;
205                                 bv.bv_len = strlen( bv.bv_val );
206                                 attr_merge_normalize_one( e, mi->mi_ad_monitorOverlay,
207                                                 &bv, NULL );
208
209                                 for ( on2 = overlay_next( NULL ), j = 0; on2; on2 = overlay_next( on2 ), j++ ) {
210                                         if ( on2->on_bi.bi_type == on->on_bi.bi_type ) {
211                                                 break;
212                                         }
213                                 }
214                                 assert( on2 );
215
216                                 snprintf( buf, sizeof( buf ), 
217                                         "cn=Overlay %d,%s", 
218                                         j, monitor_subsys[SLAPD_MONITOR_OVERLAY].mss_dn.bv_val );
219                                 bv.bv_val = buf;
220                                 bv.bv_len = strlen( buf );
221                                 attr_merge_normalize_one( e, mi->mi_ad_seeAlso,
222                                                 &bv, NULL );
223                         }
224                 }
225
226 #if defined(SLAPD_LDAP) 
227                 if ( strcmp( bi->bi_type, "ldap" ) == 0 ) {
228                         struct ldapinfo         *li = (struct ldapinfo *)be->be_private;
229                         struct berval           bv;
230
231                         bv.bv_val = li->url;
232                         bv.bv_len = strlen( bv.bv_val );
233                         attr_merge_normalize_one( e, mi->mi_ad_labeledURI,
234                                         &bv, NULL );
235                 }
236 #endif /* defined(SLAPD_LDAP) */
237
238                 for ( j = 0; j < nBackendInfo; j++ ) {
239                         if ( backendInfo[ j ].bi_type == bi->bi_type ) {
240                                 struct berval           bv;
241
242                                 snprintf( buf, sizeof( buf ), 
243                                         "cn=Backend %d,%s", 
244                                         j, monitor_subsys[SLAPD_MONITOR_BACKEND].mss_dn.bv_val );
245                                 bv.bv_val = buf;
246                                 bv.bv_len = strlen( buf );
247                                 attr_merge_normalize_one( e, mi->mi_ad_seeAlso,
248                                                 &bv, NULL );
249                                 break;
250                         }
251                 }
252                 /* we must find it! */
253                 assert( j >= 0 );
254
255                 mp = ( struct monitorentrypriv * )ch_calloc( sizeof( struct monitorentrypriv ), 1 );
256                 e->e_private = ( void * )mp;
257                 mp->mp_next = NULL;
258                 mp->mp_children = NULL;
259                 mp->mp_info = &monitor_subsys[SLAPD_MONITOR_DATABASE];
260                 mp->mp_flags = monitor_subsys[SLAPD_MONITOR_DATABASE].mss_flags
261                         | MONITOR_F_SUB;
262
263                 if ( monitor_cache_add( mi, e ) ) {
264                         Debug( LDAP_DEBUG_ANY,
265                                 "monitor_subsys_database_init: "
266                                 "unable to add entry \"cn=Database %d,%s\"\n",
267                                 i, monitor_subsys[SLAPD_MONITOR_DATABASE].mss_ndn.bv_val, 0 );
268                         return( -1 );
269                 }
270
271 #if defined(LDAP_SLAPI)
272                 monitor_back_add_plugin( be, e );
273 #endif /* defined(LDAP_SLAPI) */
274
275                 *ep = e;
276                 ep = &mp->mp_next;
277         }
278         
279         monitor_cache_release( mi, e_database );
280
281         return( 0 );
282 }
283
284 /*
285  * v: array of values
286  * cur: must not contain the tags corresponding to the values in v
287  * delta: will contain the tags corresponding to the values in v
288  */
289 static int
290 value_mask( BerVarray v, slap_mask_t cur, slap_mask_t *delta )
291 {
292         for ( ; !BER_BVISNULL( v ); v++ ) {
293                 struct restricted_ops_t         *rops;
294                 int                             i;
295
296                 if ( OID_LEADCHAR( v->bv_val[ 0 ] ) ) {
297                         rops = restricted_exops;
298
299                 } else {
300                         rops = restricted_ops;
301                 }
302
303                 for ( i = 0; !BER_BVISNULL( &rops[ i ].op ); i++ ) {
304                         if ( ber_bvstrcasecmp( v, &rops[ i ].op ) != 0 ) {
305                                 continue;
306                         }
307
308                         if ( rops[ i ].tag & *delta ) {
309                                 return LDAP_OTHER;
310                         }
311
312                         if ( rops[ i ].tag & cur ) {
313                                 return LDAP_OTHER;
314                         }
315
316                         cur |= rops[ i ].tag;
317                         *delta |= rops[ i ].tag;
318
319                         break;
320                 }
321
322                 if ( BER_BVISNULL( &rops[ i ].op ) ) {
323                         return LDAP_INVALID_SYNTAX;
324                 }
325         }
326
327         return LDAP_SUCCESS;
328 }
329
330 int
331 monitor_subsys_database_modify(
332         Operation       *op,
333         Entry           *e
334 )
335 {
336         struct monitorinfo *mi = (struct monitorinfo *)op->o_bd->be_private;
337         int rc = LDAP_OTHER;
338         Attribute *save_attrs, *a;
339         Modifications *modlist = op->oq_modify.rs_modlist;
340         Modifications *ml;
341         Backend *be;
342         int ro_gotval = 1, i, n;
343         slap_mask_t     rp_add = 0, rp_delete = 0, rp_cur;
344         struct berval *tf;
345         
346         i = sscanf( e->e_nname.bv_val, "cn=database %d,", &n );
347         if ( i != 1 )
348                 return LDAP_UNWILLING_TO_PERFORM;
349
350         if ( n < 0 || n >= nBackendDB )
351                 return LDAP_NO_SUCH_OBJECT;
352
353         /* do not allow some changes on back-monitor (needs work)... */
354         be = &backendDB[n];
355         if ( SLAP_MONITOR( be ) )
356                 return LDAP_UNWILLING_TO_PERFORM;
357                 
358         rp_cur = be->be_restrictops;
359
360         save_attrs = e->e_attrs;
361         e->e_attrs = attrs_dup( e->e_attrs );
362
363         for ( ml=modlist; ml; ml=ml->sml_next ) {
364                 Modification *mod = &ml->sml_mod;
365
366                 if ( mod->sm_desc == mi->mi_ad_readOnly ) {
367                         int     val = -1;
368
369                         if ( mod->sm_values ) {
370                                 if ( !BER_BVISNULL( &mod->sm_values[ 1 ] ) ) {
371                                         rc = LDAP_CONSTRAINT_VIOLATION;
372                                         goto done;
373                                 }
374
375                                 if ( bvmatch( &slap_true_bv, mod->sm_values )) {
376                                         val = 1;
377
378                                 } else if ( bvmatch( &slap_false_bv, mod->sm_values )) {
379                                         val = 0;
380
381                                 } else {
382                                         rc = LDAP_INVALID_SYNTAX;
383                                         goto done;
384                                 }
385                         }
386
387                         switch ( mod->sm_op ) {
388                         case LDAP_MOD_DELETE:
389                                 if ( ro_gotval < 1 ) {
390                                         rc = LDAP_CONSTRAINT_VIOLATION;
391                                         goto done;
392                                 }
393                                 ro_gotval--;
394
395                                 if ( val == 0 && ( rp_cur & SLAP_RESTRICT_OP_WRITES ) == SLAP_RESTRICT_OP_WRITES ) {
396                                         rc = LDAP_NO_SUCH_ATTRIBUTE;
397                                         goto done;
398                                 }
399                                 
400                                 if ( val == 1 && ( rp_cur & SLAP_RESTRICT_OP_WRITES ) != SLAP_RESTRICT_OP_WRITES ) {
401                                         rc = LDAP_NO_SUCH_ATTRIBUTE;
402                                         goto done;
403                                 }
404                                 
405                                 break;
406
407                         case LDAP_MOD_REPLACE:
408                                 ro_gotval = 0;
409                                 /* fall thru */
410
411                         case LDAP_MOD_ADD:
412                                 if ( ro_gotval > 0 ) {
413                                         rc = LDAP_CONSTRAINT_VIOLATION;
414                                         goto done;
415                                 }
416                                 ro_gotval++;
417
418                                 if ( val == 1 ) {
419                                         rp_add |= (~rp_cur) & SLAP_RESTRICT_OP_WRITES;
420                                         rp_cur |= SLAP_RESTRICT_OP_WRITES;
421                                         rp_delete &= ~SLAP_RESTRICT_OP_WRITES;
422                                         
423                                 } else if ( val == 0 ) {
424                                         rp_delete |= rp_cur & SLAP_RESTRICT_OP_WRITES;
425                                         rp_cur &= ~SLAP_RESTRICT_OP_WRITES;
426                                         rp_add &= ~SLAP_RESTRICT_OP_WRITES;
427                                 }
428                                 break;
429
430                         default:
431                                 rc = LDAP_OTHER;
432                                 goto done;
433                         }
434
435                 } else if ( mod->sm_desc == mi->mi_ad_restrictedOperation ) {
436                         slap_mask_t     mask = 0;
437
438                         switch ( mod->sm_op ) {
439                         case LDAP_MOD_DELETE:
440                                 if ( mod->sm_values == NULL ) {
441                                         rp_delete = rp_cur;
442                                         rp_cur = 0;
443                                         rp_add = 0;
444                                         break;
445                                 }
446                                 rc = value_mask( mod->sm_values, ~rp_cur, &mask );
447                                 if ( rc == LDAP_SUCCESS ) {
448                                         rp_delete |= mask;
449                                         rp_add &= ~mask;
450                                         rp_cur &= ~mask;
451
452                                 } else if ( rc == LDAP_OTHER ) {
453                                         rc = LDAP_NO_SUCH_ATTRIBUTE;
454                                 }
455                                 break;
456
457                         case LDAP_MOD_REPLACE:
458                                 rp_delete = rp_cur;
459                                 rp_cur = 0;
460                                 rp_add = 0;
461                                 /* fall thru */
462
463                         case LDAP_MOD_ADD:
464                                 rc = value_mask( mod->sm_values, rp_cur, &mask );
465                                 if ( rc == LDAP_SUCCESS ) {
466                                         rp_add |= mask;
467                                         rp_cur |= mask;
468                                         rp_delete &= ~mask;
469
470                                 } else if ( rc == LDAP_OTHER ) {
471                                         rc = LDAP_TYPE_OR_VALUE_EXISTS;
472                                 }
473                                 break;
474
475                         default:
476                                 rc = LDAP_OTHER;
477                                 break;
478                         }
479
480                         if ( rc != LDAP_SUCCESS ) {
481                                 goto done;
482                         }
483
484                 } else if ( is_at_operational( mod->sm_desc->ad_type )) {
485                 /* accept all operational attributes */
486                         attr_delete( &e->e_attrs, mod->sm_desc );
487                         rc = attr_merge( e, mod->sm_desc, mod->sm_values,
488                                 mod->sm_nvalues );
489                         if ( rc ) {
490                                 rc = LDAP_OTHER;
491                                 break;
492                         }
493
494                 } else {
495                         rc = LDAP_UNWILLING_TO_PERFORM;
496                         break;
497                 }
498         }
499
500         /* sanity checks: */
501         if ( ro_gotval < 1 ) {
502                 rc = LDAP_CONSTRAINT_VIOLATION;
503                 goto done;
504         }
505
506         if ( ( rp_cur & SLAP_RESTRICT_OP_EXTENDED ) && ( rp_cur & SLAP_RESTRICT_EXOP_MASK ) ) {
507                 rc = LDAP_CONSTRAINT_VIOLATION;
508                 goto done;
509         }
510
511         if ( rp_delete & rp_add ) {
512                 rc = LDAP_OTHER;
513                 goto done;
514         }
515
516         /* check current value of readOnly */
517         if ( ( rp_cur & SLAP_RESTRICT_OP_WRITES ) == SLAP_RESTRICT_OP_WRITES ) {
518                 tf = (struct berval *)&slap_true_bv;
519
520         } else {
521                 tf = (struct berval *)&slap_false_bv;
522         }
523
524         a = attr_find( e->e_attrs, mi->mi_ad_readOnly );
525         if ( a == NULL ) {
526                 rc = LDAP_OTHER;
527                 goto done;
528         }
529
530         if ( !bvmatch( &a->a_vals[0], tf ) ) {
531                 attr_delete( &e->e_attrs, mi->mi_ad_readOnly );
532                 rc = attr_merge_one( e, mi->mi_ad_readOnly, tf, NULL );
533         }
534
535         if ( rc == LDAP_SUCCESS ) {
536                 if ( rp_delete ) {
537                         if ( rp_delete == be->be_restrictops ) {
538                                 attr_delete( &e->e_attrs, mi->mi_ad_restrictedOperation );
539
540                         } else {
541                                 a = attr_find( e->e_attrs, mi->mi_ad_restrictedOperation );
542                                 if ( a == NULL ) {
543                                         rc = LDAP_OTHER;
544                                         goto done;
545                                 }
546
547                                 for ( i = 0; !BER_BVISNULL( &restricted_ops[ i ].op ); i++ ) {
548                                         if ( rp_delete & restricted_ops[ i ].tag ) {
549                                                 int     j;
550                                         
551                                                 for ( j = 0; !BER_BVISNULL( &a->a_nvals[ j ] ); j++ ) {
552                                                         int             k;
553
554                                                         if ( !bvmatch( &a->a_nvals[ j ], &restricted_ops[ i ].op ) ) {
555                                                                 continue;
556                                                         }
557
558                                                         ch_free( a->a_vals[ j ].bv_val );
559                                                         ch_free( a->a_nvals[ j ].bv_val );
560
561                                                         for ( k = j + 1; !BER_BVISNULL( &a->a_nvals[ k ] ); k++ ) {
562                                                                 a->a_vals[ k - 1 ] = a->a_vals[ k ];
563                                                                 a->a_nvals[ k - 1 ] = a->a_nvals[ k ];
564                                                         }
565         
566                                                         BER_BVZERO( &a->a_vals[ k - 1 ] );
567                                                         BER_BVZERO( &a->a_nvals[ k - 1 ] );
568                                                 }
569                                         }
570                                 }
571                                 
572                                 for ( i = 0; !BER_BVISNULL( &restricted_exops[ i ].op ); i++ ) {
573                                         if ( rp_delete & restricted_exops[ i ].tag ) {
574                                                 int     j;
575                                         
576                                                 for ( j = 0; !BER_BVISNULL( &a->a_nvals[ j ] ); j++ ) {
577                                                         int             k;
578
579                                                         if ( !bvmatch( &a->a_nvals[ j ], &restricted_exops[ i ].op ) ) {
580                                                                 continue;
581                                                         }
582
583                                                         ch_free( a->a_vals[ j ].bv_val );
584                                                         ch_free( a->a_nvals[ j ].bv_val );
585
586                                                         for ( k = j + 1; !BER_BVISNULL( &a->a_nvals[ k ] ); k++ ) {
587                                                                 a->a_vals[ k - 1 ] = a->a_vals[ k ];
588                                                                 a->a_nvals[ k - 1 ] = a->a_nvals[ k ];
589                                                         }
590         
591                                                         BER_BVZERO( &a->a_vals[ k - 1 ] );
592                                                         BER_BVZERO( &a->a_nvals[ k - 1 ] );
593                                                 }
594                                         }
595                                 }
596                         }
597                 }
598
599                 if ( rp_add ) {
600                         for ( i = 0; !BER_BVISNULL( &restricted_ops[ i ].op ); i++ ) {
601                                 if ( rp_add & restricted_ops[ i ].tag ) {
602                                         attr_merge_one( e, mi->mi_ad_restrictedOperation,
603                                                         &restricted_ops[ i ].op, NULL );
604                                 }
605                         }
606
607                         for ( i = 0; !BER_BVISNULL( &restricted_exops[ i ].op ); i++ ) {
608                                 if ( rp_add & restricted_exops[ i ].tag ) {
609                                         attr_merge_one( e, mi->mi_ad_restrictedOperation,
610                                                         &restricted_exops[ i ].op, NULL );
611                                 }
612                         }
613                 }
614         }
615
616         be->be_restrictops = rp_cur;
617
618 done:;
619         if ( rc == LDAP_SUCCESS ) {
620                 attrs_free( save_attrs );
621
622         } else {
623                 Attribute *tmp = e->e_attrs;
624                 e->e_attrs = save_attrs;
625                 attrs_free( tmp );
626         }
627         return rc;
628 }
629
630 #if defined(LDAP_SLAPI)
631 static int
632 monitor_back_add_plugin( Backend *be, Entry *e_database )
633 {
634         Slapi_PBlock            *pCurrentPB; 
635         int                     i, rc = LDAP_SUCCESS;
636         struct monitorinfo      *mi = ( struct monitorinfo * )be->be_private;
637
638         if ( slapi_int_pblock_get_first( be, &pCurrentPB ) != LDAP_SUCCESS ) {
639                 /*
640                  * LDAP_OTHER is returned if no plugins are installed
641                  */
642                 rc = LDAP_OTHER;
643                 goto done;
644         }
645
646         i = 0;
647         do {
648                 Slapi_PluginDesc        *srchdesc;
649                 char                    buf[ BACKMONITOR_BUFSIZE ];
650                 struct berval           bv;
651
652                 rc = slapi_pblock_get( pCurrentPB, SLAPI_PLUGIN_DESCRIPTION,
653                                 &srchdesc );
654                 if ( rc != LDAP_SUCCESS ) {
655                         goto done;
656                 }
657
658                 snprintf( buf, sizeof(buf),
659                                 "plugin %d name: %s; "
660                                 "vendor: %s; "
661                                 "version: %s; "
662                                 "description: %s", 
663                                 i,
664                                 srchdesc->spd_id,
665                                 srchdesc->spd_vendor,
666                                 srchdesc->spd_version,
667                                 srchdesc->spd_description );
668
669                 bv.bv_val = buf;
670                 bv.bv_len = strlen( buf );
671                 attr_merge_normalize_one( e_database,
672                                 mi->mi_ad_monitoredInfo, &bv, NULL );
673
674                 i++;
675
676         } while ( ( slapi_int_pblock_get_next( &pCurrentPB ) == LDAP_SUCCESS )
677                         && ( pCurrentPB != NULL ) );
678
679 done:
680         return rc;
681 }
682 #endif /* defined(LDAP_SLAPI) */