]> git.sur5r.net Git - openldap/blob - servers/slapd/repl.c
reject registrations when back-monitor is not configured
[openldap] / servers / slapd / repl.c
1 /* repl.c - log modifications for replication purposes */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2005 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
17  * All rights reserved.
18  *
19  * Redistribution and use in source and binary forms are permitted
20  * provided that this notice is preserved and that due credit is given
21  * to the University of Michigan at Ann Arbor. The name of the University
22  * may not be used to endorse or promote products derived from this
23  * software without specific prior written permission. This software
24  * is provided ``as is'' without express or implied warranty.
25  */
26
27 #include "portable.h"
28
29 #include <stdio.h>
30
31 #include <ac/string.h>
32 #include <ac/ctype.h>
33 #include <ac/socket.h>
34
35 #ifdef HAVE_SYS_FILE_H
36 #include <sys/file.h>
37 #endif
38
39 #include "slap.h"
40 #include "ldif.h"
41
42 int
43 add_replica_info(
44         Backend         *be,
45         const char      *uri, 
46         const char      *host )
47 {
48         int i = 0;
49
50         assert( be != NULL );
51         assert( host != NULL );
52
53         if ( be->be_replica != NULL ) {
54                 for ( ; be->be_replica[ i ] != NULL; i++ );
55         }
56                 
57         be->be_replica = ch_realloc( be->be_replica, 
58                 sizeof( struct slap_replica_info * )*( i + 2 ) );
59
60         be->be_replica[ i ] 
61                 = ch_calloc( sizeof( struct slap_replica_info ), 1 );
62         be->be_replica[ i ]->ri_uri = uri;
63         be->be_replica[ i ]->ri_host = host;
64         be->be_replica[ i ]->ri_nsuffix = NULL;
65         be->be_replica[ i ]->ri_attrs = NULL;
66         be->be_replica[ i + 1 ] = NULL;
67
68         return( i );
69 }
70
71 int
72 destroy_replica_info(
73         Backend         *be )
74 {
75         int i = 0;
76
77         assert( be != NULL );
78
79         if ( be->be_replica == NULL ) {
80                 return 0;
81         }
82
83         for ( ; be->be_replica[ i ] != NULL; i++ ) {
84
85                 ch_free( (char *)be->be_replica[ i ]->ri_uri );
86
87                 ber_bvarray_free( be->be_replica[ i ]->ri_nsuffix );
88
89                 if ( be->be_replica[ i ]->ri_attrs ) {
90                         AttributeName   *an = be->be_replica[ i ]->ri_attrs;
91                         int             j;
92
93                         for ( j = 0; !BER_BVISNULL( &an[ j ].an_name ); j++ )
94                         {
95                                 ch_free( an[ j ].an_name.bv_val );
96                         }
97                         ch_free( an );
98                 }
99
100                 bindconf_free( &be->be_replica[ i ]->ri_bindconf );
101
102                 ch_free( be->be_replica[ i ] );
103         }
104
105         ch_free( be->be_replica );
106
107         return 0;
108 }
109
110 int
111 add_replica_suffix(
112     Backend     *be,
113     int         nr,
114     const char  *suffix
115 )
116 {
117         struct berval dn, ndn;
118         int rc;
119
120         dn.bv_val = (char *) suffix;
121         dn.bv_len = strlen( dn.bv_val );
122
123         rc = dnNormalize( 0, NULL, NULL, &dn, &ndn, NULL );
124         if( rc != LDAP_SUCCESS ) {
125                 return 2;
126         }
127
128         if ( select_backend( &ndn, 0, 0 ) != be ) {
129                 free( ndn.bv_val );
130                 return 1;
131         }
132
133         ber_bvarray_add( &be->be_replica[nr]->ri_nsuffix, &ndn );
134         return 0;
135 }
136
137 int
138 add_replica_attrs(
139         Backend *be,
140         int     nr,
141         char    *attrs,
142         int     exclude
143 )
144 {
145         if ( be->be_replica[nr]->ri_attrs != NULL ) {
146                 if ( be->be_replica[nr]->ri_exclude != exclude ) {
147                         fprintf( stderr, "attr selective replication directive '%s' conflicts with previous one (discarded)\n", attrs );
148                         ch_free( be->be_replica[nr]->ri_attrs );
149                         be->be_replica[nr]->ri_attrs = NULL;
150                 }
151         }
152
153         be->be_replica[nr]->ri_exclude = exclude;
154         be->be_replica[nr]->ri_attrs = str2anlist( be->be_replica[nr]->ri_attrs,
155                 attrs, "," );
156         return ( be->be_replica[nr]->ri_attrs == NULL );
157 }
158    
159 static void
160 print_vals( FILE *fp, struct berval *type, struct berval *bv );
161 static void
162 replog1( struct slap_replica_info *ri, Operation *op, FILE *fp, long now);
163
164 void
165 replog( Operation *op )
166 {
167         FILE    *fp, *lfp;
168         int     i;
169 /* undef NO_LOG_WHEN_NO_REPLICAS */
170 #ifdef NO_LOG_WHEN_NO_REPLICAS
171         int     count = 0;
172 #endif
173         int     subsets = 0;
174         long    now = slap_get_time();
175         char    *replogfile;
176
177         replogfile = op->o_bd->be_replogfile ? op->o_bd->be_replogfile :
178                 frontendDB->be_replogfile;
179         if ( !replogfile ) {
180                 return;
181         }
182
183         ldap_pvt_thread_mutex_lock( &replog_mutex );
184         if ( (fp = lock_fopen( replogfile, "a", &lfp )) == NULL ) {
185                 ldap_pvt_thread_mutex_unlock( &replog_mutex );
186                 return;
187         }
188
189         for ( i = 0; op->o_bd->be_replica != NULL && op->o_bd->be_replica[i] != NULL; i++ ) {
190                 /* check if dn's suffix matches legal suffixes, if any */
191                 if ( op->o_bd->be_replica[i]->ri_nsuffix != NULL ) {
192                         int j;
193
194                         for ( j = 0; op->o_bd->be_replica[i]->ri_nsuffix[j].bv_val; j++ ) {
195                                 if ( dnIsSuffix( &op->o_req_ndn, &op->o_bd->be_replica[i]->ri_nsuffix[j] ) ) {
196                                         break;
197                                 }
198                         }
199
200                         if ( !op->o_bd->be_replica[i]->ri_nsuffix[j].bv_val ) {
201                                 /* do not add "replica:" line */
202                                 continue;
203                         }
204                 }
205                 /* See if we only want a subset of attributes */
206                 if ( op->o_bd->be_replica[i]->ri_attrs != NULL &&
207                         ( op->o_tag == LDAP_REQ_MODIFY || op->o_tag == LDAP_REQ_ADD || op->o_tag == LDAP_REQ_EXTENDED ) ) {
208                         if ( !subsets ) {
209                                 subsets = i + 1;
210                         }
211                         /* Do attribute subsets by themselves in a second pass */
212                         continue;
213                 }
214
215                 fprintf( fp, "replica: %s\n", op->o_bd->be_replica[i]->ri_host );
216 #ifdef NO_LOG_WHEN_NO_REPLICAS
217                 ++count;
218 #endif
219         }
220
221 #ifdef NO_LOG_WHEN_NO_REPLICAS
222         if ( count == 0 && subsets == 0 ) {
223                 /* if no replicas matched, drop the log 
224                  * (should we log it anyway?) */
225                 lock_fclose( fp, lfp );
226                 ldap_pvt_thread_mutex_unlock( &replog_mutex );
227
228                 return;
229         }
230 #endif
231
232         replog1( NULL, op, fp, now );
233
234         if ( subsets > 0 ) {
235                 for ( i = subsets - 1; op->o_bd->be_replica[i] != NULL; i++ ) {
236
237                         /* If no attrs, we already did this above */
238                         if ( op->o_bd->be_replica[i]->ri_attrs == NULL ) {
239                                 continue;
240                         }
241
242                         /* check if dn's suffix matches legal suffixes, if any */
243                         if ( op->o_bd->be_replica[i]->ri_nsuffix != NULL ) {
244                                 int j;
245
246                                 for ( j = 0; op->o_bd->be_replica[i]->ri_nsuffix[j].bv_val; j++ ) {
247                                         if ( dnIsSuffix( &op->o_req_ndn, &op->o_bd->be_replica[i]->ri_nsuffix[j] ) ) {
248                                                 break;
249                                         }
250                                 }
251
252                                 if ( !op->o_bd->be_replica[i]->ri_nsuffix[j].bv_val ) {
253                                         /* no matching suffix found, skip it */
254                                         continue;
255                                 }
256                         }
257                         switch( op->o_tag ) {
258                         case LDAP_REQ_EXTENDED:
259                                 /* quick hack for extended operations */
260                                 /* assume change parameter is a Modifications* */
261                                 /* fall thru */
262                         case LDAP_REQ_MODIFY:
263                         case LDAP_REQ_ADD:
264                                 break;
265                         default:
266                                 /* Other operations were logged in the first pass */
267                                 continue;
268                         }
269                         replog1( op->o_bd->be_replica[i], op, fp, now );
270                 }
271         }
272
273         lock_fclose( fp, lfp );
274         ldap_pvt_thread_mutex_unlock( &replog_mutex );
275 }
276
277 static void
278 rephdr(
279         struct slap_replica_info *ri,
280         Operation *op,
281         FILE *fp,
282         long now
283 )
284 {
285         if ( ri ) {
286                 fprintf( fp, "replica: %s\n", ri->ri_host );
287         }
288         fprintf( fp, "time: %ld\n", now );
289         fprintf( fp, "dn: %s\n", op->o_req_dn.bv_val );
290 }
291
292 static void
293 replog1(
294         struct slap_replica_info *ri,
295         Operation *op,
296         FILE    *fp,
297         long    now
298 )
299 {
300         Modifications   *ml;
301         Attribute       *a;
302         AttributeName   *an;
303         int             dohdr = 1, ocs = -1;
304         struct berval vals[2];
305
306         vals[1].bv_val = NULL;
307         vals[1].bv_len = 0;
308
309         switch ( op->o_tag ) {
310         case LDAP_REQ_EXTENDED:
311                 /* quick hack for extended operations */
312                 /* assume change parameter is a Modifications* */
313                 /* fall thru */
314
315         case LDAP_REQ_MODIFY:
316                 for ( ml = op->orm_modlist; ml != NULL; ml = ml->sml_next ) {
317                         char *did = NULL, *type = ml->sml_desc->ad_cname.bv_val;
318                         switch ( ml->sml_op ) {
319                         case LDAP_MOD_ADD:
320                                 did = "add"; break;
321
322                         case LDAP_MOD_DELETE:
323                                 did = "delete"; break;
324
325                         case LDAP_MOD_REPLACE:
326                                 did = "replace"; break;
327
328                         case LDAP_MOD_INCREMENT:
329                                 did = "increment"; break;
330                         }
331                         if ( ri && ri->ri_attrs ) {
332                                 int is_in = ad_inlist( ml->sml_desc, ri->ri_attrs );
333
334                                 if ( ( !is_in && !ri->ri_exclude )
335                                         || ( is_in && ri->ri_exclude ) )
336                                 {
337                                         continue;
338                                 }
339                                 /* If this is objectClass, see if the value is included
340                                  * in any subset, otherwise drop it.
341                                  */
342                                 if ( ocs && ml->sml_desc == slap_schema.si_ad_objectClass
343                                         && ml->sml_values )
344                                 {
345                                         int i, first = 1;
346
347                                         if ( ocs == -1 ) ocs = 0;
348
349                                         for ( i=0; ml->sml_values[i].bv_val; i++ ) {
350                                                 int match = 0;
351                                                 for ( an = ri->ri_attrs; an->an_name.bv_val; an++ ) {
352                                                         if ( an->an_oc ) {
353                                                                 ocs = 1;
354                                                                 match |= an->an_oc_exclude;
355                                                                 if ( ml->sml_values[i].bv_len == an->an_name.bv_len
356                                                                         && !strcasecmp(ml->sml_values[i].bv_val,
357                                                                                 an->an_name.bv_val ) ) {
358                                                                         match = !an->an_oc_exclude;
359                                                                         break;
360                                                                 }
361                                                         }
362                                                 }
363                                                 /* Objectclasses need no special treatment, drop into
364                                                  * regular processing
365                                                  */
366                                                 if ( !ocs ) break;
367
368                                                 match ^= ri->ri_exclude;
369                                                 /* Found a match, log it */
370                                                 if ( match ) {
371                                                         if ( dohdr ) {
372                                                                 rephdr( ri, op, fp, now );
373                                                                 fprintf( fp, "changetype: modify\n" );
374                                                                 dohdr = 0;
375                                                         }
376                                                         if ( first ) {
377                                                                 fprintf( fp, "%s: %s\n", did, type );
378                                                                 first = 0;
379                                                         }
380                                                         vals[0] = an->an_name;
381                                                         print_vals( fp, &ml->sml_desc->ad_cname, vals );
382                                                         ocs = 2;
383                                                 }
384
385                                         }
386                                         /* Explicit objectclasses have been handled already */
387                                         if ( ocs ) {
388                                                 if ( ocs == 2 ) {
389                                                         fprintf( fp, "-\n" );
390                                                 }
391                                                 continue;
392                                         }
393                                 }
394                         }
395                         if ( dohdr ) {
396                                 rephdr( ri, op, fp, now );
397                                 fprintf( fp, "changetype: modify\n" );
398                                 dohdr = 0;
399                         }
400                         fprintf( fp, "%s: %s\n", did, type );
401                         if ( ml->sml_values ) {
402                                 print_vals( fp, &ml->sml_desc->ad_cname, ml->sml_values );
403                         }
404                         fprintf( fp, "-\n" );
405                 }
406                 break;
407
408         case LDAP_REQ_ADD:
409                 for ( a = op->ora_e->e_attrs ; a != NULL; a=a->a_next ) {
410                         if ( ri && ri->ri_attrs ) {
411                                 int is_in = ad_inlist( a->a_desc, ri->ri_attrs );
412                                 if ( ( !is_in && !ri->ri_exclude ) || ( is_in && ri->ri_exclude ) ) {
413                                         continue;
414                                 }
415
416                                 /* If the list includes objectClass names,
417                                  * only include those classes in the
418                                  * objectClass attribute
419                                  */
420                                 if ( ocs && a->a_desc == slap_schema.si_ad_objectClass ) {
421                                         int i;
422
423                                         if ( ocs == -1 ) ocs = 0;
424
425                                         for ( i=0; a->a_vals[i].bv_val; i++ ) {
426                                                 int match = 0;
427                                                 for ( an = ri->ri_attrs; an->an_name.bv_val; an++ ) {
428                                                         if ( an->an_oc ) {
429                                                                 ocs = 1;
430                                                                 match |= an->an_oc_exclude;
431                                                                 if ( a->a_vals[i].bv_len == an->an_name.bv_len
432                                                                         && !strcasecmp(a->a_vals[i].bv_val,
433                                                                                 an->an_name.bv_val ) ) {
434                                                                         match = !an->an_oc_exclude;
435                                                                         break;
436                                                                 }
437                                                         }
438                                                 }
439                                                 if ( !ocs ) break;
440
441                                                 match ^= ri->ri_exclude;
442                                                 if ( match ) {
443                                                         if ( dohdr ) {
444                                                                 rephdr( ri, op, fp, now );
445                                                                 fprintf( fp, "changetype: add\n" );
446                                                                 dohdr = 0;
447                                                         }
448                                                         vals[0] = an->an_name;
449                                                         print_vals( fp, &a->a_desc->ad_cname, vals );
450                                                 }
451                                         }
452                                         if ( ocs ) continue;
453                                 }
454                         }
455                         if ( dohdr ) {
456                                 rephdr( ri, op, fp, now );
457                                 fprintf( fp, "changetype: add\n" );
458                                 dohdr = 0;
459                         }
460                         print_vals( fp, &a->a_desc->ad_cname, a->a_vals );
461                 }
462                 break;
463
464         case LDAP_REQ_DELETE:
465                 rephdr( ri, op, fp, now );
466                 fprintf( fp, "changetype: delete\n" );
467                 break;
468
469         case LDAP_REQ_MODRDN:
470                 rephdr( ri, op, fp, now );
471                 fprintf( fp, "changetype: modrdn\n" );
472                 fprintf( fp, "newrdn: %s\n", op->orr_newrdn.bv_val );
473                 fprintf( fp, "deleteoldrdn: %d\n", op->orr_deleteoldrdn ? 1 : 0 );
474                 if( op->orr_newSup != NULL ) {
475                         fprintf( fp, "newsuperior: %s\n", op->orr_newSup->bv_val );
476                 }
477         }
478         fprintf( fp, "\n" );
479 }
480
481 static void
482 print_vals(
483         FILE *fp,
484         struct berval *type,
485         struct berval *bv )
486 {
487         ber_len_t i, len;
488         char    *buf, *bufp;
489
490         for ( i = 0, len = 0; bv && bv[i].bv_val; i++ ) {
491                 if ( bv[i].bv_len > len )
492                         len = bv[i].bv_len;
493         }
494
495         len = LDIF_SIZE_NEEDED( type->bv_len, len ) + 1;
496         buf = (char *) ch_malloc( len );
497
498         for ( ; bv && bv->bv_val; bv++ ) {
499                 bufp = buf;
500                 ldif_sput( &bufp, LDIF_PUT_VALUE, type->bv_val,
501                                     bv->bv_val, bv->bv_len );
502                 *bufp = '\0';
503
504                 fputs( buf, fp );
505
506         }
507         free( buf );
508 }