database.c 22.2 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/>.
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
 * Copyright 2001-2008 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"
Kurt Zeilenga's avatar
Kurt Zeilenga 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
#if defined(SLAPD_BDB)
#include "../back-bdb/back-bdb.h"
#endif /* defined(SLAPD_BDB) */
#if defined(SLAPD_HDB)
#include "../back-hdb/back-bdb.h"
#endif /* defined(SLAPD_HDB) */
42
43
44
#if defined(SLAPD_LDAP) 
#include "../back-ldap/back-ldap.h"
#endif /* defined(SLAPD_LDAP) */
45
46
47
#if 0 && defined(SLAPD_LDBM) 
#include "../back-ldbm/back-ldbm.h"
#endif /* defined(SLAPD_LDBM) */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
48
49
50
#if defined(SLAPD_META) 
#include "../back-meta/back-meta.h"
#endif /* defined(SLAPD_META) */
51

Kurt Zeilenga's avatar
Kurt Zeilenga committed
52
53
54
55
56
57
static int
monitor_subsys_database_modify(
	Operation	*op,
	SlapReply	*rs,
	Entry		*e );

58
static struct restricted_ops_t {
59
60
	struct berval	op;
	unsigned int	tag;
61
} restricted_ops[] = {
62
63
64
65
66
67
68
69
70
	{ 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 }
71
}, restricted_exops[] = {
72
73
74
75
76
77
78
79
	{ BER_BVC( LDAP_EXOP_START_TLS ),	SLAP_RESTRICT_EXOP_START_TLS },
	{ BER_BVC( LDAP_EXOP_MODIFY_PASSWD ),	SLAP_RESTRICT_EXOP_MODIFY_PASSWD },
	{ BER_BVC( LDAP_EXOP_X_WHO_AM_I ),	SLAP_RESTRICT_EXOP_WHOAMI },
	{ BER_BVC( LDAP_EXOP_X_CANCEL ),	SLAP_RESTRICT_EXOP_CANCEL },
	{ BER_BVNULL,				0 }
};

static int
80
init_readOnly( monitor_info_t *mi, Entry *e, slap_mask_t restrictops )
81
82
83
84
{
	struct berval	*tf = ( ( restrictops & SLAP_RESTRICT_OP_MASK ) == SLAP_RESTRICT_OP_WRITES ) ?
		(struct berval *)&slap_true_bv : (struct berval *)&slap_false_bv;

85
	return attr_merge_one( e, mi->mi_ad_readOnly, tf, tf );
86
87
88
}

static int
89
init_restrictedOperation( monitor_info_t *mi, Entry *e, slap_mask_t restrictops )
90
91
92
{
	int	i, rc;

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

104
105
	for ( i = 0; restricted_exops[ i ].op.bv_val; i++ ) {
		if ( restrictops & restricted_exops[ i ].tag ) {
106
			rc = attr_merge_one( e, mi->mi_ad_restrictedOperation,
107
108
					&restricted_exops[ i ].op,
					&restricted_exops[ i ].op );
109
110
111
112
113
114
115
116
117
			if ( rc ) {
				return rc;
			}
		}
	}

	return LDAP_SUCCESS;
}

118
119
int
monitor_subsys_database_init(
120
121
	BackendDB		*be,
	monitor_subsys_t	*ms
122
123
)
{
124
	monitor_info_t		*mi;
125
	Entry			*e_database, **ep;
126
	int			i;
127
128
	monitor_entry_t		*mp;
	monitor_subsys_t	*ms_backend,
129
				*ms_overlay;
130
131
132

	assert( be != NULL );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
133
134
	ms->mss_modify = monitor_subsys_database_modify;

135
	mi = ( monitor_info_t * )be->be_private;
136

137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
	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 "\" "
			"subsystem\n",
			0, 0, 0 );
		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 "\" "
			"subsystem\n",
			0, 0, 0 );
		return -1;
	}

	if ( monitor_cache_get( mi, &ms->mss_ndn, &e_database ) ) {
160
161
		Debug( LDAP_DEBUG_ANY,
			"monitor_subsys_database_init: "
162
			"unable to get entry \"%s\"\n",
163
			ms->mss_ndn.bv_val, 0, 0 );
164
165
		return( -1 );
	}
