]> git.sur5r.net Git - openldap/blob - servers/slapd/ldapsync.c
fix negative counters; prepare for imrpved count of sent data
[openldap] / servers / slapd / ldapsync.c
1 /* ldapsync.c -- LDAP Content Sync Routines */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2003-2004 The OpenLDAP Foundation.
6  * Portions Copyright 2003 IBM Corporation.
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
18 #include "portable.h"
19
20 #include <stdio.h>
21
22 #include <ac/string.h>
23 #include <ac/socket.h>
24
25 #include "ldap_pvt.h"
26 #include "lutil.h"
27 #include "slap.h"
28 #include "../../libraries/liblber/lber-int.h" /* get ber_strndup() */
29 #include "lutil_ldap.h"
30
31 #if 0
32 struct sync_cookie *slap_sync_cookie = NULL;
33 #else
34 struct slap_sync_cookie_s slap_sync_cookie =
35         LDAP_STAILQ_HEAD_INITIALIZER( slap_sync_cookie );
36 #endif
37
38 int
39 slap_build_sync_state_ctrl(
40         Operation       *op,
41         SlapReply       *rs,
42         Entry           *e,
43         int                     entry_sync_state,
44         LDAPControl     **ctrls,
45         int                     num_ctrls,
46         int                     send_cookie,
47         struct berval   *cookie)
48 {
49         Attribute* a;
50         int ret;
51         int res;
52         const char *text = NULL;
53
54         BerElementBuffer berbuf;
55         BerElement *ber = (BerElement *)&berbuf;
56
57         struct berval entryuuid_bv      = BER_BVNULL;
58
59         ber_init2( ber, 0, LBER_USE_DER );
60         ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
61
62         ctrls[num_ctrls] = slap_sl_malloc ( sizeof ( LDAPControl ), op->o_tmpmemctx );
63
64         for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
65                 AttributeDescription *desc = a->a_desc;
66                 if ( desc == slap_schema.si_ad_entryUUID ) {
67                         ber_dupbv( &entryuuid_bv, &a->a_nvals[0] );
68                 }
69         }
70
71         if ( send_cookie && cookie ) {
72                 ber_printf( ber, "{eOON}",
73                         entry_sync_state, &entryuuid_bv, cookie );
74         } else {
75                 ber_printf( ber, "{eON}",
76                         entry_sync_state, &entryuuid_bv );
77         }
78
79         ch_free( entryuuid_bv.bv_val );
80         entryuuid_bv.bv_val = NULL;
81
82         ctrls[num_ctrls]->ldctl_oid = LDAP_CONTROL_SYNC_STATE;
83         ctrls[num_ctrls]->ldctl_iscritical = op->o_sync;
84         ret = ber_flatten2( ber, &ctrls[num_ctrls]->ldctl_value, 1 );
85
86         ber_free_buf( ber );
87
88         if ( ret < 0 ) {
89                 Debug( LDAP_DEBUG_TRACE,
90                         "slap_build_sync_ctrl: ber_flatten2 failed\n",
91                         0, 0, 0 );
92                 send_ldap_error( op, rs, LDAP_OTHER, "internal error" );
93                 return ret;
94         }
95
96         return LDAP_SUCCESS;
97 }
98
99 int
100 slap_build_sync_done_ctrl(
101         Operation       *op,
102         SlapReply       *rs,
103         LDAPControl     **ctrls,
104         int                     num_ctrls,
105         int                     send_cookie,
106         struct berval *cookie,
107         int                     refreshDeletes )
108 {
109         int ret;
110         BerElementBuffer berbuf;
111         BerElement *ber = (BerElement *)&berbuf;
112
113         ber_init2( ber, NULL, LBER_USE_DER );
114         ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
115
116         ctrls[num_ctrls] = ch_malloc ( sizeof ( LDAPControl ) );
117
118         ber_printf( ber, "{" );
119         if ( send_cookie && cookie ) {
120                 ber_printf( ber, "O", cookie );
121         }
122         if ( refreshDeletes == LDAP_SYNC_REFRESH_DELETES ) {
123                 ber_printf( ber, "b", refreshDeletes );
124         }
125         ber_printf( ber, "N}" );        
126
127         ctrls[num_ctrls]->ldctl_oid = LDAP_CONTROL_SYNC_DONE;
128         ctrls[num_ctrls]->ldctl_iscritical = op->o_sync;
129         ret = ber_flatten2( ber, &ctrls[num_ctrls]->ldctl_value, 1 );
130
131         ber_free_buf( ber );
132
133         if ( ret < 0 ) {
134                 Debug( LDAP_DEBUG_TRACE,
135                         "slap_build_sync_done_ctrl: ber_flatten2 failed\n",
136                         0, 0, 0 );
137                 send_ldap_error( op, rs, LDAP_OTHER, "internal error" );
138                 return ret;
139         }
140
141         return LDAP_SUCCESS;
142 }
143
144
145 int
146 slap_build_sync_state_ctrl_from_slog(
147         Operation       *op,
148         SlapReply       *rs,
149         struct slog_entry *slog_e,
150         int                     entry_sync_state,
151         LDAPControl     **ctrls,
152         int                     num_ctrls,
153         int                     send_cookie,
154         struct berval   *cookie)
155 {
156         Attribute* a;
157         int ret;
158         int res;
159         const char *text = NULL;
160
161         BerElementBuffer berbuf;
162         BerElement *ber = (BerElement *)&berbuf;
163
164         struct berval entryuuid_bv      = BER_BVNULL;
165
166         ber_init2( ber, NULL, LBER_USE_DER );
167         ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
168
169         ctrls[num_ctrls] = ch_malloc ( sizeof ( LDAPControl ) );
170
171         ber_dupbv( &entryuuid_bv, &slog_e->sl_uuid );
172
173         if ( send_cookie && cookie ) {
174                 ber_printf( ber, "{eOON}",
175                         entry_sync_state, &entryuuid_bv, cookie );
176         } else {
177                 ber_printf( ber, "{eON}",
178                         entry_sync_state, &entryuuid_bv );
179         }
180
181         ch_free( entryuuid_bv.bv_val );
182         entryuuid_bv.bv_val = NULL;
183
184         ctrls[num_ctrls]->ldctl_oid = LDAP_CONTROL_SYNC_STATE;
185         ctrls[num_ctrls]->ldctl_iscritical = op->o_sync;
186         ret = ber_flatten2( ber, &ctrls[num_ctrls]->ldctl_value, 1 );
187
188         ber_free_buf( ber );
189
190         if ( ret < 0 ) {
191                 Debug( LDAP_DEBUG_TRACE,
192                         "slap_build_sync_ctrl: ber_flatten2 failed\n",
193                         0, 0, 0 );
194                 send_ldap_error( op, rs, LDAP_OTHER, "internal error" );
195                 return ret;
196         }
197
198         return LDAP_SUCCESS;
199 }
200
201 int
202 slap_send_syncinfo(
203         Operation       *op,
204         SlapReply       *rs,
205         int                     type,
206         struct berval *cookie,
207         int                     refreshDone,
208         BerVarray       syncUUIDs,
209         int                     refreshDeletes )
210 {
211         BerElementBuffer berbuf;
212         BerElement *ber = (BerElement *)&berbuf;
213         struct berval rspdata;
214
215         int ret;
216
217         ber_init2( ber, NULL, LBER_USE_DER );
218         ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
219
220         if ( type ) {
221                 switch ( type ) {
222                 case LDAP_TAG_SYNC_NEW_COOKIE:
223                         ber_printf( ber, "tO", type, cookie );
224                         break;
225                 case LDAP_TAG_SYNC_REFRESH_DELETE:
226                 case LDAP_TAG_SYNC_REFRESH_PRESENT:
227                         ber_printf( ber, "t{", type );
228                         if ( cookie ) {
229                                 ber_printf( ber, "O", cookie );
230                         }
231                         if ( refreshDone == 0 ) {
232                                 ber_printf( ber, "b", refreshDone );
233                         }
234                         ber_printf( ber, "N}" );
235                         break;
236                 case LDAP_TAG_SYNC_ID_SET:
237                         ber_printf( ber, "t{", type );
238                         if ( cookie ) {
239                                 ber_printf( ber, "O", cookie );
240                         }
241                         if ( refreshDeletes == 1 ) {
242                                 ber_printf( ber, "b", refreshDeletes );
243                         }
244                         ber_printf( ber, "[W]", syncUUIDs );
245                         ber_printf( ber, "N}" );
246                         break;
247                 default:
248                         Debug( LDAP_DEBUG_TRACE,
249                                 "slap_send_syncinfo: invalid syncinfo type (%d)\n",
250                                 type, 0, 0 );
251                         return LDAP_OTHER;
252                 }
253         }
254
255         ret = ber_flatten2( ber, &rspdata, 0 );
256
257         if ( ret < 0 ) {
258                 Debug( LDAP_DEBUG_TRACE,
259                         "slap_send_syncinfo: ber_flatten2 failed\n",
260                         0, 0, 0 );
261                 send_ldap_error( op, rs, LDAP_OTHER, "internal error" );
262                 return ret;
263         }
264
265         rs->sr_rspdata = &rspdata;
266         send_ldap_intermediate( op, rs );
267         rs->sr_rspdata = NULL;
268         ber_free_buf( ber );
269
270         return LDAP_SUCCESS;
271 }
272
273 void
274 slap_compose_sync_cookie(
275         Operation *op,
276         struct berval *cookie,
277         struct berval *csn,
278         int sid,
279         int rid )
280 {
281         char cookiestr[ LDAP_LUTIL_CSNSTR_BUFSIZE + 20 ];
282
283         if ( csn->bv_val == NULL ) {
284                 if ( sid == -1 ) {
285                         if ( rid == -1 ) {
286                                 cookiestr[0] = '\0';
287                         } else {
288                                 snprintf( cookiestr, LDAP_LUTIL_CSNSTR_BUFSIZE + 20,
289                                                 "rid=%03d", rid );
290                         }
291                 } else {
292                         if ( rid == -1 ) {
293                                 snprintf( cookiestr, LDAP_LUTIL_CSNSTR_BUFSIZE + 20,
294                                                 "sid=%03d", sid );
295                         } else {
296                                 snprintf( cookiestr, LDAP_LUTIL_CSNSTR_BUFSIZE + 20,
297                                                 "sid=%03d,rid=%03d", sid, rid );
298                         }
299                 }
300         } else {
301                 if ( sid == -1 ) {
302                         if ( rid == -1 ) {
303                                 snprintf( cookiestr, LDAP_LUTIL_CSNSTR_BUFSIZE + 20,
304                                                 "csn=%s", csn->bv_val );
305                         } else {
306                                 snprintf( cookiestr, LDAP_LUTIL_CSNSTR_BUFSIZE + 20,
307                                                 "csn=%s,rid=%03d", csn->bv_val, rid );
308                         }
309                 } else {
310                         if ( rid == -1 ) {
311                                 snprintf( cookiestr, LDAP_LUTIL_CSNSTR_BUFSIZE + 20,
312                                                 "csn=%s,sid=%03d", csn->bv_val, sid );
313                         } else {
314                                 snprintf( cookiestr, LDAP_LUTIL_CSNSTR_BUFSIZE + 20,
315                                                 "csn=%s,sid=%03d,rid=%03d", csn->bv_val, sid, rid );
316                         }
317                 }
318         }
319         ber_str2bv( cookiestr, strlen(cookiestr), 1, cookie );
320 }
321
322 void
323 slap_sync_cookie_free(
324         struct sync_cookie *cookie,
325         int free_cookie
326 )
327 {
328         if ( cookie == NULL )
329                 return;
330
331         if ( cookie->ctxcsn ) {
332                 ber_bvarray_free( cookie->ctxcsn );
333                 cookie->ctxcsn = NULL;
334         }
335
336         if ( cookie->octet_str ) {
337                 ber_bvarray_free( cookie->octet_str );
338                 cookie->octet_str = NULL;
339         }
340
341         if ( free_cookie ) {
342                 ch_free( cookie );
343         }
344
345         return;
346 }
347
348 int
349 slap_parse_sync_cookie(
350         struct sync_cookie *cookie
351 )
352 {
353         char *csn_ptr;
354         char *csn_str;
355         int csn_str_len;
356         char *sid_ptr;
357         char *sid_str;
358         char *rid_ptr;
359         char *rid_str;
360         char *cval;
361         struct berval *ctxcsn;
362
363         if ( cookie == NULL )
364                 return -1;
365
366         if (( csn_ptr = strstr( cookie->octet_str[0].bv_val, "csn=" )) != NULL ) {
367                 csn_str = SLAP_STRNDUP( csn_ptr, LDAP_LUTIL_CSNSTR_BUFSIZE );
368                 if ( (cval = strchr( csn_str, ',' )) != NULL ) {
369                         *cval = '\0';
370                         csn_str_len = cval - csn_str - (sizeof("csn=") - 1);
371                 } else {
372                         csn_str_len = cookie->octet_str[0].bv_len -
373                                                         (csn_ptr - cookie->octet_str[0].bv_val) -
374                                                         (sizeof("csn=") - 1);
375                 }
376                 ctxcsn = ber_str2bv( csn_str + (sizeof("csn=")-1),
377                                                          csn_str_len, 1, NULL );
378                 ch_free( csn_str );
379                 ber_bvarray_add( &cookie->ctxcsn, ctxcsn );
380                 ch_free( ctxcsn );
381         } else {
382                 cookie->ctxcsn = NULL;
383         }
384
385         if (( sid_ptr = strstr( cookie->octet_str->bv_val, "sid=" )) != NULL ) {
386                 sid_str = SLAP_STRNDUP( sid_ptr,
387                                                         SLAP_SYNC_SID_SIZE + sizeof("sid=") - 1 );
388                 if ( (cval = strchr( sid_str, ',' )) != NULL ) {
389                         *cval = '\0';
390                 }
391                 cookie->sid = atoi( sid_str + sizeof("sid=") - 1 );
392                 ch_free( sid_str );
393         } else {
394                 cookie->sid = -1;
395         }
396
397         if (( rid_ptr = strstr( cookie->octet_str->bv_val, "rid=" )) != NULL ) {
398                 rid_str = SLAP_STRNDUP( rid_ptr,
399                                                         SLAP_SYNC_RID_SIZE + sizeof("rid=") - 1 );
400                 if ( (cval = strchr( rid_str, ',' )) != NULL ) {
401                         *cval = '\0';
402                 }
403                 cookie->rid = atoi( rid_str + sizeof("rid=") - 1 );
404                 ch_free( rid_str );
405         } else {
406                 cookie->rid = -1;
407         }
408         return 0;
409 }
410
411 int
412 slap_init_sync_cookie_ctxcsn(
413         struct sync_cookie *cookie
414 )
415 {
416         char csnbuf[ LDAP_LUTIL_CSNSTR_BUFSIZE + 4 ];
417         struct berval octet_str = BER_BVNULL;
418         struct berval ctxcsn = BER_BVNULL;
419         struct berval ctxcsn_dup = BER_BVNULL;
420         struct berval slap_syncCookie;
421
422         if ( cookie == NULL )
423                 return -1;
424
425         octet_str.bv_len = snprintf( csnbuf, LDAP_LUTIL_CSNSTR_BUFSIZE + 4,
426                                         "csn=%4d%02d%02d%02d%02d%02dZ#%06x#%02x#%06x",
427                                         1900, 1, 1, 0, 0, 0, 0, 0, 0 );
428         octet_str.bv_val = csnbuf;
429         build_new_dn( &slap_syncCookie, &cookie->octet_str[0], &octet_str, NULL );
430         ber_bvarray_free( cookie->octet_str );
431         cookie->octet_str = NULL;
432         ber_bvarray_add( &cookie->octet_str, &slap_syncCookie );
433
434         ber_dupbv( &ctxcsn, &octet_str );
435         ctxcsn.bv_val += 4;
436         ctxcsn.bv_len -= 4;
437         ber_dupbv( &ctxcsn_dup, &ctxcsn );
438         ch_free( ctxcsn.bv_val );
439         ber_bvarray_add( &cookie->ctxcsn, &ctxcsn_dup );
440
441         return 0;
442 }
443
444 struct sync_cookie *
445 slap_dup_sync_cookie(
446         struct sync_cookie *dst,
447         struct sync_cookie *src
448 )
449 {
450         int i;
451         struct sync_cookie *new;
452         struct berval tmp_bv;
453
454         if ( src == NULL )
455                 return NULL;
456
457         if ( dst ) {
458                 ber_bvarray_free( dst->ctxcsn );
459                 ber_bvarray_free( dst->octet_str );
460                 new = dst;
461         } else {
462                 new = ( struct sync_cookie * )
463                                 ch_calloc( 1, sizeof( struct sync_cookie ));
464         }
465
466         new->sid = src->sid;
467         new->rid = src->rid;
468
469         if ( src->ctxcsn ) {
470                 for ( i=0; src->ctxcsn[i].bv_val; i++ ) {
471                         ber_dupbv( &tmp_bv, &src->ctxcsn[i] );
472                         ber_bvarray_add( &new->ctxcsn, &tmp_bv );
473                 }
474         }
475
476         if ( src->octet_str ) {
477                 for ( i=0; src->octet_str[i].bv_val; i++ ) {
478                         ber_dupbv( &tmp_bv, &src->octet_str[i] );
479                         ber_bvarray_add( &new->octet_str, &tmp_bv );
480                 }
481         }
482
483         return new;
484 }
485
486 int
487 slap_build_syncUUID_set(
488         Operation *op,
489         BerVarray *set,
490         Entry *e
491 )
492 {
493         int ret;
494         Attribute* a;
495
496         struct berval entryuuid_bv      = BER_BVNULL;
497
498         for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
499                 AttributeDescription *desc = a->a_desc;
500                 if ( desc == slap_schema.si_ad_entryUUID ) {
501                         ber_dupbv_x( &entryuuid_bv, &a->a_nvals[0], op->o_tmpmemctx );
502                 }
503         }
504
505         ret = ber_bvarray_add_x( set, &entryuuid_bv, op->o_tmpmemctx );
506
507         return ret;
508 }