database.c 23.9 KB
Newer Older
1
/* database.c - deals with database subsystem */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
2
3
4
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
5
 * Copyright 2001-2020 The OpenLDAP Foundation.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
6
 * Portions Copyright 2001-2003 Pierangelo Masarati.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
 */
/* ACKNOWLEDGEMENTS:
 * This work was initially developed by Pierangelo Masarati for inclusion
 * in OpenLDAP Software.
 */
21
22
23
24

#include "portable.h"

#include <stdio.h>
25
#include <ac/string.h>
26
#include <ac/unistd.h>
27
28
29
30

#include "slap.h"
#include "back-monitor.h"

31
#if defined(LDAP_SLAPI)
32
#include "slapi.h"
Howard Chu's avatar
Howard Chu committed
33
static int monitor_back_add_plugin( monitor_info_t *mi, Backend *be, Entry *e );
34
35
#endif /* defined(LDAP_SLAPI) */

36
37
38
39
40
41
static int
monitor_subsys_database_modify(
	Operation	*op,
	SlapReply	*rs,
	Entry		*e );

42
static struct restricted_ops_t {
43
44
	struct berval	op;
	unsigned int	tag;
45
} restricted_ops[] = {
46
47
48
49
50
51
52
53
54
	{ BER_BVC( "add" ),			SLAP_RESTRICT_OP_ADD },
	{ BER_BVC( "bind" ),			SLAP_RESTRICT_OP_BIND },
	{ BER_BVC( "compare" ),			SLAP_RESTRICT_OP_COMPARE },
	{ BER_BVC( "delete" ),			SLAP_RESTRICT_OP_DELETE },
	{ BER_BVC( "extended" ),		SLAP_RESTRICT_OP_EXTENDED },
	{ BER_BVC( "modify" ),			SLAP_RESTRICT_OP_MODIFY },
	{ BER_BVC( "rename" ),			SLAP_RESTRICT_OP_RENAME },
	{ BER_BVC( "search" ),			SLAP_RESTRICT_OP_SEARCH },
	{ BER_BVNULL,				0 }
55
}, restricted_exops[] = {
56
57
	{ BER_BVC( LDAP_EXOP_START_TLS ),	SLAP_RESTRICT_EXOP_START_TLS },
	{ BER_BVC( LDAP_EXOP_MODIFY_PASSWD ),	SLAP_RESTRICT_EXOP_MODIFY_PASSWD },
Kurt Zeilenga's avatar
Kurt Zeilenga committed
58
59
	{ BER_BVC( LDAP_EXOP_WHO_AM_I ),	SLAP_RESTRICT_EXOP_WHOAMI },
	{ BER_BVC( LDAP_EXOP_CANCEL ),	SLAP_RESTRICT_EXOP_CANCEL },
60
61
62
63
	{ BER_BVNULL,				0 }
};