166

167
168
	(void)init_readOnly( mi, e_database, frontendDB->be_restrictops );
	(void)init_restrictedOperation( mi, e_database, frontendDB->be_restrictops );
169

170
	mp = ( monitor_entry_t * )e_database->e_private;
171
172
173
	mp->mp_children = NULL;
	ep = &mp->mp_children;

174
175
	i = -1;
	LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
176
177
178
		char		buf[ BACKMONITOR_BUFSIZE ];
		int		j;
		slap_overinfo	*oi = NULL;
179
		BackendInfo	*bi, *bi2;
180
		Entry		*e;
181

182
		i++;
183

184
185
		bi = be->bd_info;

Pierangelo Masarati's avatar
Pierangelo Masarati committed
186
		if ( overlay_is_over( be ) ) {
Howard Chu's avatar
Howard Chu committed
187
			oi = (slap_overinfo *)be->bd_info->bi_private;
188
			bi = oi->oi_orig;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
189
190
		}

191
		/* Subordinates are not exposed as their own naming context */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
192
		if ( SLAP_GLUE_SUBORDINATE( be ) ) {
193
194
195
			continue;
		}

196
		snprintf( buf, sizeof( buf ),
197
				"dn: cn=Database %d,%s\n"
198
199
				"objectClass: %s\n"
				"structuralObjectClass: %s\n"
200
				"cn: Database %d\n"
201
				"%s: %s\n"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
202
				"%s: %s\n"
203
204
				"creatorsName: %s\n"
				"modifiersName: %s\n"
205
206
				"createTimestamp: %s\n"
				"modifyTimestamp: %s\n",
207
				i,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
208
					ms->mss_dn.bv_val,
209
210
				mi->mi_oc_monitoredObject->soc_cname.bv_val,
				mi->mi_oc_monitoredObject->soc_cname.bv_val,
211
				i,
212
				mi->mi_ad_monitoredInfo->ad_cname.bv_val,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
213
214
215
					bi->bi_type,
				mi->mi_ad_monitorIsShadow->ad_cname.bv_val,
					SLAP_SHADOW( be ) ? slap_true_bv.bv_val : slap_false_bv.bv_val,
216
217
				mi->mi_creatorsName.bv_val,
				mi->mi_creatorsName.bv_val,
218
219
				mi->mi_startTime.bv_val,
				mi->mi_startTime.bv_val );
220
221
222
223
224
		
		e = str2entry( buf );
		if ( e == NULL ) {
			Debug( LDAP_DEBUG_ANY,
				"monitor_subsys_database_init: "
225
				"unable to create entry \"cn=Database %d,%s\"\n",
226
				i, ms->mss_dn.bv_val, 0 );
227
228
229
			return( -1 );
		}
		
Kurt Zeilenga's avatar
Kurt Zeilenga committed
230
		if ( SLAP_MONITOR( be ) ) {
231
232
233
234
			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 );
235

236
		} else {
237
238
239
240
241
242
243
			if ( be->be_suffix == NULL ) {
				Debug( LDAP_DEBUG_ANY,
					"monitor_subsys_database_init: "
					"missing suffix for database %d\n",
					i, 0, 0 );
				return -1;
			}
244
245
246
247
			attr_merge( e, slap_schema.si_ad_namingContexts,
					be->be_suffix, be->be_nsuffix );
			attr_merge( e_database, slap_schema.si_ad_namingContexts,
					be->be_suffix, be->be_nsuffix );
248
		}
249
250
251

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

253
254
255
256
257
		if ( SLAP_SHADOW( be ) && be->be_update_refs ) {
			attr_merge_normalize( e, mi->mi_ad_monitorUpdateRef,
					be->be_update_refs, NULL );
		}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
