xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/ldapsync.c (revision c2f76ff004a2cb67efe5b12d97bd3ef7fe89e18d)
1 /*	$NetBSD: ldapsync.c,v 1.1.1.3 2010/12/12 15:22:31 adam Exp $	*/
2 
3 /* ldapsync.c -- LDAP Content Sync Routines */
4 /* OpenLDAP: pkg/ldap/servers/slapd/ldapsync.c,v 1.32.2.13 2010/04/19 16:53:02 quanah Exp */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 2003-2010 The OpenLDAP Foundation.
8  * Portions Copyright 2003 IBM Corporation.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted only as authorized by the OpenLDAP
13  * Public License.
14  *
15  * A copy of this license is available in the file LICENSE in the
16  * top-level directory of the distribution or, alternatively, at
17  * <http://www.OpenLDAP.org/license.html>.
18  */
19 
20 #include "portable.h"
21 
22 #include <stdio.h>
23 
24 #include <ac/string.h>
25 #include <ac/socket.h>
26 
27 #include "lutil.h"
28 #include "slap.h"
29 #include "../../libraries/liblber/lber-int.h" /* get ber_strndup() */
30 #include "lutil_ldap.h"
31 
32 struct slap_sync_cookie_s slap_sync_cookie =
33 	LDAP_STAILQ_HEAD_INITIALIZER( slap_sync_cookie );
34 
35 void
36 slap_compose_sync_cookie(
37 	Operation *op,
38 	struct berval *cookie,
39 	BerVarray csn,
40 	int rid,
41 	int sid )
42 {
43 	int len, numcsn = 0;
44 
45 	if ( csn ) {
46 		for (; !BER_BVISNULL( &csn[numcsn] ); numcsn++);
47 	}
48 
49 	if ( numcsn == 0 || rid == -1 ) {
50 		char cookiestr[ LDAP_PVT_CSNSTR_BUFSIZE + 20 ];
51 		if ( rid == -1 ) {
52 			cookiestr[0] = '\0';
53 			len = 0;
54 		} else {
55 			len = snprintf( cookiestr, sizeof( cookiestr ),
56 					"rid=%03d", rid );
57 			if ( sid >= 0 ) {
58 				len += sprintf( cookiestr+len, ",sid=%03x", sid );
59 			}
60 		}
61 		ber_str2bv_x( cookiestr, len, 1, cookie,
62 			op ? op->o_tmpmemctx : NULL );
63 	} else {
64 		char *ptr;
65 		int i;
66 
67 		len = 0;
68 		for ( i=0; i<numcsn; i++)
69 			len += csn[i].bv_len + 1;
70 
71 		len += STRLENOF("rid=123,csn=");
72 		if ( sid >= 0 )
73 			len += STRLENOF("sid=xxx,");
74 
75 		cookie->bv_val = slap_sl_malloc( len, op ? op->o_tmpmemctx : NULL );
76 
77 		len = sprintf( cookie->bv_val, "rid=%03d,", rid );
78 		ptr = cookie->bv_val + len;
79 		if ( sid >= 0 ) {
80 			ptr += sprintf( ptr, "sid=%03x,", sid );
81 		}
82 		ptr = lutil_strcopy( ptr, "csn=" );
83 		for ( i=0; i<numcsn; i++) {
84 			ptr = lutil_strncopy( ptr, csn[i].bv_val, csn[i].bv_len );
85 			*ptr++ = ';';
86 		}
87 		ptr--;
88 		*ptr = '\0';
89 		cookie->bv_len = ptr - cookie->bv_val;
90 	}
91 }
92 
93 void
94 slap_sync_cookie_free(
95 	struct sync_cookie *cookie,
96 	int free_cookie
97 )
98 {
99 	if ( cookie == NULL )
100 		return;
101 
102 	if ( cookie->sids ) {
103 		ch_free( cookie->sids );
104 		cookie->sids = NULL;
105 	}
106 
107 	if ( cookie->ctxcsn ) {
108 		ber_bvarray_free( cookie->ctxcsn );
109 		cookie->ctxcsn = NULL;
110 	}
111 	cookie->numcsns = 0;
112 	if ( !BER_BVISNULL( &cookie->octet_str )) {
113 		ch_free( cookie->octet_str.bv_val );
114 		BER_BVZERO( &cookie->octet_str );
115 	}
116 
117 	if ( free_cookie ) {
118 		ch_free( cookie );
119 	}
120 
121 	return;
122 }
123 
124 int
125 slap_parse_csn_sid( struct berval *csnp )
126 {
127 	char *p, *q;
128 	struct berval csn = *csnp;
129 	int i;
130 
131 	p = ber_bvchr( &csn, '#' );
132 	if ( !p )
133 		return -1;
134 	p++;
135 	csn.bv_len -= p - csn.bv_val;
136 	csn.bv_val = p;
137 
138 	p = ber_bvchr( &csn, '#' );
139 	if ( !p )
140 		return -1;
141 	p++;
142 	csn.bv_len -= p - csn.bv_val;
143 	csn.bv_val = p;
144 
145 	q = ber_bvchr( &csn, '#' );
146 	if ( !q )
147 		return -1;
148 
149 	csn.bv_len = q - p;
150 
151 	i = strtol( p, &q, 16 );
152 	if ( p == q || q != p + csn.bv_len || i < 0 || i > SLAP_SYNC_SID_MAX ) {
153 		i = -1;
154 	}
155 
156 	return i;
157 }
158 
159 int *
160 slap_parse_csn_sids( BerVarray csns, int numcsns, void *memctx )
161 {
162 	int i, *ret;
163 
164 	ret = slap_sl_malloc( numcsns * sizeof(int), memctx );
165 	for ( i=0; i<numcsns; i++ ) {
166 		ret[i] = slap_parse_csn_sid( &csns[i] );
167 	}
168 	return ret;
169 }
170 
171 int
172 slap_parse_sync_cookie(
173 	struct sync_cookie *cookie,
174 	void *memctx
175 )
176 {
177 	char *csn_ptr;
178 	char *csn_str;
179 	char *cval;
180 	char *next, *end;
181 	AttributeDescription *ad = slap_schema.si_ad_entryCSN;
182 
183 	if ( cookie == NULL )
184 		return -1;
185 
186 	if ( cookie->octet_str.bv_len <= STRLENOF( "rid=" ) )
187 		return -1;
188 
189 	cookie->rid = -1;
190 	cookie->sid = -1;
191 	cookie->ctxcsn = NULL;
192 	cookie->sids = NULL;
193 	cookie->numcsns = 0;
194 
195 	end = cookie->octet_str.bv_val + cookie->octet_str.bv_len;
196 
197 	for ( next=cookie->octet_str.bv_val; next < end; ) {
198 		if ( !strncmp( next, "rid=", STRLENOF("rid=") )) {
199 			char *rid_ptr = next;
200 			cookie->rid = strtol( &rid_ptr[ STRLENOF( "rid=" ) ], &next, 10 );
201 			if ( next == rid_ptr ||
202 				next > end ||
203 				( *next && *next != ',' ) ||
204 				cookie->rid < 0 ||
205 				cookie->rid > SLAP_SYNC_RID_MAX )
206 			{
207 				return -1;
208 			}
209 			if ( *next == ',' ) {
210 				next++;
211 			}
212 			if ( !ad ) {
213 				break;
214 			}
215 			continue;
216 		}
217 		if ( !strncmp( next, "sid=", STRLENOF("sid=") )) {
218 			char *sid_ptr = next;
219 			sid_ptr = next;
220 			cookie->sid = strtol( &sid_ptr[ STRLENOF( "sid=" ) ], &next, 16 );
221 			if ( next == sid_ptr ||
222 				next > end ||
223 				( *next && *next != ',' ) ||
224 				cookie->sid < 0 ||
225 				cookie->sid > SLAP_SYNC_SID_MAX )
226 			{
227 				return -1;
228 			}
229 			if ( *next == ',' ) {
230 				next++;
231 			}
232 			continue;
233 		}
234 		if ( !strncmp( next, "csn=", STRLENOF("csn=") )) {
235 			struct berval stamp;
236 
237 			next += STRLENOF("csn=");
238 			while ( next < end ) {
239 				csn_str = next;
240 				csn_ptr = strchr( csn_str, '#' );
241 				if ( !csn_ptr || csn_ptr > end )
242 					break;
243 				/* ad will be NULL when called from main. we just
244 				 * want to parse the rid then. But we still iterate
245 				 * through the string to find the end.
246 				 */
247 				cval = strchr( csn_ptr, ';' );
248 				if ( !cval )
249 					cval = strchr(csn_ptr, ',' );
250 				if ( cval )
251 					stamp.bv_len = cval - csn_str;
252 				else
253 					stamp.bv_len = end - csn_str;
254 				if ( ad ) {
255 					struct berval bv;
256 					stamp.bv_val = csn_str;
257 					if ( ad->ad_type->sat_syntax->ssyn_validate(
258 						ad->ad_type->sat_syntax, &stamp ) != LDAP_SUCCESS )
259 						break;
260 					if ( ad->ad_type->sat_equality->smr_normalize(
261 						SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
262 						ad->ad_type->sat_syntax,
263 						ad->ad_type->sat_equality,
264 						&stamp, &bv, memctx ) != LDAP_SUCCESS )
265 						break;
266 					ber_bvarray_add_x( &cookie->ctxcsn, &bv, memctx );
267 					cookie->numcsns++;
268 				}
269 				if ( cval ) {
270 					next = cval + 1;
271 					if ( *cval != ';' )
272 						break;
273 				} else {
274 					next = end;
275 					break;
276 				}
277 			}
278 			continue;
279 		}
280 		next++;
281 	}
282 	if ( cookie->numcsns ) {
283 		cookie->sids = slap_parse_csn_sids( cookie->ctxcsn, cookie->numcsns,
284 			memctx );
285 	}
286 	return 0;
287 }
288 
289 int
290 slap_init_sync_cookie_ctxcsn(
291 	struct sync_cookie *cookie
292 )
293 {
294 	char csnbuf[ LDAP_PVT_CSNSTR_BUFSIZE + 4 ];
295 	struct berval octet_str = BER_BVNULL;
296 	struct berval ctxcsn = BER_BVNULL;
297 
298 	if ( cookie == NULL )
299 		return -1;
300 
301 	octet_str.bv_len = snprintf( csnbuf, LDAP_PVT_CSNSTR_BUFSIZE + 4,
302 					"csn=%4d%02d%02d%02d%02d%02dZ#%06x#%02x#%06x",
303 					1900, 1, 1, 0, 0, 0, 0, 0, 0 );
304 	octet_str.bv_val = csnbuf;
305 	ch_free( cookie->octet_str.bv_val );
306 	ber_dupbv( &cookie->octet_str, &octet_str );
307 
308 	ctxcsn.bv_val = octet_str.bv_val + 4;
309 	ctxcsn.bv_len = octet_str.bv_len - 4;
310 	cookie->ctxcsn = NULL;
311 	value_add_one( &cookie->ctxcsn, &ctxcsn );
312 	cookie->numcsns = 1;
313 	cookie->sid = -1;
314 
315 	return 0;
316 }
317 
318 struct sync_cookie *
319 slap_dup_sync_cookie(
320 	struct sync_cookie *dst,
321 	struct sync_cookie *src
322 )
323 {
324 	struct sync_cookie *new;
325 	int i;
326 
327 	if ( src == NULL )
328 		return NULL;
329 
330 	if ( dst ) {
331 		ber_bvarray_free( dst->ctxcsn );
332 		dst->ctxcsn = NULL;
333 		dst->sids = NULL;
334 		ch_free( dst->octet_str.bv_val );
335 		BER_BVZERO( &dst->octet_str );
336 		new = dst;
337 	} else {
338 		new = ( struct sync_cookie * )
339 				ch_calloc( 1, sizeof( struct sync_cookie ));
340 	}
341 
342 	new->rid = src->rid;
343 	new->sid = src->sid;
344 	new->numcsns = src->numcsns;
345 
346 	if ( src->numcsns ) {
347 		if ( ber_bvarray_dup_x( &new->ctxcsn, src->ctxcsn, NULL )) {
348 			if ( !dst ) {
349 				ch_free( new );
350 			}
351 			return NULL;
352 		}
353 		new->sids = ch_malloc( src->numcsns * sizeof(int) );
354 		for (i=0; i<src->numcsns; i++)
355 			new->sids[i] = src->sids[i];
356 	}
357 
358 	if ( !BER_BVISNULL( &src->octet_str )) {
359 		ber_dupbv( &new->octet_str, &src->octet_str );
360 	}
361 
362 	return new;
363 }
364 
365