]> git.sur5r.net Git - openldap/blob - servers/slapd/back-monitor/database.c
be28f15d3fe66008b595fe74d3f801be235e3876
[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-2009 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 #include <ac/unistd.h>
27
28 #include "slap.h"
29 #include "back-monitor.h"
30
31 #if defined(LDAP_SLAPI)
32 #include "slapi.h"
33 static int monitor_back_add_plugin( monitor_info_t *mi, Backend *be, Entry *e );
34 #endif /* defined(LDAP_SLAPI) */
35
36 static int
37 monitor_subsys_database_modify(
38         Operation       *op,
39         SlapReply       *rs,
40         Entry           *e );
41
42 static struct restricted_ops_t {
43         struct berval   op;
44         unsigned int    tag;
45 } restricted_ops[] = {
46         { BER_BVC( "add" ),                     SLAP_RESTRICT_OP_ADD },
47         { BER_BVC( "bind" ),                    SLAP_RESTRICT_OP_BIND },
48         { BER_BVC( "compare" ),                 SLAP_RESTRICT_OP_COMPARE },
49         { BER_BVC( "delete" ),                  SLAP_RESTRICT_OP_DELETE },
50         { BER_BVC( "extended" ),                SLAP_RESTRICT_OP_EXTENDED },
51         { BER_BVC( "modify" ),                  SLAP_RESTRICT_OP_MODIFY },
52         { BER_BVC( "rename" ),                  SLAP_RESTRICT_OP_RENAME },
53         { BER_BVC( "search" ),                  SLAP_RESTRICT_OP_SEARCH },
54         { BER_BVNULL,                           0 }
55 }, restricted_exops[] = {
56         { BER_BVC( LDAP_EXOP_START_TLS ),       SLAP_RESTRICT_EXOP_START_TLS },
57         { BER_BVC( LDAP_EXOP_MODIFY_PASSWD ),   SLAP_RESTRICT_EXOP_MODIFY_PASSWD },
58         { BER_BVC( LDAP_EXOP_WHO_AM_I ),        SLAP_RESTRICT_EXOP_WHOAMI },
59         { BER_BVC( LDAP_EXOP_CANCEL ),  SLAP_RESTRICT_EXOP_CANCEL },
60         { BER_BVNULL,                           0 }
61 };
62
63 static int
64 init_readOnly( monitor_info_t *mi, Entry *e, slap_mask_t restrictops )
65 {
66         struct berval   *tf = ( ( restrictops & SLAP_RESTRICT_OP_MASK ) == SLAP_RESTRICT_OP_WRITES ) ?
67                 (struct berval *)&slap_true_bv : (struct berval *)&slap_false_bv;
68
69         return attr_merge_one( e, mi->mi_ad_readOnly, tf, NULL );
70 }
71
72 static int
73 init_restrictedOperation( monitor_info_t *mi, Entry *e, slap_mask_t restrictops )
74 {
75         int     i, rc;
76
77         for ( i = 0; restricted_ops[ i ].op.bv_val; i++ ) {
78                 if ( restrictops & restricted_ops[ i ].tag ) {
79                         rc = attr_merge_one( e, mi->mi_ad_restrictedOperation,
80                                         &restricted_ops[ i ].op,
81                                         &restricted_ops[ i ].op );
82                         if ( rc ) {
83                                 return rc;
84                         }
85                 }
86         }
87
88         for ( i = 0; restricted_exops[ i ].op.bv_val; i++ ) {
89                 if ( restrictops & restricted_exops[ i ].tag ) {
90                         rc = attr_merge_one( e, mi->mi_ad_restrictedOperation,
91                                         &restricted_exops[ i ].op,
92                                         &restricted_exops[ i ].op );
93                         if ( rc ) {
94                                 return rc;
95                         }
96                 }
97         }
98
99         return LDAP_SUCCESS;
100 }
101
102 static int
103 monitor_subsys_database_init_one(
104         monitor_info_t          *mi,
105         BackendDB               *be,
106         monitor_subsys_t        *ms,
107         monitor_subsys_t        *ms_backend,
108         monitor_subsys_t        *ms_overlay,
109         struct berval           *rdn,
110         Entry                   *e_database,
111         Entry                   ***epp )
112 {
113         char                    buf[ BACKMONITOR_BUFSIZE ];
114         int                     j;
115         slap_overinfo           *oi = NULL;
116         BackendInfo             *bi, *bi2;
117         Entry                   *e;
118         monitor_entry_t         *mp;
119         char                    *rdnval = strchr( rdn->bv_val, '=' ) + 1;
120         struct berval           bv;
121
122         bi = be->bd_info;
123
124         if ( overlay_is_over( be ) ) {
125                 oi = (slap_overinfo *)be->bd_info->bi_private;
126                 bi = oi->oi_orig;
127         }
128
129         e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, rdn,
130                 mi->mi_oc_monitoredObject, mi, NULL, NULL );
131
132         if ( e == NULL ) {
133                 Debug( LDAP_DEBUG_ANY,
134                         "monitor_subsys_database_init: "
135                         "unable to create entry \"%s,%s\"\n",
136                         rdn->bv_val, ms->mss_dn.bv_val, 0 );
137                 return( -1 );
138         }
139
140         ber_str2bv( bi->bi_type, 0, 0, &bv );
141         attr_merge_normalize_one( e, mi->mi_ad_monitoredInfo, &bv, NULL );
142         attr_merge_one( e, mi->mi_ad_monitorIsShadow,
143                 SLAP_SHADOW( be ) ? (struct berval *)&slap_true_bv :
144                         (struct berval *)&slap_false_bv, NULL );
145
146         if ( SLAP_MONITOR( be ) ) {
147                 attr_merge( e, slap_schema.si_ad_monitorContext,
148                                 be->be_suffix, be->be_nsuffix );
149                 attr_merge( e_database, slap_schema.si_ad_monitorContext,
150                                 be->be_suffix, be->be_nsuffix );
151
152         } else {
153                 if ( be->be_suffix == NULL ) {
154                         Debug( LDAP_DEBUG_ANY,
155                                 "monitor_subsys_database_init: "
156                                 "missing suffix for %s\n",
157                                 rdnval, 0, 0 );
158                 } else {
159                         attr_merge( e, slap_schema.si_ad_namingContexts,
160                                 be->be_suffix, NULL );
161                         attr_merge( e_database, slap_schema.si_ad_namingContexts,
162                                 be->be_suffix, NULL );
163                 }
164
165                 if ( SLAP_GLUE_SUBORDINATE( be ) ) {
166                         BackendDB *sup_be = select_backend( &be->be_nsuffix[ 0 ], 1 );
167                         if ( sup_be == NULL ) {
168                                 Debug( LDAP_DEBUG_ANY,
169                                         "monitor_subsys_database_init: "
170                                         "unable to get superior for %s\n",
171                                         be->be_suffix[ 0 ].bv_val, 0, 0 );
172
173                         } else {
174                                 attr_merge( e, mi->mi_ad_monitorSuperiorDN,
175                                         sup_be->be_suffix, sup_be->be_nsuffix );
176                         }
177                 }
178         }
179
180         (void)init_readOnly( mi, e, be->be_restrictops );
181         (void)init_restrictedOperation( mi, e, be->be_restrictops );
182
183         if ( SLAP_SHADOW( be ) && be->be_update_refs ) {
184                 attr_merge_normalize( e, mi->mi_ad_monitorUpdateRef,
185                                 be->be_update_refs, NULL );
186         }
187
188         if ( oi != NULL ) {
189                 slap_overinst   *on = oi->oi_list,
190                                 *on1 = on;
191
192                 for ( ; on; on = on->on_next ) {
193                         slap_overinst           *on2;
194
195                         for ( on2 = on1; on2 != on; on2 = on2->on_next ) {
196                                 if ( on2->on_bi.bi_type == on->on_bi.bi_type ) {
197                                         break;
198                                 }
199                         }
200
201                         if ( on2 != on ) {
202                                 break;
203                         }
204                         
205                         ber_str2bv( on->on_bi.bi_type, 0, 0, &bv );
206                         attr_merge_normalize_one( e, mi->mi_ad_monitorOverlay,
207                                         &bv, NULL );
208
209                         /* find the overlay number, j */
210                         for ( on2 = overlay_next( NULL ), j = 0; on2; on2 = overlay_next( on2 ), j++ ) {
211                                 if ( on2->on_bi.bi_type == on->on_bi.bi_type ) {
212                                         break;
213                                 }
214                         }
215                         assert( on2 != NULL );
216
217                         snprintf( buf, sizeof( buf ), 
218                                 "cn=Overlay %d,%s", 
219                                 j, ms_overlay->mss_dn.bv_val );
220                         ber_str2bv( buf, 0, 0, &bv );
221                         attr_merge_normalize_one( e,
222                                         slap_schema.si_ad_seeAlso,
223                                         &bv, NULL );
224                 }
225         }
226
227         j = -1;
228         LDAP_STAILQ_FOREACH( bi2, &backendInfo, bi_next ) {
229                 j++;
230                 if ( bi2->bi_type == bi->bi_type ) {
231                         snprintf( buf, sizeof( buf ), 
232                                 "cn=Backend %d,%s", 
233                                 j, ms_backend->mss_dn.bv_val );
234                         bv.bv_val = buf;
235                         bv.bv_len = strlen( buf );
236                         attr_merge_normalize_one( e,
237                                         slap_schema.si_ad_seeAlso,
238                                         &bv, NULL );
239                         break;
240                 }
241         }
242         /* we must find it! */
243         assert( j >= 0 );
244
245         mp = monitor_entrypriv_create();
246         if ( mp == NULL ) {
247                 return -1;
248         }
249         e->e_private = ( void * )mp;
250         mp->mp_info = ms;
251         mp->mp_flags = ms->mss_flags
252                 | MONITOR_F_SUB;
253
254         if ( monitor_cache_add( mi, e ) ) {
255                 Debug( LDAP_DEBUG_ANY,
256                         "monitor_subsys_database_init: "
257                         "unable to add entry \"%s,%s\"\n",
258                         rdn->bv_val, ms->mss_dn.bv_val, 0 );
259                 return( -1 );
260         }
261
262 #if defined(LDAP_SLAPI)
263         monitor_back_add_plugin( mi, be, e );
264 #endif /* defined(LDAP_SLAPI) */
265
266         if ( oi != NULL ) {
267                 Entry           **ep_overlay = &mp->mp_children;
268                 monitor_entry_t *mp_overlay;
269                 slap_overinst   *on = oi->oi_list;
270                 int             o;
271
272                 for ( o = 0; on; o++, on = on->on_next ) {
273                         Entry                   *e_overlay;
274                         slap_overinst           *on2;
275
276                         /* find the overlay number, j */
277                         for ( on2 = overlay_next( NULL ), j = 0; on2; on2 = overlay_next( on2 ), j++ ) {
278                                 if ( on2->on_bi.bi_type == on->on_bi.bi_type ) {
279                                         break;
280                                 }
281                         }
282                         assert( on2 != NULL );
283
284                         bv.bv_len = snprintf( buf, sizeof( buf ), "cn=Overlay %d", o );
285                         bv.bv_val = buf;
286
287                         e_overlay = monitor_entry_stub( &e->e_name, &e->e_nname, &bv,
288                                 mi->mi_oc_monitoredObject, mi, NULL, NULL );
289
290                         if ( e_overlay == NULL ) {
291                                 Debug( LDAP_DEBUG_ANY,
292                                         "monitor_subsys_database_init: "
293                                         "unable to create entry "
294                                         "\"cn=Overlay %d,%s,%s\"\n",
295                                         o, rdn->bv_val, ms->mss_dn.bv_val );
296                                 return( -1 );
297                         }
298                         ber_str2bv( on->on_bi.bi_type, 0, 0, &bv );
299                         attr_merge_normalize_one( e_overlay, mi->mi_ad_monitoredInfo, &bv, NULL );
300
301                         bv.bv_len = snprintf( buf, sizeof( buf ), "cn=Overlay %d,%s",
302                                 j, ms_overlay->mss_dn.bv_val );
303                         bv.bv_val = buf;
304                         attr_merge_normalize_one( e_overlay, slap_schema.si_ad_seeAlso,
305                                 &bv, NULL );
306
307                         if ( SLAP_MONITOR( be ) ) {
308                                 attr_merge( e_overlay, slap_schema.si_ad_monitorContext,
309                                                 be->be_suffix, be->be_nsuffix );
310
311                         } else {
312                                 attr_merge( e_overlay, slap_schema.si_ad_namingContexts,
313                                                 be->be_suffix, NULL );
314                         }
315
316                         mp_overlay = monitor_entrypriv_create();
317                         if ( mp_overlay == NULL ) {
318                                 return -1;
319                         }
320                         e_overlay->e_private = ( void * )mp_overlay;
321                         mp_overlay->mp_info = ms;
322                         mp_overlay->mp_flags = ms->mss_flags
323                                 | MONITOR_F_SUB;
324         
325                         if ( monitor_cache_add( mi, e_overlay ) ) {
326                                 Debug( LDAP_DEBUG_ANY,
327                                         "monitor_subsys_database_init: "
328                                         "unable to add entry "
329                                         "\"cn=Overlay %d,%s,%s\"\n",
330                                         o, rdn->bv_val, ms->mss_dn.bv_val );
331                                 return( -1 );
332                         }
333
334                         *ep_overlay = e_overlay;
335                         ep_overlay = &mp_overlay->mp_next;
336                 }
337         }
338
339         **epp = e;
340         *epp = &mp->mp_next;
341
342         return 0;
343 }
344
345 int
346 monitor_back_register_database(
347         BackendDB               *be,
348         struct berval   *ndn )
349 {
350         monitor_info_t          *mi;
351         Entry                   *e_database, **ep;
352         int                     i, rc;
353         monitor_entry_t         *mp;
354         monitor_subsys_t        *ms_backend,
355                                 *ms_database,
356                                 *ms_overlay;
357         struct berval           bv;
358         char                    buf[ BACKMONITOR_BUFSIZE ];
359
360         assert( be_monitor != NULL );
361
362         if ( !monitor_subsys_is_opened() ) {
363                 return monitor_back_register_database_limbo( be, ndn );
364         }
365
366         mi = ( monitor_info_t * )be_monitor->be_private;
367
368         ms_backend = monitor_back_get_subsys( SLAPD_MONITOR_BACKEND_NAME );
369         if ( ms_backend == NULL ) {
370                 Debug( LDAP_DEBUG_ANY,
371                         "monitor_back_register_database: "
372                         "unable to get "
373                         "\"" SLAPD_MONITOR_BACKEND_NAME "\" "
374                         "subsystem\n",
375                         0, 0, 0 );
376                 return -1;
377         }
378
379         ms_database = monitor_back_get_subsys( SLAPD_MONITOR_DATABASE_NAME );
380         if ( ms_database == NULL ) {
381                 Debug( LDAP_DEBUG_ANY,
382                         "monitor_back_register_database: "
383                         "unable to get "
384                         "\"" SLAPD_MONITOR_DATABASE_NAME "\" "
385                         "subsystem\n",
386                         0, 0, 0 );
387                 return -1;
388         }
389
390         ms_overlay = monitor_back_get_subsys( SLAPD_MONITOR_OVERLAY_NAME );
391         if ( ms_overlay == NULL ) {
392                 Debug( LDAP_DEBUG_ANY,
393                         "monitor_back_register_database: "
394                         "unable to get "
395                         "\"" SLAPD_MONITOR_OVERLAY_NAME "\" "
396                         "subsystem\n",
397                         0, 0, 0 );
398                 return -1;
399         }
400
401         if ( monitor_cache_get( mi, &ms_database->mss_ndn, &e_database ) ) {
402                 Debug( LDAP_DEBUG_ANY,
403                         "monitor_subsys_database_init: "
404                         "unable to get entry \"%s\"\n",
405                         ms_database->mss_ndn.bv_val, 0, 0 );
406                 return( -1 );
407         }
408
409         mp = ( monitor_entry_t * )e_database->e_private;
410         for ( i = -1, ep = &mp->mp_children; *ep; i++ ) {
411                 Attribute       *a;
412
413                 a = attr_find( (*ep)->e_attrs, slap_schema.si_ad_namingContexts );
414                 if ( a ) {
415                         int             j, k;
416
417                         /* FIXME: RFC 4512 defines namingContexts without an
418                          *        equality matching rule, making comparisons
419                          *        like this one tricky.  We use a_vals and
420                          *        be_suffix instead for now.
421                          */
422                         for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); j++ ) {
423                                 for ( k = 0; !BER_BVISNULL( &be->be_suffix[ k ] ); k++ ) {
424                                         if ( dn_match( &a->a_vals[ j ],
425                                                        &be->be_suffix[ k ] ) ) {
426                                                 rc = 0;
427                                                 goto done;
428                                         }
429                                 }
430                         }
431                 }
432
433                 mp = ( monitor_entry_t * )(*ep)->e_private;
434
435                 assert( mp != NULL );
436                 ep = &mp->mp_next;
437         }
438
439         bv.bv_val = buf;
440         bv.bv_len = snprintf( buf, sizeof( buf ), "cn=Database %d", i );
441         if ( bv.bv_len >= sizeof( buf ) ) {
442                 rc = -1;
443                 goto done;
444         }
445         
446         rc = monitor_subsys_database_init_one( mi, be,
447                 ms_database, ms_backend, ms_overlay, &bv, e_database, &ep );
448         if ( rc != 0 ) {
449                 goto done;
450         }
451         /* database_init_one advanced ep past where we want.
452          * But it stored the entry we want in mp->mp_next.
453          */
454         ep = &mp->mp_next;
455
456 done:;
457         monitor_cache_release( mi, e_database );
458         if ( rc == 0 && ndn && ep && *ep ) {
459                 *ndn = (*ep)->e_nname;
460         }
461
462         return rc;
463 }
464
465 int
466 monitor_subsys_database_init(
467         BackendDB               *be,
468         monitor_subsys_t        *ms )
469 {
470         monitor_info_t          *mi;
471         Entry                   *e_database, **ep;
472         int                     i, rc;
473         monitor_entry_t         *mp;
474         monitor_subsys_t        *ms_backend,
475                                 *ms_overlay;
476         struct berval           bv;
477
478         assert( be != NULL );
479
480         ms->mss_modify = monitor_subsys_database_modify;
481
482         mi = ( monitor_info_t * )be->be_private;
483
484         ms_backend = monitor_back_get_subsys( SLAPD_MONITOR_BACKEND_NAME );
485         if ( ms_backend == NULL ) {
486                 Debug( LDAP_DEBUG_ANY,
487                         "monitor_subsys_database_init: "
488                         "unable to get "
489                         "\"" SLAPD_MONITOR_BACKEND_NAME "\" "
490                         "subsystem\n",
491                         0, 0, 0 );
492                 return -1;
493         }
494
495         ms_overlay = monitor_back_get_subsys( SLAPD_MONITOR_OVERLAY_NAME );
496         if ( ms_overlay == NULL ) {
497                 Debug( LDAP_DEBUG_ANY,
498                         "monitor_subsys_database_init: "
499                         "unable to get "
500                         "\"" SLAPD_MONITOR_OVERLAY_NAME "\" "
501                         "subsystem\n",
502                         0, 0, 0 );
503                 return -1;
504         }
505
506         if ( monitor_cache_get( mi, &ms->mss_ndn, &e_database ) ) {
507                 Debug( LDAP_DEBUG_ANY,
508                         "monitor_subsys_database_init: "
509                         "unable to get entry \"%s\"\n",
510                         ms->mss_ndn.bv_val, 0, 0 );
511                 return( -1 );
512         }
513
514         (void)init_readOnly( mi, e_database, frontendDB->be_restrictops );
515         (void)init_restrictedOperation( mi, e_database, frontendDB->be_restrictops );
516
517         mp = ( monitor_entry_t * )e_database->e_private;
518         mp->mp_children = NULL;
519         ep = &mp->mp_children;
520
521         BER_BVSTR( &bv, "cn=Frontend" );
522         rc = monitor_subsys_database_init_one( mi, frontendDB,
523                 ms, ms_backend, ms_overlay, &bv, e_database, &ep );
524         if ( rc != 0 ) {
525                 return rc;
526         }
527
528         i = -1;
529         LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) {
530                 char            buf[ BACKMONITOR_BUFSIZE ];
531
532                 bv.bv_val = buf;
533                 bv.bv_len = snprintf( buf, sizeof( buf ), "cn=Database %d", ++i );
534                 if ( bv.bv_len >= sizeof( buf ) ) {
535                         return -1;
536                 }
537                 
538                 rc = monitor_subsys_database_init_one( mi, be,
539                         ms, ms_backend, ms_overlay, &bv, e_database, &ep );
540                 if ( rc != 0 ) {
541                         return rc;
542                 }
543         }
544         
545         monitor_cache_release( mi, e_database );
546
547         return( 0 );
548 }
549
550 /*
551  * v: array of values
552  * cur: must not contain the tags corresponding to the values in v
553  * delta: will contain the tags corresponding to the values in v
554  */
555 static int
556 value_mask( BerVarray v, slap_mask_t cur, slap_mask_t *delta )
557 {
558         for ( ; !BER_BVISNULL( v ); v++ ) {
559                 struct restricted_ops_t         *rops;
560                 int                             i;
561
562                 if ( OID_LEADCHAR( v->bv_val[ 0 ] ) ) {
563                         rops = restricted_exops;
564
565                 } else {
566                         rops = restricted_ops;
567                 }
568
569                 for ( i = 0; !BER_BVISNULL( &rops[ i ].op ); i++ ) {
570                         if ( ber_bvstrcasecmp( v, &rops[ i ].op ) != 0 ) {
571                                 continue;
572                         }
573
574                         if ( rops[ i ].tag & *delta ) {
575                                 return LDAP_OTHER;
576                         }
577
578                         if ( rops[ i ].tag & cur ) {
579                                 return LDAP_OTHER;
580                         }
581
582                         cur |= rops[ i ].tag;
583                         *delta |= rops[ i ].tag;
584
585                         break;
586                 }
587
588                 if ( BER_BVISNULL( &rops[ i ].op ) ) {
589                         return LDAP_INVALID_SYNTAX;
590                 }
591         }
592
593         return LDAP_SUCCESS;
594 }
595
596 static int
597 monitor_subsys_database_modify(
598         Operation       *op,
599         SlapReply       *rs,
600         Entry           *e )
601 {
602         monitor_info_t  *mi = (monitor_info_t *)op->o_bd->be_private;
603         int             rc = LDAP_OTHER;
604         Attribute       *save_attrs, *a;
605         Modifications   *ml;
606         Backend         *be;
607         int             ro_gotval = 1, i, n;
608         slap_mask_t     rp_add = 0, rp_delete = 0, rp_cur;
609         struct berval   *tf;
610         
611         i = sscanf( e->e_nname.bv_val, "cn=database %d,", &n );
612         if ( i != 1 ) {
613                 return SLAP_CB_CONTINUE;
614         }
615
616         if ( n < 0 || n >= nBackendDB ) {
617                 rs->sr_text = "invalid database index";
618                 return ( rs->sr_err = LDAP_NO_SUCH_OBJECT );
619         }
620
621         LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) {
622                 if ( n == 0 ) {
623                         break;
624                 }
625                 n--;
626         }
627         /* do not allow some changes on back-monitor (needs work)... */
628         if ( SLAP_MONITOR( be ) ) {
629                 rs->sr_text = "no modifications allowed to monitor database entry";
630                 return ( rs->sr_err = LDAP_UNWILLING_TO_PERFORM );
631         }
632                 
633         rp_cur = be->be_restrictops;
634
635         save_attrs = e->e_attrs;
636         e->e_attrs = attrs_dup( e->e_attrs );
637
638         for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
639                 Modification *mod = &ml->sml_mod;
640
641                 if ( mod->sm_desc == mi->mi_ad_readOnly ) {
642                         int     val = -1;
643
644                         if ( mod->sm_values ) {
645                                 if ( !BER_BVISNULL( &mod->sm_values[ 1 ] ) ) {
646                                         rs->sr_text = "attempting to modify multiple values of single-valued attribute";
647                                         rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
648                                         goto done;
649                                 }
650
651                                 if ( bvmatch( &slap_true_bv, mod->sm_values )) {
652                                         val = 1;
653
654                                 } else if ( bvmatch( &slap_false_bv, mod->sm_values )) {
655                                         val = 0;
656
657                                 } else {
658                                         assert( 0 );
659                                         rc = rs->sr_err = LDAP_INVALID_SYNTAX;
660                                         goto done;
661                                 }
662                         }
663
664                         switch ( mod->sm_op ) {
665                         case LDAP_MOD_DELETE:
666                                 if ( ro_gotval < 1 ) {
667                                         rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
668                                         goto done;
669                                 }
670                                 ro_gotval--;
671
672                                 if ( val == 0 && ( rp_cur & SLAP_RESTRICT_OP_WRITES ) == SLAP_RESTRICT_OP_WRITES ) {
673                                         rc = rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE;
674                                         goto done;
675                                 }
676                                 
677                                 if ( val == 1 && ( rp_cur & SLAP_RESTRICT_OP_WRITES ) != SLAP_RESTRICT_OP_WRITES ) {
678                                         rc = rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE;
679                                         goto done;
680                                 }
681                                 
682                                 break;
683
684                         case LDAP_MOD_REPLACE:
685                                 ro_gotval = 0;
686                                 /* fall thru */
687
688                         case LDAP_MOD_ADD:
689                                 if ( ro_gotval > 0 ) {
690                                         rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
691                                         goto done;
692                                 }
693                                 ro_gotval++;
694
695                                 if ( val == 1 ) {
696                                         rp_add |= (~rp_cur) & SLAP_RESTRICT_OP_WRITES;
697                                         rp_cur |= SLAP_RESTRICT_OP_WRITES;
698                                         rp_delete &= ~SLAP_RESTRICT_OP_WRITES;
699                                         
700                                 } else if ( val == 0 ) {
701                                         rp_delete |= rp_cur & SLAP_RESTRICT_OP_WRITES;
702                                         rp_cur &= ~SLAP_RESTRICT_OP_WRITES;
703                                         rp_add &= ~SLAP_RESTRICT_OP_WRITES;
704                                 }
705                                 break;
706
707                         default:
708                                 rc = rs->sr_err = LDAP_OTHER;
709                                 goto done;
710                         }
711
712                 } else if ( mod->sm_desc == mi->mi_ad_restrictedOperation ) {
713                         slap_mask_t     mask = 0;
714
715                         switch ( mod->sm_op ) {
716                         case LDAP_MOD_DELETE:
717                                 if ( mod->sm_values == NULL ) {
718                                         rp_delete = rp_cur;
719                                         rp_cur = 0;
720                                         rp_add = 0;
721                                         break;
722                                 }
723                                 rc = value_mask( mod->sm_values, ~rp_cur, &mask );
724                                 if ( rc == LDAP_SUCCESS ) {
725                                         rp_delete |= mask;
726                                         rp_add &= ~mask;
727                                         rp_cur &= ~mask;
728
729                                 } else if ( rc == LDAP_OTHER ) {
730                                         rc = LDAP_NO_SUCH_ATTRIBUTE;
731                                 }
732                                 break;
733
734                         case LDAP_MOD_REPLACE:
735                                 rp_delete = rp_cur;
736                                 rp_cur = 0;
737                                 rp_add = 0;
738                                 /* fall thru */
739
740                         case LDAP_MOD_ADD:
741                                 rc = value_mask( mod->sm_values, rp_cur, &mask );
742                                 if ( rc == LDAP_SUCCESS ) {
743                                         rp_add |= mask;
744                                         rp_cur |= mask;
745                                         rp_delete &= ~mask;
746
747                                 } else if ( rc == LDAP_OTHER ) {
748                                         rc = rs->sr_err = LDAP_TYPE_OR_VALUE_EXISTS;
749                                 }
750                                 break;
751
752                         default:
753                                 rc = rs->sr_err = LDAP_OTHER;
754                                 break;
755                         }
756
757                         if ( rc != LDAP_SUCCESS ) {
758                                 goto done;
759                         }
760
761                 } else if ( is_at_operational( mod->sm_desc->ad_type )) {
762                 /* accept all operational attributes */
763                         attr_delete( &e->e_attrs, mod->sm_desc );
764                         rc = attr_merge( e, mod->sm_desc, mod->sm_values,
765                                 mod->sm_nvalues );
766                         if ( rc ) {
767                                 rc = rs->sr_err = LDAP_OTHER;
768                                 break;
769                         }
770
771                 } else {
772                         rc = rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
773                         break;
774                 }
775         }
776
777         /* sanity checks: */
778         if ( ro_gotval < 1 ) {
779                 rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
780                 goto done;
781         }
782
783         if ( ( rp_cur & SLAP_RESTRICT_OP_EXTENDED ) && ( rp_cur & SLAP_RESTRICT_EXOP_MASK ) ) {
784                 rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
785                 goto done;
786         }
787
788         if ( rp_delete & rp_add ) {
789                 rc = rs->sr_err = LDAP_OTHER;
790                 goto done;
791         }
792
793         /* check current value of readOnly */
794         if ( ( rp_cur & SLAP_RESTRICT_OP_WRITES ) == SLAP_RESTRICT_OP_WRITES ) {
795                 tf = (struct berval *)&slap_true_bv;
796
797         } else {
798                 tf = (struct berval *)&slap_false_bv;
799         }
800
801         a = attr_find( e->e_attrs, mi->mi_ad_readOnly );
802         if ( a == NULL ) {
803                 rc = LDAP_OTHER;
804                 goto done;
805         }
806
807         if ( !bvmatch( &a->a_vals[ 0 ], tf ) ) {
808                 attr_delete( &e->e_attrs, mi->mi_ad_readOnly );
809                 rc = attr_merge_one( e, mi->mi_ad_readOnly, tf, tf );
810         }
811
812         if ( rc == LDAP_SUCCESS ) {
813                 if ( rp_delete ) {
814                         if ( rp_delete == be->be_restrictops ) {
815                                 attr_delete( &e->e_attrs, mi->mi_ad_restrictedOperation );
816
817                         } else {
818                                 a = attr_find( e->e_attrs, mi->mi_ad_restrictedOperation );
819                                 if ( a == NULL ) {
820                                         rc = rs->sr_err = LDAP_OTHER;
821                                         goto done;
822                                 }
823
824                                 for ( i = 0; !BER_BVISNULL( &restricted_ops[ i ].op ); i++ ) {
825                                         if ( rp_delete & restricted_ops[ i ].tag ) {
826                                                 int     j;
827                                         
828                                                 for ( j = 0; !BER_BVISNULL( &a->a_nvals[ j ] ); j++ ) {
829                                                         int             k;
830
831                                                         if ( !bvmatch( &a->a_nvals[ j ], &restricted_ops[ i ].op ) ) {
832                                                                 continue;
833                                                         }
834
835                                                         ch_free( a->a_vals[ j ].bv_val );
836                                                         ch_free( a->a_nvals[ j ].bv_val );
837
838                                                         for ( k = j + 1; !BER_BVISNULL( &a->a_nvals[ k ] ); k++ ) {
839                                                                 a->a_vals[ k - 1 ] = a->a_vals[ k ];
840                                                                 a->a_nvals[ k - 1 ] = a->a_nvals[ k ];
841                                                         }
842         
843                                                         BER_BVZERO( &a->a_vals[ k - 1 ] );
844                                                         BER_BVZERO( &a->a_nvals[ k - 1 ] );
845                                                         a->a_numvals--;
846                                                 }
847                                         }
848                                 }
849                                 
850                                 for ( i = 0; !BER_BVISNULL( &restricted_exops[ i ].op ); i++ ) {
851                                         if ( rp_delete & restricted_exops[ i ].tag ) {
852                                                 int     j;
853                                         
854                                                 for ( j = 0; !BER_BVISNULL( &a->a_nvals[ j ] ); j++ ) {
855                                                         int             k;
856
857                                                         if ( !bvmatch( &a->a_nvals[ j ], &restricted_exops[ i ].op ) ) {
858                                                                 continue;
859                                                         }
860
861                                                         ch_free( a->a_vals[ j ].bv_val );
862                                                         ch_free( a->a_nvals[ j ].bv_val );
863
864                                                         for ( k = j + 1; !BER_BVISNULL( &a->a_nvals[ k ] ); k++ ) {
865                                                                 a->a_vals[ k - 1 ] = a->a_vals[ k ];
866                                                                 a->a_nvals[ k - 1 ] = a->a_nvals[ k ];
867                                                         }
868         
869                                                         BER_BVZERO( &a->a_vals[ k - 1 ] );
870                                                         BER_BVZERO( &a->a_nvals[ k - 1 ] );
871                                                         a->a_numvals--;
872                                                 }
873                                         }
874                                 }
875
876                                 if ( a->a_vals == NULL ) {
877                                         assert( a->a_numvals == 0 );
878
879                                         attr_delete( &e->e_attrs, mi->mi_ad_restrictedOperation );
880                                 }
881                         }
882                 }
883
884                 if ( rp_add ) {
885                         for ( i = 0; !BER_BVISNULL( &restricted_ops[ i ].op ); i++ ) {
886                                 if ( rp_add & restricted_ops[ i ].tag ) {
887                                         attr_merge_one( e, mi->mi_ad_restrictedOperation,
888                                                         &restricted_ops[ i ].op,
889                                                         &restricted_ops[ i ].op );
890                                 }
891                         }
892
893                         for ( i = 0; !BER_BVISNULL( &restricted_exops[ i ].op ); i++ ) {
894                                 if ( rp_add & restricted_exops[ i ].tag ) {
895                                         attr_merge_one( e, mi->mi_ad_restrictedOperation,
896                                                         &restricted_exops[ i ].op,
897                                                         &restricted_exops[ i ].op );
898                                 }
899                         }
900                 }
901         }
902
903         be->be_restrictops = rp_cur;
904
905 done:;
906         if ( rc == LDAP_SUCCESS ) {
907                 attrs_free( save_attrs );
908                 rc = SLAP_CB_CONTINUE;
909
910         } else {
911                 Attribute *tmp = e->e_attrs;
912                 e->e_attrs = save_attrs;
913                 attrs_free( tmp );
914         }
915         return rc;
916 }
917
918 #if defined(LDAP_SLAPI)
919 static int
920 monitor_back_add_plugin( monitor_info_t *mi, Backend *be, Entry *e_database )
921 {
922         Slapi_PBlock    *pCurrentPB; 
923         int             i, rc = LDAP_SUCCESS;
924
925         if ( slapi_int_pblock_get_first( be, &pCurrentPB ) != LDAP_SUCCESS ) {
926                 /*
927                  * LDAP_OTHER is returned if no plugins are installed
928                  */
929                 rc = LDAP_OTHER;
930                 goto done;
931         }
932
933         i = 0;
934         do {
935                 Slapi_PluginDesc        *srchdesc;
936                 char                    buf[ BACKMONITOR_BUFSIZE ];
937                 struct berval           bv;
938
939                 rc = slapi_pblock_get( pCurrentPB, SLAPI_PLUGIN_DESCRIPTION,
940                                 &srchdesc );
941                 if ( rc != LDAP_SUCCESS ) {
942                         goto done;
943                 }
944                 if ( srchdesc ) {
945                         snprintf( buf, sizeof(buf),
946                                         "plugin %d name: %s; "
947                                         "vendor: %s; "
948                                         "version: %s; "
949                                         "description: %s", 
950                                         i,
951                                         srchdesc->spd_id,
952                                         srchdesc->spd_vendor,
953                                         srchdesc->spd_version,
954                                         srchdesc->spd_description );
955                 } else {
956                         snprintf( buf, sizeof(buf),
957                                         "plugin %d name: <no description available>", i );
958                 }
959
960                 ber_str2bv( buf, 0, 0, &bv );
961                 attr_merge_normalize_one( e_database,
962                                 mi->mi_ad_monitoredInfo, &bv, NULL );
963
964                 i++;
965
966         } while ( ( slapi_int_pblock_get_next( &pCurrentPB ) == LDAP_SUCCESS )
967                         && ( pCurrentPB != NULL ) );
968
969 done:
970         return rc;
971 }
972 #endif /* defined(LDAP_SLAPI) */