1/* log.c - deal with log subsystem */
2/* $OpenLDAP$ */
3/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 *
5 * Copyright 2001-2011 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
26#include <ac/string.h>
27
28#include "slap.h"
29#include <lber_pvt.h>
30#include "lutil.h"
31#include "ldif.h"
32#include "back-monitor.h"
33
34static int
35monitor_subsys_log_open(
36	BackendDB		*be,
37	monitor_subsys_t	*ms );
38
39static int
40monitor_subsys_log_modify(
41	Operation		*op,
42	SlapReply		*rs,
43	Entry 			*e );
44
45/*
46 * log mutex
47 */
48ldap_pvt_thread_mutex_t		monitor_log_mutex;
49
50static int add_values( Operation *op, Entry *e, Modification *mod, int *newlevel );
51static int delete_values( Operation *op, Entry *e, Modification *mod, int *newlevel );
52static int replace_values( Operation *op, Entry *e, Modification *mod, int *newlevel );
53
54/*
55 * initializes log subentry
56 */
57int
58monitor_subsys_log_init(
59	BackendDB		*be,
60	monitor_subsys_t	*ms )
61{
62	ms->mss_open = monitor_subsys_log_open;
63	ms->mss_modify = monitor_subsys_log_modify;
64
65	ldap_pvt_thread_mutex_init( &monitor_log_mutex );
66
67	return( 0 );
68}
69
70/*
71 * opens log subentry
72 */
73int
74monitor_subsys_log_open(
75	BackendDB		*be,
76	monitor_subsys_t	*ms )
77{
78	BerVarray	bva = NULL;
79
80	if ( loglevel2bvarray( ldap_syslog, &bva ) == 0 && bva != NULL ) {
81		monitor_info_t	*mi;
82		Entry		*e;
83
84		mi = ( monitor_info_t * )be->be_private;
85
86		if ( monitor_cache_get( mi, &ms->mss_ndn, &e ) ) {
87			Debug( LDAP_DEBUG_ANY,
88				"monitor_subsys_log_init: "
89				"unable to get entry \"%s\"\n",
90				ms->mss_ndn.bv_val, 0, 0 );
91			ber_bvarray_free( bva );
92			return( -1 );
93		}
94
95		attr_merge_normalize( e, mi->mi_ad_managedInfo, bva, NULL );
96		ber_bvarray_free( bva );
97
98		monitor_cache_release( mi, e );
99	}
100
101	return( 0 );
102}
103
104static int
105monitor_subsys_log_modify(
106	Operation		*op,
107	SlapReply		*rs,
108	Entry 			*e )
109{
110	monitor_info_t	*mi = ( monitor_info_t * )op->o_bd->be_private;
111	int		rc = LDAP_OTHER;
112	int		newlevel = ldap_syslog;
113	Attribute	*save_attrs;
114	Modifications	*modlist = op->orm_modlist;
115	Modifications	*ml;
116
117	ldap_pvt_thread_mutex_lock( &monitor_log_mutex );
118
119	save_attrs = e->e_attrs;
120	e->e_attrs = attrs_dup( e->e_attrs );
121
122	for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
123		Modification	*mod = &ml->sml_mod;
124
125		/*
126		 * accept all operational attributes;
127		 * this includes modifersName and modifyTimestamp
128		 * if lastmod is "on"
129		 */
130		if ( is_at_operational( mod->sm_desc->ad_type ) ) {
131			( void ) attr_delete( &e->e_attrs, mod->sm_desc );
132			rc = rs->sr_err = attr_merge( e, mod->sm_desc,
133					mod->sm_values, mod->sm_nvalues );
134			if ( rc != LDAP_SUCCESS ) {
135				break;
136			}
137			continue;
138
139		/*
140		 * only the "managedInfo" attribute can be modified
141		 */
142		} else if ( mod->sm_desc != mi->mi_ad_managedInfo ) {
143			rc = rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
144			break;
145		}
146
147		switch ( mod->sm_op ) {
148		case LDAP_MOD_ADD:
149			rc = add_values( op, e, mod, &newlevel );
150			break;
151
152		case LDAP_MOD_DELETE:
153			rc = delete_values( op, e, mod, &newlevel );
154			break;
155
156		case LDAP_MOD_REPLACE:
157			rc = replace_values( op, e, mod, &newlevel );
158			break;
159
160		default:
161			rc = LDAP_OTHER;
162			break;
163		}
164
165		if ( rc != LDAP_SUCCESS ) {
166			rs->sr_err = rc;
167			break;
168		}
169	}
170
171	/* set the new debug level */
172	if ( rc == LDAP_SUCCESS ) {
173		const char	*text;
174		static char	textbuf[ BACKMONITOR_BUFSIZE ];
175
176		/* check for abandon */
177		if ( op->o_abandon ) {
178			rc = rs->sr_err = SLAPD_ABANDON;
179
180			goto cleanup;
181		}
182
183		/* check that the entry still obeys the schema */
184		rc = entry_schema_check( op, e, save_attrs, 0, 0, NULL,
185			&text, textbuf, sizeof( textbuf ) );
186		if ( rc != LDAP_SUCCESS ) {
187			rs->sr_err = rc;
188			goto cleanup;
189		}
190
191		/*
192		 * Do we need to protect this with a mutex?
193		 */
194		ldap_syslog = newlevel;
195
196#if 0	/* debug rather than log */
197		slap_debug = newlevel;
198		lutil_set_debug_level( "slapd", slap_debug );
199		ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &slap_debug);
200		ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &slap_debug);
201		ldif_debug = slap_debug;
202#endif
203	}
204
205cleanup:;
206	if ( rc == LDAP_SUCCESS ) {
207		attrs_free( save_attrs );
208
209	} else {
210		attrs_free( e->e_attrs );
211		e->e_attrs = save_attrs;
212	}
213
214	ldap_pvt_thread_mutex_unlock( &monitor_log_mutex );
215
216	if ( rc == LDAP_SUCCESS ) {
217		rc = SLAP_CB_CONTINUE;
218	}
219
220	return rc;
221}
222
223static int
224check_constraints( Modification *mod, int *newlevel )
225{
226	int		i;
227
228	if ( mod->sm_nvalues != NULL ) {
229		ber_bvarray_free( mod->sm_nvalues );
230		mod->sm_nvalues = NULL;
231	}
232
233	for ( i = 0; !BER_BVISNULL( &mod->sm_values[ i ] ); i++ ) {
234		int		l;
235		struct berval	bv;
236
237		if ( str2loglevel( mod->sm_values[ i ].bv_val, &l ) ) {
238			return LDAP_CONSTRAINT_VIOLATION;
239		}
240
241		if ( loglevel2bv( l, &bv ) ) {
242			return LDAP_CONSTRAINT_VIOLATION;
243		}
244
245		assert( bv.bv_len == mod->sm_values[ i ].bv_len );
246
247		AC_MEMCPY( mod->sm_values[ i ].bv_val,
248				bv.bv_val, bv.bv_len );
249
250		*newlevel |= l;
251	}
252
253	return LDAP_SUCCESS;
254}
255
256static int
257add_values( Operation *op, Entry *e, Modification *mod, int *newlevel )
258{
259	Attribute	*a;
260	int		i, rc;
261	MatchingRule 	*mr = mod->sm_desc->ad_type->sat_equality;
262
263	assert( mod->sm_values != NULL );
264
265	rc = check_constraints( mod, newlevel );
266	if ( rc != LDAP_SUCCESS ) {
267		return rc;
268	}
269
270	a = attr_find( e->e_attrs, mod->sm_desc );
271
272	if ( a != NULL ) {
273		/* "managedInfo" SHOULD have appropriate rules ... */
274		if ( mr == NULL || !mr->smr_match ) {
275			return LDAP_INAPPROPRIATE_MATCHING;
276		}
277
278		for ( i = 0; !BER_BVISNULL( &mod->sm_values[ i ] ); i++ ) {
279			int rc;
280			int j;
281			const char *text = NULL;
282			struct berval asserted;
283
284			rc = asserted_value_validate_normalize(
285				mod->sm_desc, mr, SLAP_MR_EQUALITY,
286				&mod->sm_values[ i ], &asserted, &text,
287				op->o_tmpmemctx );
288
289			if ( rc != LDAP_SUCCESS ) {
290				return rc;
291			}
292
293			for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); j++ ) {
294				int match;
295				int rc = value_match( &match, mod->sm_desc, mr,
296					0, &a->a_nvals[ j ], &asserted, &text );
297
298				if ( rc == LDAP_SUCCESS && match == 0 ) {
299					free( asserted.bv_val );
300					return LDAP_TYPE_OR_VALUE_EXISTS;
301				}
302			}
303
304			free( asserted.bv_val );
305		}
306	}
307
308	/* no - add them */
309	rc = attr_merge_normalize( e, mod->sm_desc, mod->sm_values,
310		op->o_tmpmemctx );
311	if ( rc != LDAP_SUCCESS ) {
312		return rc;
313	}
314
315	return LDAP_SUCCESS;
316}
317
318static int
319delete_values( Operation *op, Entry *e, Modification *mod, int *newlevel )
320{
321	int             i, j, k, found, rc, nl = 0;
322	Attribute       *a;
323	MatchingRule 	*mr = mod->sm_desc->ad_type->sat_equality;
324
325	/* delete the entire attribute */
326	if ( mod->sm_values == NULL ) {
327		int rc = attr_delete( &e->e_attrs, mod->sm_desc );
328
329		if ( rc ) {
330			rc = LDAP_NO_SUCH_ATTRIBUTE;
331
332		} else {
333			*newlevel = 0;
334			rc = LDAP_SUCCESS;
335		}
336		return rc;
337	}
338
339	rc = check_constraints( mod, &nl );
340	if ( rc != LDAP_SUCCESS ) {
341		return rc;
342	}
343
344	*newlevel &= ~nl;
345
346	if ( mr == NULL || !mr->smr_match ) {
347		/* disallow specific attributes from being deleted if
348		 * no equality rule */
349		return LDAP_INAPPROPRIATE_MATCHING;
350	}
351
352	/* delete specific values - find the attribute first */
353	if ( (a = attr_find( e->e_attrs, mod->sm_desc )) == NULL ) {
354		return( LDAP_NO_SUCH_ATTRIBUTE );
355	}
356
357	/* find each value to delete */
358	for ( i = 0; !BER_BVISNULL( &mod->sm_values[ i ] ); i++ ) {
359		int rc;
360		const char *text = NULL;
361
362		struct berval asserted;
363
364		rc = asserted_value_validate_normalize(
365				mod->sm_desc, mr, SLAP_MR_EQUALITY,
366				&mod->sm_values[ i ], &asserted, &text,
367				op->o_tmpmemctx );
368
369		if( rc != LDAP_SUCCESS ) return rc;
370
371		found = 0;
372		for ( j = 0; !BER_BVISNULL( &a->a_vals[ j ] ); j++ ) {
373			int match;
374			int rc = value_match( &match, mod->sm_desc, mr,
375				0, &a->a_nvals[ j ], &asserted, &text );
376
377			if( rc == LDAP_SUCCESS && match != 0 ) {
378				continue;
379			}
380
381			/* found a matching value */
382			found = 1;
383
384			/* delete it */
385			if ( a->a_nvals != a->a_vals ) {
386				free( a->a_nvals[ j ].bv_val );
387				for ( k = j + 1; !BER_BVISNULL( &a->a_nvals[ k ] ); k++ ) {
388					a->a_nvals[ k - 1 ] = a->a_nvals[ k ];
389				}
390				BER_BVZERO( &a->a_nvals[ k - 1 ] );
391			}
392
393			free( a->a_vals[ j ].bv_val );
394			for ( k = j + 1; !BER_BVISNULL( &a->a_vals[ k ] ); k++ ) {
395				a->a_vals[ k - 1 ] = a->a_vals[ k ];
396			}
397			BER_BVZERO( &a->a_vals[ k - 1 ] );
398			a->a_numvals--;
399
400			break;
401		}
402
403		free( asserted.bv_val );
404
405		/* looked through them all w/o finding it */
406		if ( ! found ) {
407			return LDAP_NO_SUCH_ATTRIBUTE;
408		}
409	}
410
411	/* if no values remain, delete the entire attribute */
412	if ( BER_BVISNULL( &a->a_vals[ 0 ] ) ) {
413		assert( a->a_numvals == 0 );
414
415		/* should already be zero */
416		*newlevel = 0;
417
418		if ( attr_delete( &e->e_attrs, mod->sm_desc ) ) {
419			return LDAP_NO_SUCH_ATTRIBUTE;
420		}
421	}
422
423	return LDAP_SUCCESS;
424}
425
426static int
427replace_values( Operation *op, Entry *e, Modification *mod, int *newlevel )
428{
429	int rc;
430
431	if ( mod->sm_values != NULL ) {
432		*newlevel = 0;
433		rc = check_constraints( mod, newlevel );
434		if ( rc != LDAP_SUCCESS ) {
435			return rc;
436		}
437	}
438
439	rc = attr_delete( &e->e_attrs, mod->sm_desc );
440
441	if ( rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_ATTRIBUTE ) {
442		return rc;
443	}
444
445	if ( mod->sm_values != NULL ) {
446		rc = attr_merge_normalize( e, mod->sm_desc, mod->sm_values,
447				op->o_tmpmemctx );
448		if ( rc != LDAP_SUCCESS ) {
449			return rc;
450		}
451	}
452
453	return LDAP_SUCCESS;
454}
455
456