1/*	$NetBSD: var.c,v 1.3 2021/08/14 16:14:58 christos Exp $	*/
2
3/* $OpenLDAP$ */
4/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 *
6 * Copyright 2000-2021 The OpenLDAP Foundation.
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 the file LICENSE in the
14 * top-level directory of the distribution or, alternatively, at
15 * <http://www.OpenLDAP.org/license.html>.
16 */
17/* ACKNOWLEDGEMENT:
18 * This work was initially developed by Pierangelo Masarati for
19 * inclusion in OpenLDAP Software.
20 */
21
22#include <portable.h>
23
24#include "rewrite-int.h"
25
26/*
27 * Compares two vars
28 */
29static int
30rewrite_var_cmp(
31		const void *c1,
32		const void *c2
33)
34{
35	const struct rewrite_var *v1, *v2;
36
37	v1 = ( const struct rewrite_var * )c1;
38	v2 = ( const struct rewrite_var * )c2;
39
40	assert( v1 != NULL );
41	assert( v2 != NULL );
42	assert( v1->lv_name != NULL );
43	assert( v2->lv_name != NULL );
44
45	return strcasecmp( v1->lv_name, v2->lv_name );
46}
47
48/*
49 * Duplicate var ?
50 */
51static int
52rewrite_var_dup(
53		void *c1,
54		void *c2
55)
56{
57	struct rewrite_var *v1, *v2;
58
59	v1 = ( struct rewrite_var * )c1;
60	v2 = ( struct rewrite_var * )c2;
61
62	assert( v1 != NULL );
63	assert( v2 != NULL );
64	assert( v1->lv_name != NULL );
65	assert( v2->lv_name != NULL );
66
67	return ( strcasecmp( v1->lv_name, v2->lv_name ) == 0 ? -1 : 0 );
68}
69
70/*
71 * Frees a var
72 */
73static void
74rewrite_var_free(
75		void *v_var
76)
77{
78	struct rewrite_var *var = v_var;
79	assert( var != NULL );
80
81	assert( var->lv_name != NULL );
82	assert( var->lv_value.bv_val != NULL );
83
84	if ( var->lv_flags & REWRITE_VAR_COPY_NAME )
85		free( var->lv_name );
86	if ( var->lv_flags & REWRITE_VAR_COPY_VALUE )
87		free( var->lv_value.bv_val );
88	free( var );
89}
90
91/*
92 * Deletes a var tree
93 */
94int
95rewrite_var_delete(
96		Avlnode *tree
97)
98{
99	ldap_avl_free( tree, rewrite_var_free );
100	return REWRITE_SUCCESS;
101}
102
103/*
104 * Finds a var
105 */
106struct rewrite_var *
107rewrite_var_find(
108		Avlnode *tree,
109		const char *name
110)
111{
112	struct rewrite_var var;
113
114	assert( name != NULL );
115
116	var.lv_name = ( char * )name;
117	return ( struct rewrite_var * )ldap_avl_find( tree,
118			( caddr_t )&var, rewrite_var_cmp );
119}
120
121int
122rewrite_var_replace(
123		struct rewrite_var *var,
124		const char *value,
125		int flags
126)
127{
128	ber_len_t	len;
129
130	assert( value != NULL );
131
132	len = strlen( value );
133
134	if ( var->lv_flags & REWRITE_VAR_COPY_VALUE ) {
135		if ( flags & REWRITE_VAR_COPY_VALUE ) {
136			if ( len <= var->lv_value.bv_len ) {
137				AC_MEMCPY(var->lv_value.bv_val, value, len + 1);
138
139			} else {
140				free( var->lv_value.bv_val );
141				var->lv_value.bv_val = strdup( value );
142			}
143
144		} else {
145			free( var->lv_value.bv_val );
146			var->lv_value.bv_val = (char *)value;
147			var->lv_flags &= ~REWRITE_VAR_COPY_VALUE;
148		}
149
150	} else {
151		if ( flags & REWRITE_VAR_COPY_VALUE ) {
152			var->lv_value.bv_val = strdup( value );
153			var->lv_flags |= REWRITE_VAR_COPY_VALUE;
154
155		} else {
156			var->lv_value.bv_val = (char *)value;
157		}
158	}
159
160	if ( var->lv_value.bv_val == NULL ) {
161		return -1;
162	}
163
164	var->lv_value.bv_len = len;
165
166	return 0;
167}
168
169/*
170 * Inserts a newly created var
171 */
172struct rewrite_var *
173rewrite_var_insert_f(
174		Avlnode **tree,
175		const char *name,
176		const char *value,
177		int flags
178)
179{
180	struct rewrite_var *var;
181	int rc = 0;
182
183	assert( tree != NULL );
184	assert( name != NULL );
185	assert( value != NULL );
186
187	var = rewrite_var_find( *tree, name );
188	if ( var != NULL ) {
189		if ( flags & REWRITE_VAR_UPDATE ) {
190			(void)rewrite_var_replace( var, value, flags );
191			goto cleanup;
192		}
193		rc = -1;
194		goto cleanup;
195	}
196
197	var = calloc( sizeof( struct rewrite_var ), 1 );
198	if ( var == NULL ) {
199		return NULL;
200	}
201
202	memset( var, 0, sizeof( struct rewrite_var ) );
203
204	if ( flags & REWRITE_VAR_COPY_NAME ) {
205		var->lv_name = strdup( name );
206		if ( var->lv_name == NULL ) {
207			rc = -1;
208			goto cleanup;
209		}
210		var->lv_flags |= REWRITE_VAR_COPY_NAME;
211
212	} else {
213		var->lv_name = (char *)name;
214	}
215
216	if ( flags & REWRITE_VAR_COPY_VALUE ) {
217		var->lv_value.bv_val = strdup( value );
218		if ( var->lv_value.bv_val == NULL ) {
219			rc = -1;
220			goto cleanup;
221		}
222		var->lv_flags |= REWRITE_VAR_COPY_VALUE;
223
224	} else {
225		var->lv_value.bv_val = (char *)value;
226	}
227	var->lv_value.bv_len = strlen( value );
228	rc = ldap_avl_insert( tree, ( caddr_t )var,
229			rewrite_var_cmp, rewrite_var_dup );
230
231cleanup:;
232	if ( rc != 0 && var ) {
233		ldap_avl_delete( tree, ( caddr_t )var, rewrite_var_cmp );
234		rewrite_var_free( var );
235		var = NULL;
236	}
237
238	return var;
239}
240
241/*
242 * Sets/inserts a var
243 */
244struct rewrite_var *
245rewrite_var_set_f(
246		Avlnode **tree,
247		const char *name,
248		const char *value,
249		int flags
250)
251{
252	struct rewrite_var *var;
253
254	assert( tree != NULL );
255	assert( name != NULL );
256	assert( value != NULL );
257
258	var = rewrite_var_find( *tree, name );
259	if ( var == NULL ) {
260		if ( flags & REWRITE_VAR_INSERT ) {
261			return rewrite_var_insert_f( tree, name, value, flags );
262
263		} else {
264			return NULL;
265		}
266
267	} else {
268		assert( var->lv_value.bv_val != NULL );
269
270		(void)rewrite_var_replace( var, value, flags );
271	}
272
273	return var;
274}
275
276