258
		if ( oi != NULL ) {
259
260
			slap_overinst	*on = oi->oi_list,
					*on1 = on;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
261
262
263

			for ( ; on; on = on->on_next ) {
				struct berval		bv;
264
				slap_overinst		*on2;
265
266
267
268
269
270
271
272
273
274

				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;
				}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
275
				
276
				ber_str2bv( on->on_bi.bi_type, 0, 0, &bv );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
277
278
				attr_merge_normalize_one( e, mi->mi_ad_monitorOverlay,
						&bv, NULL );
279

Pierangelo Masarati's avatar
Pierangelo Masarati committed
280
				/* find the overlay number, j */
281
282
283
284
285
				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;
					}
				}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
286
				assert( on2 != NULL );
287
288
289

				snprintf( buf, sizeof( buf ), 
					"cn=Overlay %d,%s", 
290
					j, ms_overlay->mss_dn.bv_val );
291
292
293
				ber_str2bv( buf, 0, 0, &bv );
				attr_merge_normalize_one( e,
						slap_schema.si_ad_seeAlso,
294
						&bv, NULL );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
295
296
297
			}
		}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
298
299
300
301

		if ( 0 ) {
			assert( 0 );

302
#if defined(SLAPD_BDB) || defined(SLAPD_HDB) 
Kurt Zeilenga's avatar
Kurt Zeilenga committed
303
		} else if ( strcmp( bi->bi_type, "bdb" ) == 0
304
305
306
307
				|| strcmp( bi->bi_type, "hdb" ) == 0 )
		{
			struct berval	bv;
			ber_len_t	pathlen = 0, len = 0;
308
			char		path[ MAXPATHLEN ] = { '\0' };
Kurt Zeilenga's avatar
Kurt Zeilenga committed
309
310
			struct bdb_info *bdb = (struct bdb_info *) be->be_private;
			char		*fname = bdb->bi_dbenv_home;
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

			len = strlen( fname );
			if ( fname[ 0 ] != '/' ) {
				/* get full path name */
				getcwd( path, sizeof( path ) );
				pathlen = strlen( path );

				if ( fname[ 0 ] == '.' && fname[ 1 ] == '/' ) {
					fname += 2;
					len -= 2;
				}
			}

			bv.bv_len = STRLENOF( "file://" ) + pathlen
				+ STRLENOF( "/" ) + len;
			bv.bv_val = ch_malloc( bv.bv_len + STRLENOF( "/" ) + 1 );
			AC_MEMCPY( bv.bv_val, "file://", STRLENOF( "file://" ) );
			if ( pathlen ) {
				AC_MEMCPY( &bv.bv_val[ STRLENOF( "file://" ) ],
						path, pathlen );
				bv.bv_val[ STRLENOF( "file://" ) + pathlen ] = '/';
				pathlen++;
			}
			AC_MEMCPY( &bv.bv_val[ STRLENOF( "file://" ) + pathlen ],
					fname, len );
			if ( bv.bv_val[ bv.bv_len - 1 ] != '/' ) {
				bv.bv_val[ bv.bv_len ] = '/';
				bv.bv_len++;
			}
			bv.bv_val[ bv.bv_len ] = '\0';

			attr_merge_normalize_one( e, slap_schema.si_ad_labeledURI,
					&bv, NULL );

			ch_free( bv.bv_val );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
347
#endif /* defined(SLAPD_BDB) || defined(SLAPD_HDB) */
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
348
#if defined(SLAPD_LDAP) 
Kurt Zeilenga's avatar
Kurt Zeilenga committed
349
350
351
352
353
354
355
356
		} else if ( strcmp( bi->bi_type, "ldap" ) == 0 ) {
			ldapinfo_t	*li = (ldapinfo_t *)be->be_private;
#if 0
			attr_merge_normalize( e, slap_schema.si_ad_labeledURI,
					li->li_bvuri, NULL );
#else
			char		**urls = ldap_str2charray( li->li_uri, " " );
			int		u;
357

Kurt Zeilenga's avatar
Kurt Zeilenga committed
358
359
360
361
362
363
364
365
366
367
368
369
			for ( u = 0; urls[ u ] != NULL; u++ ) {
				struct berval	bv;

				ber_str2bv( urls[ u ], 0, 0, &bv );

				attr_merge_normalize_one( e,
						slap_schema.si_ad_labeledURI,
						&bv, NULL );
			}

			ldap_charray_free( urls );
#endif
Pierangelo Masarati's avatar
Pierangelo Masarati committed
370

371
#endif /* defined(SLAPD_LDAP) */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
372
373
374
375
376
377
#if defined(SLAPD_META) 
		} else if ( strcmp( bi->bi_type, "meta" ) == 0 ) {
			metainfo_t	*mi = (metainfo_t *)be->be_private;
			int		t;

			for ( t = 0; t < mi->mi_ntargets; t++ ) {
378
				char		**urls = ldap_str2charray( mi->mi_targets[ t ]->mt_uri, " " );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
				int		u;

				for ( u = 0; urls[ u ] != NULL; u++ ) {
					struct berval	bv;

					ber_str2bv( urls[ u ], 0, 0, &bv );

					attr_merge_normalize_one( e,
						slap_schema.si_ad_labeledURI,
						&bv, NULL );
				}
				ldap_charray_free( urls );
			}
#endif /* defined(SLAPD_META) */
		}
