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