static int
64
init_readOnly( monitor_info_t *mi, Entry *e, slap_mask_t restrictops )
65
66
67
68
{
	struct berval	*tf = ( ( restrictops & SLAP_RESTRICT_OP_MASK ) == SLAP_RESTRICT_OP_WRITES ) ?
		(struct berval *)&slap_true_bv : (struct berval *)&slap_false_bv;

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
76
{
	int	i, rc;

77
78
	for ( i = 0; restricted_ops[ i ].op.bv_val; i++ ) {
		if ( restrictops & restricted_ops[ i ].tag ) {
79
			rc = attr_merge_one( e, mi->mi_ad_restrictedOperation,
80
81
					&restricted_ops[ i ].op,
					&restricted_ops[ i ].op );
82
83
84
85
86
87
			if ( rc ) {
				return rc;
			}
		}
	}

88
89
	for ( i = 0; restricted_exops[ i ].op.bv_val; i++ ) {
		if ( restrictops & restricted_exops[ i ].tag ) {
90
			rc = attr_merge_one( e, mi->mi_ad_restrictedOperation,
91
92
					&restricted_exops[ i ].op,
					&restricted_exops[ i ].op );
93
94
95
96
97
98
99
100
101
			if ( rc ) {
				return rc;
			}
		}
	}

	return LDAP_SUCCESS;
}

102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
static int
monitor_subsys_overlay_init_one(
	monitor_info_t		*mi,
	BackendDB		*be,
	monitor_subsys_t	*ms,
	monitor_subsys_t	*ms_overlay,
	slap_overinst		*on,
	Entry			*e_database,
	Entry			**ep_overlay )
{
	char			buf[ BACKMONITOR_BUFSIZE ];
	int			j, o;
	Entry			*e_overlay;
	slap_overinst		*on2;
	slap_overinfo		*oi = NULL;
	BackendInfo		*bi;
	monitor_entry_t		*mp_overlay;
	struct berval		bv;

	assert( overlay_is_over( be ) );

	oi = (slap_overinfo *)be->bd_info->bi_private;
	bi = oi->oi_orig;

	/* find the overlay number, o */
	for ( o = 0, on2 = oi->oi_list; on2 && on2 != on; on2 = on2->on_next, o++ )
		;

	if ( on2 == NULL ) {
		return -1;
	}

	/* find the overlay type number, j */
	for ( on2 = overlay_next( NULL ), j = 0; on2; on2 = overlay_next( on2 ), j++ ) {
		if ( on2->on_bi.bi_type == on->on_bi.bi_type ) {
			break;
		}
	}
	assert( on2 != NULL );

	bv.bv_len = snprintf( buf, sizeof( buf ), "cn=Overlay %d", o );
	bv.bv_val = buf;

	e_overlay = monitor_entry_stub( &e_database->e_name, &e_database->e_nname, &bv,
146
		mi->mi_oc_monitoredObject, NULL, NULL );
147
148
149
150
151
152

	if ( e_overlay == NULL ) {
		Debug( LDAP_DEBUG_ANY,
			"monitor_subsys_overlay_init_one: "
			"unable to create entry "
			"\"cn=Overlay %d,%s\"\n",
153
			o, e_database->e_name.bv_val );
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
		return( -1 );
	}
	ber_str2bv( on->on_bi.bi_type, 0, 0, &bv );
	attr_merge_normalize_one( e_overlay, mi->mi_ad_monitoredInfo, &bv, NULL );

	bv.bv_len = snprintf( buf, sizeof( buf ), "cn=Overlay %d,%s",
		j, ms_overlay->mss_dn.bv_val );
	bv.bv_val = buf;
	attr_merge_normalize_one( e_overlay, slap_schema.si_ad_seeAlso,
		&bv, NULL );

	if ( SLAP_MONITOR( be ) ) {
		attr_merge( e_overlay, slap_schema.si_ad_monitorContext,
				be->be_suffix, be->be_nsuffix );

	} else {
		attr_merge( e_overlay, slap_schema.si_ad_namingContexts,
				be->be_suffix, NULL );
	}

	mp_overlay = monitor_entrypriv_create();
	if ( mp_overlay == NULL ) {
		return -1;
	}
	e_overlay->e_private = ( void * )mp_overlay;
	mp_overlay->mp_info = ms;
	mp_overlay->mp_flags = ms->mss_flags | MONITOR_F_SUB;
	
	if ( monitor_cache_add( mi, e_overlay ) ) {
		Debug( LDAP_DEBUG_ANY,
			"monitor_subsys_overlay_init_one: "
			"unable to add entry "
			"\"cn=Overlay %d,%s\"\n",
187
			o, e_database->e_name.bv_val );
188
189
190
191
192
193
194
195
196
		return -1;
	}

	*ep_overlay = e_overlay;
	ep_overlay = &mp_overlay->mp_next;

	return 0;
}

197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
static int
monitor_subsys_database_init_one(
	monitor_info_t		*mi,
	BackendDB		*be,
	monitor_subsys_t	*ms,
	monitor_subsys_t	*ms_backend,
	monitor_subsys_t	*ms_overlay,
	struct berval		*rdn,
	Entry			*e_database,
	Entry			***epp )
{
	char			buf[ BACKMONITOR_BUFSIZE ];
	int			j;
	slap_overinfo		*oi = NULL;
	BackendInfo		*bi, *bi2;
	Entry			*e;
	monitor_entry_t		*mp;
	char			*rdnval = strchr( rdn->bv_val, '=' ) + 1;
	struct berval		bv;

	bi = be->bd_info;

Howard Chu's avatar
Howard Chu committed
219
220
221
222
	if ( be->be_suffix == NULL ) {
		Debug( LDAP_DEBUG_ANY,
			"monitor_subsys_database_init_one: "
			"missing suffix for %s\n",
223
			rdnval );
Howard Chu's avatar
Howard Chu committed
224
225
226
		return( -1 );
	}

227
228
229
230
231
232
	if ( overlay_is_over( be ) ) {
		oi = (slap_overinfo *)be->bd_info->bi_private;
		bi = oi->oi_orig;
	}

	e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, rdn,
233
		mi->mi_oc_monitoredObject, NULL, NULL );
234
235
236

	if ( e == NULL ) {
		Debug( LDAP_DEBUG_ANY,
237
			"monitor_subsys_database_init_one: "
238
			"unable to create entry \"%s,%s\"\n",
239
			rdn->bv_val, ms->mss_dn.bv_val );
240
241
242
243
		return( -1 );
	}

	ber_str2bv( bi->bi_type, 0, 0, &bv );
244
	attr_merge_normalize_one( e, mi->mi_ad_monitoredInfo, &bv, NULL );
245
246
247
248
249
250
251
252
253
254
255
	attr_merge_one( e, mi->mi_ad_monitorIsShadow,
		SLAP_SHADOW( be ) ? (struct berval *)&slap_true_bv :
			(struct berval *)&slap_false_bv, NULL );

	if ( SLAP_MONITOR( be ) ) {
		attr_merge( e, slap_schema.si_ad_monitorContext,
				be->be_suffix, be->be_nsuffix );
		attr_merge( e_database, slap_schema.si_ad_monitorContext,
				be->be_suffix, be->be_nsuffix );

	} else {
Howard Chu's avatar
Howard Chu committed
256
257
258
259
		attr_merge( e, slap_schema.si_ad_namingContexts,
			be->be_suffix, NULL );
		attr_merge( e_database, slap_schema.si_ad_namingContexts,
			be->be_suffix, NULL );
260
261
262
263
264
265
266

		if ( SLAP_GLUE_SUBORDINATE( be ) ) {
			BackendDB *sup_be = select_backend( &be->be_nsuffix[ 0 ], 1 );
			if ( sup_be == NULL ) {
				Debug( LDAP_DEBUG_ANY,
					"monitor_subsys_database_init: "
					"unable to get superior for %s\n",
267
					be->be_suffix[ 0 ].bv_val );
268
269
270
271
272
273

			} else {
				attr_merge( e, mi->mi_ad_monitorSuperiorDN,
					sup_be->be_suffix, sup_be->be_nsuffix );
			}
		}
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
	}

	(void)init_readOnly( mi, e, be->be_restrictops );
	(void)init_restrictedOperation( mi, e, be->be_restrictops );

	if ( SLAP_SHADOW( be ) && be->be_update_refs ) {
		attr_merge_normalize( e, mi->mi_ad_monitorUpdateRef,
				be->be_update_refs, NULL );
	}

	if ( oi != NULL ) {
		slap_overinst	*on = oi->oi_list,
				*on1 = on;

		for ( ; on; on = on->on_next ) {
			slap_overinst		*on2;

			for ( on2 = on1; on2 != on; on2 = on2->on_next ) {
				if ( on2->on_bi.bi_type == on->on_bi.bi_type ) {
					break;
				}
			}

			if ( on2 != on ) {
				break;
			}
			
			ber_str2bv( on->on_bi.bi_type, 0, 0, &bv );
			attr_merge_normalize_one( e, mi->mi_ad_monitorOverlay,
					&bv, NULL );

			/* find the overlay number, j */
			for ( on2 = overlay_next( NULL ), j = 0; on2; on2 = overlay_next( on2 ), j++ ) {
				if ( on2->on_bi.bi_type == on->on_bi.bi_type ) {
					break;
				}
			}
			assert( on2 != NULL );

			snprintf( buf, sizeof( buf ), 
				"cn=Overlay %d,%s", 
				j, ms_overlay->mss_dn.bv_val );
			ber_str2bv( buf, 0, 0, &bv );
			attr_merge_normalize_one( e,
					slap_schema.si_ad_seeAlso,
					&bv, NULL );
		}
	}

	j = -1;
	LDAP_STAILQ_FOREACH( bi2, &backendInfo, bi_next ) {
		j++;
		if ( bi2->bi_type == bi->bi_type ) {
			snprintf( buf, sizeof( buf ), 
				"cn=Backend %d,%s", 
				j, ms_backend->mss_dn.bv_val );
			bv.bv_val = buf;
			bv.bv_len = strlen( buf );
			attr_merge_normalize_one( e,
					slap_schema.si_ad_seeAlso,
					&bv, NULL );
			break;
		}
	}
	/* we must find it! */
	assert( j >= 0 );

	mp = monitor_entrypriv_create();
	if ( mp == NULL ) {
		return -1;
	}
	e->e_private = ( void * )mp;
	mp->mp_info = ms;
	mp->mp_flags = ms->mss_flags
		| MONITOR_F_SUB;
349
	mp->mp_private = be;
350
351
352

	if ( monitor_cache_add( mi, e ) ) {
		Debug( LDAP_DEBUG_ANY,
353
			"monitor_subsys_database_init_one: "
354
			"unable to add entry \"%s,%s\"\n",
355
			rdn->bv_val, ms->mss_dn.bv_val );
356
357
358
359
360
361
362
363
364
365
366
		return( -1 );
	}

#if defined(LDAP_SLAPI)
	monitor_back_add_plugin( mi, be, e );
#endif /* defined(LDAP_SLAPI) */

	if ( oi != NULL ) {
		Entry		**ep_overlay = &mp->mp_children;
		slap_overinst	*on = oi->oi_list;

367
368
369
		for ( ; on; on = on->on_next ) {
			monitor_subsys_overlay_init_one( mi, be,
				ms, ms_overlay, on, e, ep_overlay );
370
371
372
373
374
375
376
377
378
		}
	}

	**epp = e;
	*epp = &mp->mp_next;

	return 0;
}