394

395
396
397
398
		j = -1;
		LDAP_STAILQ_FOREACH( bi2, &backendInfo, bi_next ) {
			j++;
			if ( bi2->bi_type == bi->bi_type ) {
399
				struct berval 		bv;
400
401
402

				snprintf( buf, sizeof( buf ), 
					"cn=Backend %d,%s", 
403
					j, ms_backend->mss_dn.bv_val );
404
405
				bv.bv_val = buf;
				bv.bv_len = strlen( buf );
406
407
				attr_merge_normalize_one( e,
						slap_schema.si_ad_seeAlso,
408
						&bv, NULL );
409
410
411
412
413
414
				break;
			}
		}
		/* we must find it! */
		assert( j >= 0 );

415
416
417
418
		mp = monitor_entrypriv_create();
		if ( mp == NULL ) {
			return -1;
		}
419
		e->e_private = ( void * )mp;
420
421
		mp->mp_info = ms;
		mp->mp_flags = ms->mss_flags
422
423
424
425
426
			| MONITOR_F_SUB;

		if ( monitor_cache_add( mi, e ) ) {
			Debug( LDAP_DEBUG_ANY,
				"monitor_subsys_database_init: "
427
				"unable to add entry \"cn=Database %d,%s\"\n",
428
				i, ms->mss_dn.bv_val, 0 );
429
430
431
			return( -1 );
		}

432
#if defined(LDAP_SLAPI)
Kurt Zeilenga's avatar
Kurt Zeilenga committed
433
		monitor_back_add_plugin( mi, be, e );
434
435
#endif /* defined(LDAP_SLAPI) */

