1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2021 The OpenLDAP Foundation.
5  * Portions Copyright 2001-2003 Pierangelo Masarati.
6  * Portions Copyright 1999-2003 Howard Chu.
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 /* ACKNOWLEDGEMENTS:
18  * This work was initially developed by the Howard Chu for inclusion
19  * in OpenLDAP Software and subsequently enhanced by Pierangelo
20  * Masarati.
21  */
22 
23 #include "portable.h"
24 
25 #include <stdio.h>
26 #include <ac/string.h>
27 
28 #include "slap.h"
29 #include "../back-ldap/back-ldap.h"
30 #include "back-meta.h"
31 
32 /*
33  * The dncache, at present, maps an entry to the target that holds it.
34  */
35 
36 typedef struct metadncacheentry_t {
37 	struct berval	dn;
38 	int 		target;
39 
40 	time_t 		lastupdated;
41 } metadncacheentry_t;
42 
43 /*
44  * meta_dncache_cmp
45  *
46  * compares two struct metadncacheentry; used by avl stuff
47  * FIXME: modify avl stuff to delete an entry based on cmp
48  * (e.g. when ttl expired?)
49  */
50 int
meta_dncache_cmp(const void * c1,const void * c2)51 meta_dncache_cmp(
52 	const void	*c1,
53 	const void	*c2 )
54 {
55 	metadncacheentry_t	*cc1 = ( metadncacheentry_t * )c1;
56 	metadncacheentry_t	*cc2 = ( metadncacheentry_t * )c2;
57 
58 	/*
59 	 * case sensitive, because the dn MUST be normalized
60 	 */
61  	return ber_bvcmp( &cc1->dn, &cc2->dn);
62 }
63 
64 /*
65  * meta_dncache_dup
66  *
67  * returns -1 in case a duplicate struct metadncacheentry has been inserted;
68  * used by avl stuff
69  */
70 int
meta_dncache_dup(void * c1,void * c2)71 meta_dncache_dup(
72 	void		*c1,
73 	void		*c2 )
74 {
75 	metadncacheentry_t	*cc1 = ( metadncacheentry_t * )c1;
76 	metadncacheentry_t	*cc2 = ( metadncacheentry_t * )c2;
77 
78 	/*
79 	 * case sensitive, because the dn MUST be normalized
80 	 */
81  	return ( ber_bvcmp( &cc1->dn, &cc2->dn ) == 0 ) ? -1 : 0;
82 }
83 
84 /*
85  * meta_dncache_get_target
86  *
87  * returns the target a dn belongs to, or -1 in case the dn is not
88  * in the cache
89  */
90 int
meta_dncache_get_target(metadncache_t * cache,struct berval * ndn)91 meta_dncache_get_target(
92 	metadncache_t	*cache,
93 	struct berval	*ndn )
94 {
95 	metadncacheentry_t	tmp_entry,
96 				*entry;
97 	int			target = META_TARGET_NONE;
98 
99 	assert( cache != NULL );
100 	assert( ndn != NULL );
101 
102 	tmp_entry.dn = *ndn;
103 	ldap_pvt_thread_mutex_lock( &cache->mutex );
104 	entry = ( metadncacheentry_t * )ldap_avl_find( cache->tree,
105 			( caddr_t )&tmp_entry, meta_dncache_cmp );
106 
107 	if ( entry != NULL ) {
108 
109 		/*
110 		 * if cache->ttl < 0, cache never expires;
111 		 * if cache->ttl = 0 no cache is used; shouldn't get here
112 		 * else, cache is used with ttl
113 		 */
114 		if ( cache->ttl < 0 ) {
115 			target = entry->target;
116 
117 		} else {
118 			if ( entry->lastupdated+cache->ttl > slap_get_time() ) {
119 				target = entry->target;
120 			}
121 		}
122 	}
123 	ldap_pvt_thread_mutex_unlock( &cache->mutex );
124 
125 	return target;
126 }
127 
128 /*
129  * meta_dncache_update_entry
130  *
131  * updates target and lastupdated of a struct metadncacheentry if exists,
132  * otherwise it gets created; returns -1 in case of error
133  */
134 int
meta_dncache_update_entry(metadncache_t * cache,struct berval * ndn,int target)135 meta_dncache_update_entry(
136 	metadncache_t	*cache,
137 	struct berval	*ndn,
138 	int 		target )
139 {
140 	metadncacheentry_t	*entry,
141 				tmp_entry;
142 	time_t			curr_time = 0L;
143 	int			err = 0;
144 
145 	assert( cache != NULL );
146 	assert( ndn != NULL );
147 
148 	/*
149 	 * if cache->ttl < 0, cache never expires;
150 	 * if cache->ttl = 0 no cache is used; shouldn't get here
151 	 * else, cache is used with ttl
152 	 */
153 	if ( cache->ttl > 0 ) {
154 		curr_time = slap_get_time();
155 	}
156 
157 	tmp_entry.dn = *ndn;
158 
159 	ldap_pvt_thread_mutex_lock( &cache->mutex );
160 	entry = ( metadncacheentry_t * )ldap_avl_find( cache->tree,
161 			( caddr_t )&tmp_entry, meta_dncache_cmp );
162 
163 	if ( entry != NULL ) {
164 		entry->target = target;
165 		entry->lastupdated = curr_time;
166 
167 	} else {
168 		entry = ch_malloc( sizeof( metadncacheentry_t ) + ndn->bv_len + 1 );
169 		if ( entry == NULL ) {
170 			err = -1;
171 			goto error_return;
172 		}
173 
174 		entry->dn.bv_len = ndn->bv_len;
175 		entry->dn.bv_val = (char *)&entry[ 1 ];
176 		AC_MEMCPY( entry->dn.bv_val, ndn->bv_val, ndn->bv_len );
177 		entry->dn.bv_val[ ndn->bv_len ] = '\0';
178 
179 		entry->target = target;
180 		entry->lastupdated = curr_time;
181 
182 		err = ldap_avl_insert( &cache->tree, ( caddr_t )entry,
183 				meta_dncache_cmp, meta_dncache_dup );
184 	}
185 
186 error_return:;
187 	ldap_pvt_thread_mutex_unlock( &cache->mutex );
188 
189 	return err;
190 }
191 
192 /*
193  * meta_dncache_update_entry
194  *
195  * updates target and lastupdated of a struct metadncacheentry if exists,
196  * otherwise it gets created; returns -1 in case of error
197  */
198 int
meta_dncache_delete_entry(metadncache_t * cache,struct berval * ndn)199 meta_dncache_delete_entry(
200 	metadncache_t	*cache,
201 	struct berval	*ndn )
202 {
203 	metadncacheentry_t	*entry,
204 				tmp_entry;
205 
206 	assert( cache != NULL );
207 	assert( ndn != NULL );
208 
209 	tmp_entry.dn = *ndn;
210 
211 	ldap_pvt_thread_mutex_lock( &cache->mutex );
212 	entry = ldap_avl_delete( &cache->tree, ( caddr_t )&tmp_entry,
213  			meta_dncache_cmp );
214 	ldap_pvt_thread_mutex_unlock( &cache->mutex );
215 
216 	if ( entry != NULL ) {
217 		meta_dncache_free( ( void * )entry );
218 	}
219 
220 	return 0;
221 }
222 
223 /*
224  * meta_dncache_free
225  *
226  * frees an entry
227  *
228  */
229 void
meta_dncache_free(void * e)230 meta_dncache_free(
231 	void		*e )
232 {
233 	free( e );
234 }
235 
236