379
380
static int
monitor_back_register_database_and_overlay(
381
	BackendDB		*be,
382
383
	struct slap_overinst	*on,
	struct berval		*ndn_out )
384
385
386
387
388
389
390
391
392
{
	monitor_info_t		*mi;
	Entry			*e_database, **ep;
	int			i, rc;
	monitor_entry_t		*mp;
	monitor_subsys_t	*ms_backend,
				*ms_database,
				*ms_overlay;
	struct berval		bv;
393
	char			buf[ BACKMONITOR_BUFSIZE ];
394
395
396

	assert( be_monitor != NULL );

397
	if ( !monitor_subsys_is_opened() ) {
398
399
400
401
402
403
		if ( on ) {
			return monitor_back_register_overlay_limbo( be, on, ndn_out );

		} else {
			return monitor_back_register_database_limbo( be, ndn_out );
		}
404
405
	}

406
407
408
409
410
411
412
413
	mi = ( monitor_info_t * )be_monitor->be_private;

	ms_backend = monitor_back_get_subsys( SLAPD_MONITOR_BACKEND_NAME );
	if ( ms_backend == NULL ) {
		Debug( LDAP_DEBUG_ANY,
			"monitor_back_register_database: "
			"unable to get "
			"\"" SLAPD_MONITOR_BACKEND_NAME "\" "
414
			"subsystem\n" );
415
416
417
418
		return -1;
	}

	ms_database = monitor_back_get_subsys( SLAPD_MONITOR_DATABASE_NAME );
Howard Chu's avatar
Howard Chu committed
419
	if ( ms_database == NULL ) {
420
421
422
423
		Debug( LDAP_DEBUG_ANY,
			"monitor_back_register_database: "
			"unable to get "
			"\"" SLAPD_MONITOR_DATABASE_NAME "\" "
424
			"subsystem\n" );
425
426
427
428
429
430
431
432
433
		return -1;
	}

	ms_overlay = monitor_back_get_subsys( SLAPD_MONITOR_OVERLAY_NAME );
	if ( ms_overlay == NULL ) {
		Debug( LDAP_DEBUG_ANY,
			"monitor_back_register_database: "
			"unable to get "
			"\"" SLAPD_MONITOR_OVERLAY_NAME "\" "
434
			"subsystem\n" );
435
436
437
438
439
440
441
		return -1;
	}

	if ( monitor_cache_get( mi, &ms_database->mss_ndn, &e_database ) ) {
		Debug( LDAP_DEBUG_ANY,
			"monitor_subsys_database_init: "
			"unable to get entry \"%s\"\n",
442
			ms_database->mss_ndn.bv_val );
443
444
445
446
447
448
449
450
		return( -1 );
	}

	mp = ( monitor_entry_t * )e_database->e_private;
	for ( i = -1, ep = &mp->mp_children; *ep; i++ ) {
		mp = ( monitor_entry_t * )(*ep)->e_private;

		assert( mp != NULL );
451
452
453
454
		if ( mp->mp_private == be->bd_self ) {
			rc = 0;
			goto done;
		}
455
456
457
		ep = &mp->mp_next;
	}

458
459
460
461
462
	bv.bv_val = buf;
	bv.bv_len = snprintf( buf, sizeof( buf ), "cn=Database %d", i );
	if ( bv.bv_len >= sizeof( buf ) ) {
		rc = -1;
		goto done;
463
464
	}
	
465
466
467
468
469
	rc = monitor_subsys_database_init_one( mi, be,
		ms_database, ms_backend, ms_overlay, &bv, e_database, &ep );
	if ( rc != 0 ) {
		goto done;
	}
Howard Chu's avatar
Howard Chu committed
470
471
472
	/* database_init_one advanced ep past where we want.
	 * But it stored the entry we want in mp->mp_next.
	 */
Howard Chu's avatar
Howard Chu committed
473
	ep = &mp->mp_next;
474
475

done:;
476
	monitor_cache_release( mi, e_database );
477
478
479
480
481
482
483
484
485
	if ( rc == 0 && ndn_out && ep && *ep ) {
		if ( on ) {
			Entry *e_ov;
			struct berval ov_type;

			ber_str2bv( on->on_bi.bi_type, 0, 0, &ov_type );

			mp = ( monitor_entry_t * ) (*ep)->e_private;
			for ( e_ov = mp->mp_children; e_ov; ) {
Howard Chu's avatar
Howard Chu committed
486
				Attribute *a = attr_find( e_ov->e_attrs, mi->mi_ad_monitoredInfo );
487
488
489
490
491
492
493
494
495
496
497
498
499

				if ( a != NULL && bvmatch( &a->a_nvals[ 0 ], &ov_type ) ) {
					*ndn_out = e_ov->e_nname;
					break;
				}

				mp = ( monitor_entry_t * ) e_ov->e_private;
				e_ov = mp->mp_next;
			}
			
		} else {
			*ndn_out = (*ep)->e_nname;
		}
500
	}
501

502
	return rc;
503
504
}