436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
		if ( oi != NULL ) {
			Entry		**ep_overlay = &mp->mp_children;
			monitor_entry_t	*mp_overlay;
			slap_overinst	*on = oi->oi_list;
			int		o;

			for ( o = 0; on; o++, on = on->on_next ) {
				Entry			*e_overlay;
				slap_overinst		*on2;

				/* 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;
					}
				}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
452
				assert( on2 != NULL );
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512

				snprintf( buf, sizeof( buf ),
						"dn: cn=Overlay %d,cn=Database %d,%s\n"
						"objectClass: %s\n"
						"structuralObjectClass: %s\n"
						"cn: Overlay %d\n"
						"%s: %s\n"
						"seeAlso: cn=Overlay %d,%s\n"
						"creatorsName: %s\n"
						"modifiersName: %s\n"
						"createTimestamp: %s\n"
						"modifyTimestamp: %s\n",
						o,
						i,
						ms->mss_dn.bv_val,
						mi->mi_oc_monitoredObject->soc_cname.bv_val,
						mi->mi_oc_monitoredObject->soc_cname.bv_val,
						o,
						mi->mi_ad_monitoredInfo->ad_cname.bv_val,
						on->on_bi.bi_type,
						j,
						ms_overlay->mss_dn.bv_val,
						mi->mi_creatorsName.bv_val,
						mi->mi_creatorsName.bv_val,
						mi->mi_startTime.bv_val,
						mi->mi_startTime.bv_val );
				
				e_overlay = str2entry( buf );
				if ( e_overlay == NULL ) {
					Debug( LDAP_DEBUG_ANY,
						"monitor_subsys_database_init: "
						"unable to create entry "
						"\"cn=Overlay %d,cn=Database %d,%s\"\n",
						o, i, ms->mss_dn.bv_val );
					return( -1 );
				}

				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_database_init: "
						"unable to add entry "
						"\"cn=Overlay %d,cn=Database %d,%s\"\n",
						o, i, ms->mss_dn.bv_val );
					return( -1 );
				}

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

513
514
		*ep = e;
		ep = &mp->mp_next;
515
516
517
518
519
520
521
	}
	
	monitor_cache_release( mi, e_database );

	return( 0 );
}

522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
/*
 * 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;
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
568
static int
569
570
monitor_subsys_database_modify(
	Operation	*op,
571
	SlapReply	*rs,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
572
	Entry		*e )
573
{
574
575
576
577
578
579
	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;
580
	slap_mask_t	rp_add = 0, rp_delete = 0, rp_cur;
581
	struct berval	*tf;
582
583
	
	i = sscanf( e->e_nname.bv_val, "cn=database %d,", &n );
584
585
586
	if ( i != 1 ) {
		return SLAP_CB_CONTINUE;
	}
587

588
589
590
591
	if ( n < 0 || n >= nBackendDB ) {
		rs->sr_text = "invalid database index";
		return ( rs->sr_err = LDAP_NO_SUCH_OBJECT );
	}
592

593
594
595
596
597
598
	LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) {
		if ( n == 0 ) {
			break;
		}
		n--;
	}
599
	/* do not allow some changes on back-monitor (needs work)... */
600
601
602
603
	if ( SLAP_MONITOR( be ) ) {
		rs->sr_text = "no modifications allowed to monitor database entry";
		return ( rs->sr_err = LDAP_UNWILLING_TO_PERFORM );
	}
604
		
605
	rp_cur = be->be_restrictops;
606
607
608
609

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

610
	for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
611
612
613
		Modification *mod = &ml->sml_mod;

		if ( mod->sm_desc == mi->mi_ad_readOnly ) {
614
			int	val = -1;
615
616

			if ( mod->sm_values ) {
617
				if ( !BER_BVISNULL( &mod->sm_values[ 1 ] ) ) {
618
619
					rs->sr_text = "attempting to modify multiple values of single-valued attribute";
					rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
620
					goto done;
621
				}
622

623
624
				if ( bvmatch( &slap_true_bv, mod->sm_values )) {
					val = 1;
625

626
627
				} else if ( bvmatch( &slap_false_bv, mod->sm_values )) {
					val = 0;
628
629

				} else {
630
631
					assert( 0 );
					rc = rs->sr_err = LDAP_INVALID_SYNTAX;
632
					goto done;
633
634
				}
			}
635
636

			switch ( mod->sm_op ) {
637
			case LDAP_MOD_DELETE:
638
				if ( ro_gotval < 1 ) {
639
					rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
640
641
642
643
644
					goto done;
				}
				ro_gotval--;

				if ( val == 0 && ( rp_cur & SLAP_RESTRICT_OP_WRITES ) == SLAP_RESTRICT_OP_WRITES ) {
645
					rc = rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE;
646
					goto done;
647
				}
648
649
				
				if ( val == 1 && ( rp_cur & SLAP_RESTRICT_OP_WRITES ) != SLAP_RESTRICT_OP_WRITES ) {
650
					rc = rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE;
651
652
653
					goto done;
				}
				
654
				break;
655

656
			case LDAP_MOD_REPLACE:
657
658
659
				ro_gotval = 0;
				/* fall thru */

660
			case LDAP_MOD_ADD:
661
				if ( ro_gotval > 0 ) {
662
					rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
663
664
665
666
667
668
669
670
671
672
673
674
675
					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;
676
677
				}
				break;
678

679
			default:
680
				rc = rs->sr_err = LDAP_OTHER;
681
				goto done;
682
			}
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719

		} 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 ) {
720
					rc = rs->sr_err = LDAP_TYPE_OR_VALUE_EXISTS;
721
722
723
724
				}
				break;

			default:
725
				rc = rs->sr_err = LDAP_OTHER;
726
727
				break;
			}