505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
int
monitor_back_register_database(
	BackendDB		*be,
	struct berval		*ndn_out )
{
	return monitor_back_register_database_and_overlay( be, NULL, ndn_out );
}

int
monitor_back_register_overlay(
	BackendDB		*be,
	struct slap_overinst	*on,
	struct berval		*ndn_out )
{
	return monitor_back_register_database_and_overlay( be, on, ndn_out );
}

522
523
int
monitor_subsys_database_init(
524
	BackendDB		*be,
525
	monitor_subsys_t	*ms )
526
{
527
	monitor_info_t		*mi;
528
	Entry			*e_database, **ep;
529
	int			i, rc;
530
531
	monitor_entry_t		*mp;
	monitor_subsys_t	*ms_backend,
532
				*ms_overlay;
533
	struct berval		bv;
534
535
536

	assert( be != NULL );

537
538
	ms->mss_modify = monitor_subsys_database_modify;

539
	mi = ( monitor_info_t * )be->be_private;
540

541
542
543
544
545
546
	ms_backend = monitor_back_get_subsys( SLAPD_MONITOR_BACKEND_NAME );
	if ( ms_backend == NULL ) {
		Debug( LDAP_DEBUG_ANY,
			"monitor_subsys_database_init: "
			"unable to get "
			"\"" SLAPD_MONITOR_BACKEND_NAME "\" "
547
			"subsystem\n" );
548
549
550
551
552
553
554
555
556
		return -1;
	}

	ms_overlay = monitor_back_get_subsys( SLAPD_MONITOR_OVERLAY_NAME );
	if ( ms_overlay == NULL ) {
		Debug( LDAP_DEBUG_ANY,
			"monitor_subsys_database_init: "
			"unable to get "
			"\"" SLAPD_MONITOR_OVERLAY_NAME "\" "
557
			"subsystem\n" );
558
559
560
561
		return -1;
	}

	if ( monitor_cache_get( mi, &ms->mss_ndn, &e_database ) ) {
562
563
		Debug( LDAP_DEBUG_ANY,
			"monitor_subsys_database_init: "
564
			"unable to get entry \"%s\"\n",
565
			ms->mss_ndn.bv_val );
566
567
		return( -1 );
	}
568

569
570
	(void)init_readOnly( mi, e_database, frontendDB->be_restrictops );
	(void)init_restrictedOperation( mi, e_database, frontendDB->be_restrictops );
571

572
	mp = ( monitor_entry_t * )e_database->e_private;
573
574
575
	mp->mp_children = NULL;
	ep = &mp->mp_children;

576
577
578
579
580
581
582
	BER_BVSTR( &bv, "cn=Frontend" );
	rc = monitor_subsys_database_init_one( mi, frontendDB,
		ms, ms_backend, ms_overlay, &bv, e_database, &ep );
	if ( rc != 0 ) {
		return rc;
	}

583
584
	i = -1;
	LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
585
		char		buf[ BACKMONITOR_BUFSIZE ];
586

587
		bv.bv_val = buf;
588
589
		bv.bv_len = snprintf( buf, sizeof( buf ), "cn=Database %d", ++i );
		if ( bv.bv_len >= sizeof( buf ) ) {
590
591
			return -1;
		}
592
		
593
594
595
596
		rc = monitor_subsys_database_init_one( mi, be,
			ms, ms_backend, ms_overlay, &bv, e_database, &ep );
		if ( rc != 0 ) {
			return rc;
597
		}
598
599
600
601
602
603
604
	}
	
	monitor_cache_release( mi, e_database );

	return( 0 );
}

605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
/*
 * v: array of values
 * cur: must not contain the tags corresponding to the values in v
 * delta: will contain the tags corresponding to the values in v
 */
static int
value_mask( BerVarray v, slap_mask_t cur, slap_mask_t *delta )
{
	for ( ; !BER_BVISNULL( v ); v++ ) {
		struct restricted_ops_t		*rops;
		int				i;

		if ( OID_LEADCHAR( v->bv_val[ 0 ] ) ) {
			rops = restricted_exops;

		} else {
			rops = restricted_ops;
		}

		for ( i = 0; !BER_BVISNULL( &rops[ i ].op ); i++ ) {
			if ( ber_bvstrcasecmp( v, &rops[ i ].op ) != 0 ) {
				continue;
			}

			if ( rops[ i ].tag & *delta ) {
				return LDAP_OTHER;
			}

			if ( rops[ i ].tag & cur ) {
				return LDAP_OTHER;
			}

			cur |= rops[ i ].tag;
			*delta |= rops[ i ].tag;

			break;
		}

		if ( BER_BVISNULL( &rops[ i ].op ) ) {
			return LDAP_INVALID_SYNTAX;
		}
	}

	return LDAP_SUCCESS;
}

651
static int
652
653
monitor_subsys_database_modify(
	Operation	*op,
654
	SlapReply	*rs,
655
	Entry		*e )