728

729
730
731
			if ( rc != LDAP_SUCCESS ) {
				goto done;
			}
732

733
734
735
736
737
738
		} 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 ) {
739
				rc = rs->sr_err = LDAP_OTHER;
740
741
				break;
			}
742

743
		} else {
744
			rc = rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
745
746
747
			break;
		}
	}
748

749
750
	/* sanity checks: */
	if ( ro_gotval < 1 ) {
751
		rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
752
753
754
755
		goto done;
	}

	if ( ( rp_cur & SLAP_RESTRICT_OP_EXTENDED ) && ( rp_cur & SLAP_RESTRICT_EXOP_MASK ) ) {
756
		rc = rs->sr_err = LDAP_CONSTRAINT_VIOLATION;
757
758
759
760
		goto done;
	}

	if ( rp_delete & rp_add ) {
761
		rc = rs->sr_err = LDAP_OTHER;
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
		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;
	}

779
	if ( !bvmatch( &a->a_vals[ 0 ], tf ) ) {
780
		attr_delete( &e->e_attrs, mi->mi_ad_readOnly );
781
		rc = attr_merge_one( e, mi->mi_ad_readOnly, tf, tf );
782
783
784
785
786
787
788
	}

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

789
			} else {
790
791
				a = attr_find( e->e_attrs, mi->mi_ad_restrictedOperation );
				if ( a == NULL ) {
792
					rc = rs->sr_err = LDAP_OTHER;
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
					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 ] );
						}
					}
				}
				
				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 ] );
						}
					}
				}
			}
		}

		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,
852
853
							&restricted_ops[ i ].op,
							&restricted_ops[ i ].op );
854
855
856
857
858
859
				}
			}

			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,
860
861
							&restricted_exops[ i ].op,
							&restricted_exops[ i ].op );
862
				}
863
864
865
			}
		}
	}
866
867
868
869

	be->be_restrictops = rp_cur;

done:;
870
871
	if ( rc == LDAP_SUCCESS ) {
		attrs_free( save_attrs );
872
		rc = SLAP_CB_CONTINUE;
873

874
875
876
877
878
879
880
881
	} else {
		Attribute *tmp = e->e_attrs;
		e->e_attrs = save_attrs;
		attrs_free( tmp );
	}
	return rc;
}

882
883
#if defined(LDAP_SLAPI)
static int
Kurt Zeilenga's avatar
Kurt Zeilenga committed
884
monitor_back_add_plugin( monitor_info_t *mi, Backend *be, Entry *e_database )
885
{
886
887
	Slapi_PBlock	*pCurrentPB; 
	int		i, rc = LDAP_SUCCESS;
888

889
	if ( slapi_int_pblock_get_first( be, &pCurrentPB ) != LDAP_SUCCESS ) {
890
891
892
893
894
895
896
897
898
899
		/*
		 * LDAP_OTHER is returned if no plugins are installed
		 */
		rc = LDAP_OTHER;
		goto done;
	}

	i = 0;
	do {
		Slapi_PluginDesc	*srchdesc;
900
		char			buf[ BACKMONITOR_BUFSIZE ];
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
		struct berval		bv;

		rc = slapi_pblock_get( pCurrentPB, SLAPI_PLUGIN_DESCRIPTION,
				&srchdesc );
		if ( rc != LDAP_SUCCESS ) {
			goto done;
		}

		snprintf( buf, sizeof(buf),
				"plugin %d name: %s; "
				"vendor: %s; "
				"version: %s; "
				"description: %s", 
				i,
				srchdesc->spd_id,
				srchdesc->spd_vendor,
				srchdesc->spd_version,
				srchdesc->spd_description );

920
		ber_str2bv( buf, 0, 0, &bv );
921
		attr_merge_normalize_one( e_database,
922
				mi->mi_ad_monitoredInfo, &bv, NULL );
923
924
925

		i++;

926
	} while ( ( slapi_int_pblock_get_next( &pCurrentPB ) == LDAP_SUCCESS )
927
928
929
930
931
932
			&& ( pCurrentPB != NULL ) );

done:
	return rc;
}
#endif /* defined(LDAP_SLAPI) */