656
{
657
658
659
660
661
662
	monitor_info_t	*mi = (monitor_info_t *)op->o_bd->be_private;
	int		rc = LDAP_OTHER;
	Attribute	*save_attrs, *a;
	Modifications	*ml;
	Backend		*be;
	int		ro_gotval = 1, i, n;
663
	slap_mask_t	rp_add = 0, rp_delete = 0, rp_cur;
664
	struct berval	*tf;
665
666
	
	i = sscanf( e->e_nname.bv_val, "cn=database %d,", &n );
667
668
669
	if ( i != 1 ) {
		return SLAP_CB_CONTINUE;
	}
670

671
672
673
674
	if ( n < 0 || n >= nBackendDB ) {
		rs->sr_text = "invalid database index";
		return ( rs->sr_err = LDAP_NO_SUCH_OBJECT );
	}
675

676
	LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) {
677
678
679
		if ( n == 0 ) {
			break;
		}
680
681
		n--;
	}
682
	/* do not allow some changes on back-monitor (needs work)... */
683
684
685
686
	if ( SLAP_MONITOR( be ) ) {
		rs->sr_text = "no modifications allowed to monitor database entry";
		return ( rs->sr_err = LDAP_UNWILLING_TO_PERFORM );
	}
687
		
688
	rp_cur = be->be_restrictops;
689
690
691
692

	save_attrs = e->e_attrs;
	e->e_attrs = attrs_dup( e->e_attrs );

693
	for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
694
695
696
		Modification *mod = &ml->sml_mod;

		if ( mod->sm_desc == mi->mi_ad_readOnly ) {
697
			int	val = -1;
698
699

			if ( mod->sm_values ) {
700
				if ( !BER_BVISNULL( &mod->sm_values[ 1 ] ) ) {
701
702
					rs->sr_text = "attempting to modify multiple values of single-valued attribute";
					rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
703
					goto done;
704
				}
705

706
707
				if ( bvmatch( &slap_true_bv, mod->sm_values )) {
					val = 1;
708

709
710
				} else if ( bvmatch( &slap_false_bv, mod->sm_values )) {
					val = 0;
711
712

				} else {
713
714
					assert( 0 );
					rc = rs->sr_err = LDAP_INVALID_SYNTAX;
715
					goto done;
716
717
				}
			}
718
719

			switch ( mod->sm_op ) {
720
			case LDAP_MOD_DELETE:
721
				if ( ro_gotval < 1 ) {
722
					rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
723
724
725
726
727
					goto done;
				}
				ro_gotval--;

				if ( val == 0 && ( rp_cur & SLAP_RESTRICT_OP_WRITES ) == SLAP_RESTRICT_OP_WRITES ) {
728
					rc = rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE;
729
					goto done;
730
				}
731
732
				
				if ( val == 1 && ( rp_cur & SLAP_RESTRICT_OP_WRITES ) != SLAP_RESTRICT_OP_WRITES ) {
733
					rc = rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE;
734
735
736
					goto done;
				}
				
737
				break;
738

739
			case LDAP_MOD_REPLACE:
740
741
742
				ro_gotval = 0;
				/* fall thru */

743
			case LDAP_MOD_ADD:
744
				if ( ro_gotval > 0 ) {
745
					rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
746
747
748
749
750
751
752
753
754
755
756
757
758
					goto done;
				}
				ro_gotval++;

				if ( val == 1 ) {
					rp_add |= (~rp_cur) & SLAP_RESTRICT_OP_WRITES;
					rp_cur |= SLAP_RESTRICT_OP_WRITES;
					rp_delete &= ~SLAP_RESTRICT_OP_WRITES;
					
				} else if ( val == 0 ) {
					rp_delete |= rp_cur & SLAP_RESTRICT_OP_WRITES;
					rp_cur &= ~SLAP_RESTRICT_OP_WRITES;
					rp_add &= ~SLAP_RESTRICT_OP_WRITES;
759
760
				}
				break;
761

762
			default:
763
				rc = rs->sr_err = LDAP_OTHER;
764
				goto done;
765
			}
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802

		} else if ( mod->sm_desc == mi->mi_ad_restrictedOperation ) {
			slap_mask_t	mask = 0;

			switch ( mod->sm_op ) {
			case LDAP_MOD_DELETE:
				if ( mod->sm_values == NULL ) {
					rp_delete = rp_cur;
					rp_cur = 0;
					rp_add = 0;
					break;
				}
				rc = value_mask( mod->sm_values, ~rp_cur, &mask );
				if ( rc == LDAP_SUCCESS ) {
					rp_delete |= mask;
					rp_add &= ~mask;
					rp_cur &= ~mask;

				} else if ( rc == LDAP_OTHER ) {
					rc = LDAP_NO_SUCH_ATTRIBUTE;
				}
				break;

			case LDAP_MOD_REPLACE:
				rp_delete = rp_cur;
				rp_cur = 0;
				rp_add = 0;
				/* fall thru */

			case LDAP_MOD_ADD:
				rc = value_mask( mod->sm_values, rp_cur, &mask );
				if ( rc == LDAP_SUCCESS ) {
					rp_add |= mask;
					rp_cur |= mask;
					rp_delete &= ~mask;

				} else if ( rc == LDAP_OTHER ) {
803
					rc = rs->sr_err = LDAP_TYPE_OR_VALUE_EXISTS;
804
805
806
807
				}
				break;

			default:
808
				rc = rs->sr_err = LDAP_OTHER;
809
810
				break;
			}
811

812
813
814
			if ( rc != LDAP_SUCCESS ) {
				goto done;
			}
815

816
817
818
819
820
821
		} else if ( is_at_operational( mod->sm_desc->ad_type )) {
		/* accept all operational attributes */
			attr_delete( &e->e_attrs, mod->sm_desc );
			rc = attr_merge( e, mod->sm_desc, mod->sm_values,
				mod->sm_nvalues );
			if ( rc ) {
822
				rc = rs->sr_err = LDAP_OTHER;
823
824
				break;
			}
825

826
		} else {
827
			rc = rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
828
829
830
			break;
		}
	}
831

832
833
	/* sanity checks: */
	if ( ro_gotval < 1 ) {
834
		rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
835
836
837
838
		goto done;
	}

	if ( ( rp_cur & SLAP_RESTRICT_OP_EXTENDED ) && ( rp_cur & SLAP_RESTRICT_EXOP_MASK ) ) {
839
		rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
840
841
842
843
		goto done;
	}

	if ( rp_delete & rp_add ) {
844
		rc = rs->sr_err = LDAP_OTHER;
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
		goto done;
	}

	/* check current value of readOnly */
	if ( ( rp_cur & SLAP_RESTRICT_OP_WRITES ) == SLAP_RESTRICT_OP_WRITES ) {
		tf = (struct berval *)&slap_true_bv;

	} else {
		tf = (struct berval *)&slap_false_bv;
	}

	a = attr_find( e->e_attrs, mi->mi_ad_readOnly );
	if ( a == NULL ) {
		rc = LDAP_OTHER;
		goto done;
	}

862
	if ( !bvmatch( &a->a_vals[ 0 ], tf ) ) {
863
		attr_delete( &e->e_attrs, mi->mi_ad_readOnly );
864
		rc = attr_merge_one( e, mi->mi_ad_readOnly, tf, tf );
865
866
867
868
869
870
871
	}

	if ( rc == LDAP_SUCCESS ) {
		if ( rp_delete ) {
			if ( rp_delete == be->be_restrictops ) {
				attr_delete( &e->e_attrs, mi->mi_ad_restrictedOperation );

872
			} else {
873
874
				a = attr_find( e->e_attrs, mi->mi_ad_restrictedOperation );
				if ( a == NULL ) {
875
					rc = rs->sr_err = LDAP_OTHER;
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
					goto done;
				}

				for ( i = 0; !BER_BVISNULL( &restricted_ops[ i ].op ); i++ ) {
					if ( rp_delete & restricted_ops[ i ].tag ) {
						int	j;
					
						for ( j = 0; !BER_BVISNULL( &a->a_nvals[ j ] ); j++ ) {
							int		k;

							if ( !bvmatch( &a->a_nvals[ j ], &restricted_ops[ i ].op ) ) {
								continue;
							}

							ch_free( a->a_vals[ j ].bv_val );
							ch_free( a->a_nvals[ j ].bv_val );

							for ( k = j + 1; !BER_BVISNULL( &a->a_nvals[ k ] ); k++ ) {
								a->a_vals[ k - 1 ] = a->a_vals[ k ];
								a->a_nvals[ k - 1 ] = a->a_nvals[ k ];
							}
	
							BER_BVZERO( &a->a_vals[ k - 1 ] );
							BER_BVZERO( &a->a_nvals[ k - 1 ] );
900
							a->a_numvals--;
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
						}
					}
				}
				
				for ( i = 0; !BER_BVISNULL( &restricted_exops[ i ].op ); i++ ) {
					if ( rp_delete & restricted_exops[ i ].tag ) {
						int	j;
					
						for ( j = 0; !BER_BVISNULL( &a->a_nvals[ j ] ); j++ ) {
							int		k;

							if ( !bvmatch( &a->a_nvals[ j ], &restricted_exops[ i ].op ) ) {
								continue;
							}

							ch_free( a->a_vals[ j ].bv_val );
							ch_free( a->a_nvals[ j ].bv_val );

							for ( k = j + 1; !BER_BVISNULL( &a->a_nvals[ k ] ); k++ ) {
								a->a_vals[ k - 1 ] = a->a_vals[ k ];
								a->a_nvals[ k - 1 ] = a->a_nvals[ k ];
							}
	
							BER_BVZERO( &a->a_vals[ k - 1 ] );
							BER_BVZERO( &a->a_nvals[ k - 1 ] );
926
							a->a_numvals--;
927
928
929
						}
					}
				}
930
931
932
933
934
935

				if ( a->a_vals == NULL ) {
					assert( a->a_numvals == 0 );

					attr_delete( &e->e_attrs, mi->mi_ad_restrictedOperation );
				}
936
937
938
939
940
941
942
			}
		}

		if ( rp_add ) {
			for ( i = 0; !BER_BVISNULL( &restricted_ops[ i ].op ); i++ ) {
				if ( rp_add & restricted_ops[ i ].tag ) {
					attr_merge_one( e, mi->mi_ad_restrictedOperation,
943
944
							&restricted_ops[ i ].op,
							&restricted_ops[ i ].op );
945
946
947
948
949
950
				}
			}

			for ( i = 0; !BER_BVISNULL( &restricted_exops[ i ].op ); i++ ) {
				if ( rp_add & restricted_exops[ i ].tag ) {
					attr_merge_one( e, mi->mi_ad_restrictedOperation,
951
952
							&restricted_exops[ i ].op,
							&restricted_exops[ i ].op );
953
				}
954
955
956
			}
		}
	}
957
958
959
960

	be->be_restrictops = rp_cur;

done:;
961
962
	if ( rc == LDAP_SUCCESS ) {
		attrs_free( save_attrs );
963
		rc = SLAP_CB_CONTINUE;
964

965
966
967
968
969
970
971
972
	} else {
		Attribute *tmp = e->e_attrs;
		e->e_attrs = save_attrs;
		attrs_free( tmp );
	}
	return rc;
}

973
974
#if defined(LDAP_SLAPI)
static int
Howard Chu's avatar
Howard Chu committed
975
monitor_back_add_plugin( monitor_info_t *mi, Backend *be, Entry *e_database )
976
{
977
978
	Slapi_PBlock	*pCurrentPB; 
	int		i, rc = LDAP_SUCCESS;
979

980
	if ( slapi_int_pblock_get_first( be, &pCurrentPB ) != LDAP_SUCCESS ) {
981
982
983
984
985
986
987
988
989
990
		/*
		 * LDAP_OTHER is returned if no plugins are installed
		 */
		rc = LDAP_OTHER;
		goto done;
	}

	i = 0;
	do {
		Slapi_PluginDesc	*srchdesc;
991
		char			buf[ BACKMONITOR_BUFSIZE ];
992
993
994
995
996
997
998
		struct berval		bv;

		rc = slapi_pblock_get( pCurrentPB, SLAPI_PLUGIN_DESCRIPTION,
				&srchdesc );
		if ( rc != LDAP_SUCCESS ) {
			goto done;
		}
999
1000
		if ( srchdesc ) {
			snprintf( buf, sizeof(buf),
For faster browsing, not all history is shown. View entire blame