]> git.sur5r.net Git - openldap/blob - servers/slapd/back-meta/config.c
Merge remote branch 'origin/mdb.master'
[openldap] / servers / slapd / back-meta / config.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2012 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
27 #include <ac/string.h>
28 #include <ac/socket.h>
29
30 #include "slap.h"
31 #include "lutil.h"
32 #include "../back-ldap/back-ldap.h"
33 #include "back-meta.h"
34
35 static int
36 meta_back_new_target( 
37         metatarget_t    **mtp )
38 {
39         char                    *rargv[ 3 ];
40         metatarget_t            *mt;
41
42         *mtp = NULL;
43
44         mt = ch_calloc( sizeof( metatarget_t ), 1 );
45
46         mt->mt_rwmap.rwm_rw = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
47         if ( mt->mt_rwmap.rwm_rw == NULL ) {
48                 ch_free( mt );
49                 return -1;
50         }
51
52         /*
53          * the filter rewrite as a string must be disabled
54          * by default; it can be re-enabled by adding rules;
55          * this creates an empty rewriteContext
56          */
57         rargv[ 0 ] = "rewriteContext";
58         rargv[ 1 ] = "searchFilter";
59         rargv[ 2 ] = NULL;
60         rewrite_parse( mt->mt_rwmap.rwm_rw, "<suffix massage>", 1, 2, rargv );
61
62         rargv[ 0 ] = "rewriteContext";
63         rargv[ 1 ] = "default";
64         rargv[ 2 ] = NULL;
65         rewrite_parse( mt->mt_rwmap.rwm_rw, "<suffix massage>", 1, 2, rargv );
66
67         ldap_pvt_thread_mutex_init( &mt->mt_uri_mutex );
68
69         mt->mt_idassert_mode = LDAP_BACK_IDASSERT_LEGACY;
70         mt->mt_idassert_authmethod = LDAP_AUTH_NONE;
71         mt->mt_idassert_tls = SB_TLS_DEFAULT;
72
73         /* by default, use proxyAuthz control on each operation */
74         mt->mt_idassert_flags = LDAP_BACK_AUTH_PRESCRIPTIVE;
75
76         *mtp = mt;
77
78         return 0;
79 }
80
81 static int
82 check_true_false( char *str )
83 {
84         if ( strcasecmp( str, "true" ) == 0 || strcasecmp( str, "yes" ) == 0 ) {
85                 return 1;
86         }
87
88         if ( strcasecmp( str, "false" ) == 0 || strcasecmp( str, "no" ) == 0 ) {
89                 return 0;
90         }
91
92         return -1;
93 }
94
95 int
96 meta_subtree_destroy( metasubtree_t *ms )
97 {
98         if ( ms->ms_next ) {
99                 meta_subtree_destroy( ms->ms_next );
100         }
101
102         switch ( ms->ms_type ) {
103         case META_ST_SUBTREE:
104         case META_ST_SUBORDINATE:
105                 ber_memfree( ms->ms_dn.bv_val );
106                 break;
107
108         case META_ST_REGEX:
109                 regfree( &ms->ms_regex );
110                 ch_free( ms->ms_regex_pattern );
111                 break;
112
113         default:
114                 return -1;
115         }
116
117         ch_free( ms );
118
119         return 0;
120 }
121
122 static int
123 meta_subtree_config(
124         metatarget_t *mt,
125         int argc,
126         char **argv,
127         char *buf,
128         ber_len_t buflen,
129         char *log_prefix )
130 {
131         meta_st_t       type = META_ST_SUBTREE;
132         char            *pattern;
133         struct berval   ndn = BER_BVNULL;
134         metasubtree_t   *ms = NULL;
135
136         if ( strcasecmp( argv[0], "subtree-exclude" ) == 0 ) {
137                 if ( mt->mt_subtree && !mt->mt_subtree_exclude ) {
138                         snprintf( buf, buflen,
139                                 "\"subtree-exclude\" incompatible with previous \"subtree-include\" directives" );
140                         return 1;
141                 }
142
143                 mt->mt_subtree_exclude = 1;
144
145         } else {
146                 if ( mt->mt_subtree && mt->mt_subtree_exclude ) {
147                         snprintf( buf, buflen,
148                                 "\"subtree-include\" incompatible with previous \"subtree-exclude\" directives" );
149                         return 1;
150                 }
151         }
152
153         switch ( argc ) {
154         case 1:
155                 snprintf( buf, buflen, "missing pattern" );
156                 return 1;
157
158         case 2:
159                 break;
160
161         default:
162                 snprintf( buf, buflen, "too many args" );
163                 return 1;
164         }
165
166         pattern = argv[1];
167         if ( strncasecmp( pattern, "dn", STRLENOF( "dn" ) ) == 0 ) {
168                 char *style;
169
170                 pattern = &pattern[STRLENOF( "dn")];
171
172                 if ( pattern[0] == '.' ) {
173                         style = &pattern[1];
174
175                         if ( strncasecmp( style, "subtree", STRLENOF( "subtree" ) ) == 0 ) {
176                                 type = META_ST_SUBTREE;
177                                 pattern = &style[STRLENOF( "subtree" )];
178
179                         } else if ( strncasecmp( style, "children", STRLENOF( "children" ) ) == 0 ) {
180                                 type = META_ST_SUBORDINATE;
181                                 pattern = &style[STRLENOF( "children" )];
182
183                         } else if ( strncasecmp( style, "sub", STRLENOF( "sub" ) ) == 0 ) {
184                                 type = META_ST_SUBTREE;
185                                 pattern = &style[STRLENOF( "sub" )];
186
187                         } else if ( strncasecmp( style, "regex", STRLENOF( "regex" ) ) == 0 ) {
188                                 type = META_ST_REGEX;
189                                 pattern = &style[STRLENOF( "regex" )];
190
191                         } else {
192                                 snprintf( buf, buflen, "unknown style in \"dn.<style>\"" );
193                                 return 1;
194                         }
195                 }
196
197                 if ( pattern[0] != ':' ) {
198                         snprintf( buf, buflen, "missing colon after \"dn.<style>\"" );
199                         return 1;
200                 }
201                 pattern++;
202         }
203
204         switch ( type ) {
205         case META_ST_SUBTREE:
206         case META_ST_SUBORDINATE: {
207                 struct berval dn;
208
209                 ber_str2bv( pattern, 0, 0, &dn );
210                 if ( dnNormalize( 0, NULL, NULL, &dn, &ndn, NULL )
211                         != LDAP_SUCCESS )
212                 {
213                         snprintf( buf, buflen, "DN=\"%s\" is invalid", pattern );
214                         return 1;
215                 }
216
217                 if ( !dnIsSuffix( &ndn, &mt->mt_nsuffix ) ) {
218                         snprintf( buf, buflen,
219                                 "DN=\"%s\" is not a subtree of target \"%s\"",
220                                 pattern, mt->mt_nsuffix.bv_val );
221                         ber_memfree( ndn.bv_val );
222                         return( 1 );
223                 }
224                 } break;
225
226         default:
227                 /* silence warnings */
228                 break;
229         }
230
231         ms = ch_calloc( sizeof( metasubtree_t ), 1 );
232         ms->ms_type = type;
233
234         switch ( ms->ms_type ) {
235         case META_ST_SUBTREE:
236         case META_ST_SUBORDINATE:
237                 ms->ms_dn = ndn;
238                 break;
239
240         case META_ST_REGEX: {
241                 int rc;
242
243                 rc = regcomp( &ms->ms_regex, pattern, REG_EXTENDED|REG_ICASE );
244                 if ( rc != 0 ) {
245                         char regerr[ SLAP_TEXT_BUFLEN ];
246
247                         regerror( rc, &ms->ms_regex, regerr, sizeof(regerr) );
248
249                         snprintf( buf, sizeof( buf ),
250                                 "regular expression \"%s\" bad because of %s",
251                                 pattern, regerr );
252                         ch_free( ms );
253                         return 1;
254                 }
255                 ms->ms_regex_pattern = ch_strdup( pattern );
256                 } break;
257         }
258
259         if ( mt->mt_subtree == NULL ) {
260                  mt->mt_subtree = ms;
261
262         } else {
263                 metasubtree_t **msp;
264
265                 for ( msp = &mt->mt_subtree; *msp; ) {
266                         switch ( ms->ms_type ) {
267                         case META_ST_SUBTREE:
268                                 switch ( (*msp)->ms_type ) {
269                                 case META_ST_SUBTREE:
270                                         if ( dnIsSuffix( &(*msp)->ms_dn, &ms->ms_dn ) ) {
271                                                 metasubtree_t *tmp = *msp;
272                                                 Debug( LDAP_DEBUG_CONFIG,
273                                                         "%s: previous rule \"dn.subtree:%s\" is contained in rule \"dn.subtree:%s\" (replaced)\n",
274                                                         log_prefix, pattern, (*msp)->ms_dn.bv_val );
275                                                 *msp = (*msp)->ms_next;
276                                                 tmp->ms_next = NULL;
277                                                 meta_subtree_destroy( tmp );
278                                                 continue;
279
280                                         } else if ( dnIsSuffix( &ms->ms_dn, &(*msp)->ms_dn ) ) {
281                                                 Debug( LDAP_DEBUG_CONFIG,
282                                                         "%s: previous rule \"dn.subtree:%s\" contains rule \"dn.subtree:%s\" (ignored)\n",
283                                                         log_prefix, (*msp)->ms_dn.bv_val, pattern );
284                                                 meta_subtree_destroy( ms );
285                                                 ms = NULL;
286                                                 return( 0 );
287                                         }
288                                         break;
289
290                                 case META_ST_SUBORDINATE:
291                                         if ( dnIsSuffix( &(*msp)->ms_dn, &ms->ms_dn ) ) {
292                                                 metasubtree_t *tmp = *msp;
293                                                 Debug( LDAP_DEBUG_CONFIG,
294                                                         "%s: previous rule \"dn.children:%s\" is contained in rule \"dn.subtree:%s\" (replaced)\n",
295                                                         log_prefix, pattern, (*msp)->ms_dn.bv_val );
296                                                 *msp = (*msp)->ms_next;
297                                                 tmp->ms_next = NULL;
298                                                 meta_subtree_destroy( tmp );
299                                                 continue;
300
301                                         } else if ( dnIsSuffix( &ms->ms_dn, &(*msp)->ms_dn ) && ms->ms_dn.bv_len > (*msp)->ms_dn.bv_len ) {
302                                                 Debug( LDAP_DEBUG_CONFIG,
303                                                         "%s: previous rule \"dn.children:%s\" contains rule \"dn.subtree:%s\" (ignored)\n",
304                                                         log_prefix, (*msp)->ms_dn.bv_val, pattern );
305                                                 meta_subtree_destroy( ms );
306                                                 ms = NULL;
307                                                 return( 0 );
308                                         }
309                                         break;
310
311                                 case META_ST_REGEX:
312                                         if ( regexec( &(*msp)->ms_regex, ms->ms_dn.bv_val, 0, NULL, 0 ) == 0 ) {
313                                                 Debug( LDAP_DEBUG_CONFIG,
314                                                         "%s: previous rule \"dn.regex:%s\" may contain rule \"dn.subtree:%s\"\n",
315                                                         log_prefix, (*msp)->ms_regex_pattern, ms->ms_dn.bv_val );
316                                         }
317                                         break;
318                                 }
319                                 break;
320
321                         case META_ST_SUBORDINATE:
322                                 switch ( (*msp)->ms_type ) {
323                                 case META_ST_SUBTREE:
324                                         if ( dnIsSuffix( &(*msp)->ms_dn, &ms->ms_dn ) ) {
325                                                 metasubtree_t *tmp = *msp;
326                                                 Debug( LDAP_DEBUG_CONFIG,
327                                                         "%s: previous rule \"dn.children:%s\" is contained in rule \"dn.subtree:%s\" (replaced)\n",
328                                                         log_prefix, pattern, (*msp)->ms_dn.bv_val );
329                                                 *msp = (*msp)->ms_next;
330                                                 tmp->ms_next = NULL;
331                                                 meta_subtree_destroy( tmp );
332                                                 continue;
333
334                                         } else if ( dnIsSuffix( &ms->ms_dn, &(*msp)->ms_dn ) && ms->ms_dn.bv_len > (*msp)->ms_dn.bv_len ) {
335                                                 Debug( LDAP_DEBUG_CONFIG,
336                                                         "%s: previous rule \"dn.children:%s\" contains rule \"dn.subtree:%s\" (ignored)\n",
337                                                         log_prefix, (*msp)->ms_dn.bv_val, pattern );
338                                                 meta_subtree_destroy( ms );
339                                                 ms = NULL;
340                                                 return( 0 );
341                                         }
342                                         break;
343
344                                 case META_ST_SUBORDINATE:
345                                         if ( dnIsSuffix( &(*msp)->ms_dn, &ms->ms_dn ) ) {
346                                                 metasubtree_t *tmp = *msp;
347                                                 Debug( LDAP_DEBUG_CONFIG,
348                                                         "%s: previous rule \"dn.children:%s\" is contained in rule \"dn.children:%s\" (replaced)\n",
349                                                         log_prefix, pattern, (*msp)->ms_dn.bv_val );
350                                                 *msp = (*msp)->ms_next;
351                                                 tmp->ms_next = NULL;
352                                                 meta_subtree_destroy( tmp );
353                                                 continue;
354
355                                         } else if ( dnIsSuffix( &ms->ms_dn, &(*msp)->ms_dn ) ) {
356                                                 Debug( LDAP_DEBUG_CONFIG,
357                                                         "%s: previous rule \"dn.children:%s\" contains rule \"dn.children:%s\" (ignored)\n",
358                                                         log_prefix, (*msp)->ms_dn.bv_val, pattern );
359                                                 meta_subtree_destroy( ms );
360                                                 ms = NULL;
361                                                 return( 0 );
362                                         }
363                                         break;
364
365                                 case META_ST_REGEX:
366                                         if ( regexec( &(*msp)->ms_regex, ms->ms_dn.bv_val, 0, NULL, 0 ) == 0 ) {
367                                                 Debug( LDAP_DEBUG_CONFIG,
368                                                         "%s: previous rule \"dn.regex:%s\" may contain rule \"dn.subtree:%s\"\n",
369                                                         log_prefix, (*msp)->ms_regex_pattern, ms->ms_dn.bv_val );
370                                         }
371                                         break;
372                                 }
373                                 break;
374
375                         case META_ST_REGEX:
376                                 switch ( (*msp)->ms_type ) {
377                                 case META_ST_SUBTREE:
378                                 case META_ST_SUBORDINATE:
379                                         if ( regexec( &ms->ms_regex, (*msp)->ms_dn.bv_val, 0, NULL, 0 ) == 0 ) {
380                                                 Debug( LDAP_DEBUG_CONFIG,
381                                                         "%s: previous rule \"dn.subtree:%s\" may be contained in rule \"dn.regex:%s\"\n",
382                                                         log_prefix, (*msp)->ms_dn.bv_val, ms->ms_regex_pattern );
383                                         }
384                                         break;
385
386                                 case META_ST_REGEX:
387                                         /* no check possible */
388                                         break;
389                                 }
390                                 break;
391                         }
392
393                         msp = &(*msp)->ms_next;
394                 }
395
396                 *msp = ms;
397         }
398
399         return 0;
400 }
401
402 int
403 meta_back_db_config(
404                 BackendDB       *be,
405                 const char      *fname,
406                 int             lineno,
407                 int             argc,
408                 char            **argv )
409 {
410         metainfo_t      *mi = ( metainfo_t * )be->be_private;
411
412         assert( mi != NULL );
413
414         /* URI of server to query */
415         if ( strcasecmp( argv[ 0 ], "uri" ) == 0 ) {
416                 int             i = mi->mi_ntargets;
417                 LDAPURLDesc     *ludp;
418                 struct berval   dn;
419                 int             rc;
420                 int             c;
421
422                 metatarget_t    *mt;
423
424                 char            **uris = NULL;
425                 
426                 if ( argc == 1 ) {
427                         Debug( LDAP_DEBUG_ANY,
428         "%s: line %d: missing URI "
429         "in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
430                                 fname, lineno, 0 );
431                         return 1;
432                 }
433
434                 if ( be->be_nsuffix == NULL ) {
435                         Debug( LDAP_DEBUG_ANY,
436         "%s: line %d: the suffix must be defined before any target.\n",
437                                 fname, lineno, 0 );
438                         return 1;
439                 }
440                 
441                 ++mi->mi_ntargets;
442
443                 mi->mi_targets = ( metatarget_t ** )ch_realloc( mi->mi_targets, 
444                         sizeof( metatarget_t * ) * mi->mi_ntargets );
445                 if ( mi->mi_targets == NULL ) {
446                         Debug( LDAP_DEBUG_ANY,
447         "%s: line %d: out of memory while storing server name"
448         " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
449                                 fname, lineno, 0 );
450                         return 1;
451                 }
452
453                 if ( meta_back_new_target( &mi->mi_targets[ i ] ) != 0 ) {
454                         Debug( LDAP_DEBUG_ANY,
455         "%s: line %d: unable to init server"
456         " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
457                                 fname, lineno, 0 );
458                         return 1;
459                 }
460
461                 mt = mi->mi_targets[ i ];
462
463                 mt->mt_rebind_f = mi->mi_rebind_f;
464                 mt->mt_urllist_f = mi->mi_urllist_f;
465                 mt->mt_urllist_p = mt;
466
467                 mt->mt_nretries = mi->mi_nretries;
468                 mt->mt_quarantine = mi->mi_quarantine;
469                 if ( META_BACK_QUARANTINE( mi ) ) {
470                         ldap_pvt_thread_mutex_init( &mt->mt_quarantine_mutex );
471                 }
472                 mt->mt_flags = mi->mi_flags;
473                 mt->mt_version = mi->mi_version;
474 #ifdef SLAPD_META_CLIENT_PR
475                 mt->mt_ps = mi->mi_ps;
476 #endif /* SLAPD_META_CLIENT_PR */
477                 mt->mt_network_timeout = mi->mi_network_timeout;
478                 mt->mt_bind_timeout = mi->mi_bind_timeout;
479                 for ( c = 0; c < SLAP_OP_LAST; c++ ) {
480                         mt->mt_timeout[ c ] = mi->mi_timeout[ c ];
481                 }
482
483                 for ( c = 1; c < argc; c++ ) {
484                         char    **tmpuris = ldap_str2charray( argv[ c ], "\t" );
485
486                         if ( tmpuris == NULL ) {
487                                 Debug( LDAP_DEBUG_ANY,
488         "%s: line %d: unable to parse URIs #%d"
489         " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
490                                 fname, lineno, c - 1 );
491                                 return 1;
492                         }
493
494                         if ( c == 0 ) {
495                                 uris = tmpuris;
496
497                         } else {
498                                 ldap_charray_merge( &uris, tmpuris );
499                                 ldap_charray_free( tmpuris );
500                         }
501                 }
502
503                 for ( c = 0; uris[ c ] != NULL; c++ ) {
504                         char *tmpuri = NULL;
505
506                         /*
507                          * uri MUST be legal!
508                          */
509                         if ( ldap_url_parselist_ext( &ludp, uris[ c ], "\t",
510                                         LDAP_PVT_URL_PARSE_NONE ) != LDAP_SUCCESS
511                                 || ludp->lud_next != NULL )
512                         {
513                                 Debug( LDAP_DEBUG_ANY,
514                 "%s: line %d: unable to parse URI #%d"
515                 " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
516                                         fname, lineno, c );
517                                 ldap_charray_free( uris );
518                                 return 1;
519                         }
520
521                         if ( c == 0 ) {
522
523                                 /*
524                                  * uri MUST have the <dn> part!
525                                  */
526                                 if ( ludp->lud_dn == NULL ) {
527                                         Debug( LDAP_DEBUG_ANY,
528                         "%s: line %d: missing <naming context> "
529                         " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
530                                                 fname, lineno, 0 );
531                                         ldap_free_urllist( ludp );
532                                         ldap_charray_free( uris );
533                                         return 1;
534                                 }
535
536                                 /*
537                                  * copies and stores uri and suffix
538                                  */
539                                 ber_str2bv( ludp->lud_dn, 0, 0, &dn );
540                                 rc = dnPrettyNormal( NULL, &dn, &mt->mt_psuffix,
541                                         &mt->mt_nsuffix, NULL );
542                                 if ( rc != LDAP_SUCCESS ) {
543                                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
544                                                 "target \"%s\" DN is invalid\n",
545                                                 fname, lineno, argv[ 1 ] );
546                                         ldap_free_urllist( ludp );
547                                         ldap_charray_free( uris );
548                                         return( 1 );
549                                 }
550
551                                 ludp->lud_dn[ 0 ] = '\0';
552
553                                 switch ( ludp->lud_scope ) {
554                                 case LDAP_SCOPE_DEFAULT:
555                                         mt->mt_scope = LDAP_SCOPE_SUBTREE;
556                                         break;
557
558                                 case LDAP_SCOPE_SUBTREE:
559                                 case LDAP_SCOPE_SUBORDINATE:
560                                         mt->mt_scope = ludp->lud_scope;
561                                         break;
562
563                                 default:
564                                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
565                                                 "invalid scope for target \"%s\"\n",
566                                                 fname, lineno, argv[ 1 ] );
567                                         ldap_free_urllist( ludp );
568                                         ldap_charray_free( uris );
569                                         return( 1 );
570                                 }
571
572                         } else {
573                                 /* check all, to apply the scope check on the first one */
574                                 if ( ludp->lud_dn != NULL && ludp->lud_dn[ 0 ] != '\0' ) {
575                                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
576                                                 "multiple URIs must have "
577                                                 "no DN part\n",
578                                                 fname, lineno, 0 );
579                                         ldap_free_urllist( ludp );
580                                         ldap_charray_free( uris );
581                                         return( 1 );
582
583                                 }
584                         }
585
586                         tmpuri = ldap_url_list2urls( ludp );
587                         ldap_free_urllist( ludp );
588                         if ( tmpuri == NULL ) {
589                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: no memory?\n",
590                                         fname, lineno, 0 );
591                                 ldap_charray_free( uris );
592                                 return( 1 );
593                         }
594                         ldap_memfree( uris[ c ] );
595                         uris[ c ] = tmpuri;
596                 }
597
598                 mt->mt_uri = ldap_charray2str( uris, " " );
599                 ldap_charray_free( uris );
600                 if ( mt->mt_uri == NULL) {
601                         Debug( LDAP_DEBUG_ANY, "%s: line %d: no memory?\n",
602                                 fname, lineno, 0 );
603                         return( 1 );
604                 }
605                 
606                 /*
607                  * uri MUST be a branch of suffix!
608                  */
609                 for ( c = 0; !BER_BVISNULL( &be->be_nsuffix[ c ] ); c++ ) {
610                         if ( dnIsSuffix( &mt->mt_nsuffix, &be->be_nsuffix[ c ] ) ) {
611                                 break;
612                         }
613                 }
614
615                 if ( BER_BVISNULL( &be->be_nsuffix[ c ] ) ) {
616                         Debug( LDAP_DEBUG_ANY,
617         "%s: line %d: <naming context> of URI must be within the naming context of this database.\n",
618                                 fname, lineno, 0 );
619                         return 1;
620                 }
621
622         /* subtree-exclude */
623         } else if ( strcasecmp( argv[ 0 ], "subtree-exclude" ) == 0 ||
624                 strcasecmp( argv[ 0 ], "subtree-include" ) == 0)
625         {
626                 char log_prefix[SLAP_TEXT_BUFLEN];
627                 char textbuf[SLAP_TEXT_BUFLEN];
628                 char *arg0;
629                 int i = mi->mi_ntargets - 1;
630
631                 if ( i < 0 ) {
632                         Debug( LDAP_DEBUG_ANY,
633                 "%s: line %d: need \"uri\" directive first\n",
634                                 fname, lineno, 0 );
635                         return 1;
636                 }
637
638                 if ( strcasecmp( argv[ 0 ], "subtree-exclude" ) == 0 ) {
639                         arg0 = "subtree-exclude";
640
641                 } else {
642                         arg0 = "subtree-include";
643                 }
644
645                 snprintf( log_prefix, sizeof(log_prefix), "%s: line %d: %s", fname, lineno, arg0 );
646
647                 if ( meta_subtree_config( mi->mi_targets[ i ], argc, argv, textbuf, sizeof(textbuf), log_prefix ) ) {
648                         Debug( LDAP_DEBUG_ANY, "%s: %s\n", log_prefix, textbuf, 0 );
649                         return 1;
650                 }
651
652         /* default target directive */
653         } else if ( strcasecmp( argv[ 0 ], "default-target" ) == 0 ) {
654                 int             i = mi->mi_ntargets - 1;
655                 
656                 if ( argc == 1 ) {
657                         if ( i < 0 ) {
658                                 Debug( LDAP_DEBUG_ANY,
659         "%s: line %d: \"default-target\" alone need be"
660         " inside a \"uri\" directive\n",
661                                         fname, lineno, 0 );
662                                 return 1;
663                         }
664                         mi->mi_defaulttarget = i;
665
666                 } else {
667                         if ( strcasecmp( argv[ 1 ], "none" ) == 0 ) {
668                                 if ( i >= 0 ) {
669                                         Debug( LDAP_DEBUG_ANY,
670         "%s: line %d: \"default-target none\""
671         " should go before uri definitions\n",
672                                                 fname, lineno, 0 );
673                                 }
674                                 mi->mi_defaulttarget = META_DEFAULT_TARGET_NONE;
675
676                         } else {
677                                 
678                                 if ( lutil_atoi( &mi->mi_defaulttarget, argv[ 1 ] ) != 0
679                                         || mi->mi_defaulttarget < 0
680                                         || mi->mi_defaulttarget >= i - 1 )
681                                 {
682                                         Debug( LDAP_DEBUG_ANY,
683         "%s: line %d: illegal target number %d\n",
684                                                 fname, lineno, mi->mi_defaulttarget );
685                                         return 1;
686                                 }
687                         }
688                 }
689                 
690         /* ttl of dn cache */
691         } else if ( strcasecmp( argv[ 0 ], "dncache-ttl" ) == 0 ) {
692                 if ( argc != 2 ) {
693                         Debug( LDAP_DEBUG_ANY,
694         "%s: line %d: missing ttl in \"dncache-ttl <ttl>\" line\n",
695                                 fname, lineno, 0 );
696                         return 1;
697                 }
698                 
699                 if ( strcasecmp( argv[ 1 ], "forever" ) == 0 ) {
700                         mi->mi_cache.ttl = META_DNCACHE_FOREVER;
701
702                 } else if ( strcasecmp( argv[ 1 ], "disabled" ) == 0 ) {
703                         mi->mi_cache.ttl = META_DNCACHE_DISABLED;
704
705                 } else {
706                         unsigned long   t;
707
708                         if ( lutil_parse_time( argv[ 1 ], &t ) != 0 ) {
709                                 Debug( LDAP_DEBUG_ANY,
710         "%s: line %d: unable to parse ttl \"%s\" in \"dncache-ttl <ttl>\" line\n",
711                                         fname, lineno, argv[ 1 ] );
712                                 return 1;
713                         }
714                         mi->mi_cache.ttl = (time_t)t;
715                 }
716
717         /* network timeout when connecting to ldap servers */
718         } else if ( strcasecmp( argv[ 0 ], "network-timeout" ) == 0 ) {
719                 unsigned long   t;
720                 time_t          *tp = mi->mi_ntargets ?
721                                 &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_network_timeout
722                                 : &mi->mi_network_timeout;
723
724                 if ( argc != 2 ) {
725                         Debug( LDAP_DEBUG_ANY,
726         "%s: line %d: missing network timeout in \"network-timeout <seconds>\" line\n",
727                                 fname, lineno, 0 );
728                         return 1;
729                 }
730
731                 if ( lutil_parse_time( argv[ 1 ], &t ) ) {
732                         Debug( LDAP_DEBUG_ANY,
733         "%s: line %d: unable to parse timeout \"%s\" in \"network-timeout <seconds>\" line\n",
734                                 fname, lineno, argv[ 1 ] );
735                         return 1;
736
737                 }
738
739                 *tp = (time_t)t;
740
741         /* idle timeout when connecting to ldap servers */
742         } else if ( strcasecmp( argv[ 0 ], "idle-timeout" ) == 0 ) {
743                 unsigned long   t;
744
745                 switch ( argc ) {
746                 case 1:
747                         Debug( LDAP_DEBUG_ANY,
748         "%s: line %d: missing timeout value in \"idle-timeout <seconds>\" line\n",
749                                 fname, lineno, 0 );
750                         return 1;
751                 case 2:
752                         break;
753                 default:
754                         Debug( LDAP_DEBUG_ANY,
755         "%s: line %d: extra cruft after timeout value in \"idle-timeout <seconds>\" line\n",
756                                 fname, lineno, 0 );
757                         return 1;
758                 }
759
760                 if ( lutil_parse_time( argv[ 1 ], &t ) ) {
761                         Debug( LDAP_DEBUG_ANY,
762         "%s: line %d: unable to parse timeout \"%s\" in \"idle-timeout <seconds>\" line\n",
763                                 fname, lineno, argv[ 1 ] );
764                         return 1;
765
766                 }
767
768                 mi->mi_idle_timeout = (time_t)t;
769
770         /* conn ttl */
771         } else if ( strcasecmp( argv[ 0 ], "conn-ttl" ) == 0 ) {
772                 unsigned long   t;
773
774                 switch ( argc ) {
775                 case 1:
776                         Debug( LDAP_DEBUG_ANY,
777         "%s: line %d: missing ttl value in \"conn-ttl <seconds>\" line\n",
778                                 fname, lineno, 0 );
779                         return 1;
780                 case 2:
781                         break;
782                 default:
783                         Debug( LDAP_DEBUG_ANY,
784         "%s: line %d: extra cruft after ttl value in \"conn-ttl <seconds>\" line\n",
785                                 fname, lineno, 0 );
786                         return 1;
787                 }
788
789                 if ( lutil_parse_time( argv[ 1 ], &t ) ) {
790                         Debug( LDAP_DEBUG_ANY,
791         "%s: line %d: unable to parse ttl \"%s\" in \"conn-ttl <seconds>\" line\n",
792                                 fname, lineno, argv[ 1 ] );
793                         return 1;
794
795                 }
796
797                 mi->mi_conn_ttl = (time_t)t;
798
799         /* bind timeout when connecting to ldap servers */
800         } else if ( strcasecmp( argv[ 0 ], "bind-timeout" ) == 0 ) {
801                 unsigned long   t;
802                 struct timeval  *tp = mi->mi_ntargets ?
803                                 &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_bind_timeout
804                                 : &mi->mi_bind_timeout;
805
806                 switch ( argc ) {
807                 case 1:
808                         Debug( LDAP_DEBUG_ANY,
809         "%s: line %d: missing timeout value in \"bind-timeout <microseconds>\" line\n",
810                                 fname, lineno, 0 );
811                         return 1;
812                 case 2:
813                         break;
814                 default:
815                         Debug( LDAP_DEBUG_ANY,
816         "%s: line %d: extra cruft after timeout value in \"bind-timeout <microseconds>\" line\n",
817                                 fname, lineno, 0 );
818                         return 1;
819                 }
820
821                 if ( lutil_atoul( &t, argv[ 1 ] ) != 0 ) {
822                         Debug( LDAP_DEBUG_ANY,
823         "%s: line %d: unable to parse timeout \"%s\" in \"bind-timeout <microseconds>\" line\n",
824                                 fname, lineno, argv[ 1 ] );
825                         return 1;
826
827                 }
828
829                 tp->tv_sec = t/1000000;
830                 tp->tv_usec = t%1000000;
831
832         /* name to use for meta_back_group */
833         } else if ( strcasecmp( argv[ 0 ], "acl-authcDN" ) == 0
834                         || strcasecmp( argv[ 0 ], "binddn" ) == 0 )
835         {
836                 int             i = mi->mi_ntargets - 1;
837                 struct berval   dn;
838
839                 if ( i < 0 ) {
840                         Debug( LDAP_DEBUG_ANY,
841         "%s: line %d: need \"uri\" directive first\n",
842                                 fname, lineno, 0 );
843                         return 1;
844                 }
845                 
846                 if ( argc != 2 ) {
847                         Debug( LDAP_DEBUG_ANY,
848         "%s: line %d: missing name in \"binddn <name>\" line\n",
849                                 fname, lineno, 0 );
850                         return 1;
851                 }
852
853                 if ( strcasecmp( argv[ 0 ], "binddn" ) == 0 ) {
854                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
855                                 "\"binddn\" statement is deprecated; "
856                                 "use \"acl-authcDN\" instead\n",
857                                 fname, lineno, 0 );
858                         /* FIXME: some day we'll need to throw an error */
859                 }
860
861                 ber_str2bv( argv[ 1 ], 0, 0, &dn );
862                 if ( dnNormalize( 0, NULL, NULL, &dn, &mi->mi_targets[ i ]->mt_binddn,
863                         NULL ) != LDAP_SUCCESS )
864                 {
865                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
866                                         "bind DN '%s' is invalid\n",
867                                         fname, lineno, argv[ 1 ] );
868                         return( 1 );
869                 }
870
871         /* password to use for meta_back_group */
872         } else if ( strcasecmp( argv[ 0 ], "acl-passwd" ) == 0
873                         || strcasecmp( argv[ 0 ], "bindpw" ) == 0 )
874         {
875                 int             i = mi->mi_ntargets - 1;
876
877                 if ( i < 0 ) {
878                         Debug( LDAP_DEBUG_ANY,
879         "%s: line %d: need \"uri\" directive first\n",
880                                 fname, lineno, 0 );
881                         return 1;
882                 }
883
884                 if ( argc != 2 ) {
885                         Debug( LDAP_DEBUG_ANY,
886         "%s: line %d: missing password in \"bindpw <password>\" line\n",
887                             fname, lineno, 0 );
888                         return 1;
889                 }
890
891                 if ( strcasecmp( argv[ 0 ], "bindpw" ) == 0 ) {
892                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
893                                 "\"bindpw\" statement is deprecated; "
894                                 "use \"acl-passwd\" instead\n",
895                                 fname, lineno, 0 );
896                         /* FIXME: some day we'll need to throw an error */
897                 }
898
899                 ber_str2bv( argv[ 1 ], 0L, 1, &mi->mi_targets[ i ]->mt_bindpw );
900                 
901         /* save bind creds for referral rebinds? */
902         } else if ( strcasecmp( argv[ 0 ], "rebind-as-user" ) == 0 ) {
903                 unsigned        *flagsp = mi->mi_ntargets ?
904                                 &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_flags
905                                 : &mi->mi_flags;
906
907                 if ( argc > 2 ) {
908                         Debug( LDAP_DEBUG_ANY,
909         "%s: line %d: \"rebind-as-user {NO|yes}\" takes 1 argument.\n",
910                             fname, lineno, 0 );
911                         return( 1 );
912                 }
913
914                 if ( argc == 1 ) {
915                         Debug( LDAP_DEBUG_ANY,
916         "%s: line %d: deprecated use of \"rebind-as-user {FALSE|true}\" with no arguments.\n",
917                             fname, lineno, 0 );
918                         *flagsp |= LDAP_BACK_F_SAVECRED;
919
920                 } else {
921                         switch ( check_true_false( argv[ 1 ] ) ) {
922                         case 0:
923                                 *flagsp &= ~LDAP_BACK_F_SAVECRED;
924                                 break;
925
926                         case 1:
927                                 *flagsp |= LDAP_BACK_F_SAVECRED;
928                                 break;
929
930                         default:
931                                 Debug( LDAP_DEBUG_ANY,
932         "%s: line %d: \"rebind-as-user {FALSE|true}\" unknown argument \"%s\".\n",
933                                     fname, lineno, argv[ 1 ] );
934                                 return 1;
935                         }
936                 }
937
938         } else if ( strcasecmp( argv[ 0 ], "chase-referrals" ) == 0 ) {
939                 unsigned        *flagsp = mi->mi_ntargets ?
940                                 &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_flags
941                                 : &mi->mi_flags;
942
943                 if ( argc != 2 ) {
944                         Debug( LDAP_DEBUG_ANY,
945         "%s: line %d: \"chase-referrals {TRUE|false}\" needs 1 argument.\n",
946                                 fname, lineno, 0 );
947                         return( 1 );
948                 }
949
950                 /* this is the default; we add it because the default might change... */
951                 switch ( check_true_false( argv[ 1 ] ) ) {
952                 case 1:
953                         *flagsp |= LDAP_BACK_F_CHASE_REFERRALS;
954                         break;
955
956                 case 0:
957                         *flagsp &= ~LDAP_BACK_F_CHASE_REFERRALS;
958                         break;
959
960                 default:
961                         Debug( LDAP_DEBUG_ANY,
962                 "%s: line %d: \"chase-referrals {TRUE|false}\": unknown argument \"%s\".\n",
963                                 fname, lineno, argv[ 1 ] );
964                         return( 1 );
965                 }
966         
967         } else if ( strcasecmp( argv[ 0 ], "tls" ) == 0 ) {
968                 unsigned        *flagsp = mi->mi_ntargets ?
969                                 &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_flags
970                                 : &mi->mi_flags;
971
972                 /* start */
973                 if ( strcasecmp( argv[ 1 ], "start" ) == 0 ) {
974                         *flagsp |= ( LDAP_BACK_F_USE_TLS | LDAP_BACK_F_TLS_CRITICAL );
975         
976                 /* try start tls */
977                 } else if ( strcasecmp( argv[ 1 ], "try-start" ) == 0 ) {
978                         *flagsp &= ~LDAP_BACK_F_TLS_CRITICAL;
979                         *flagsp |= LDAP_BACK_F_USE_TLS;
980         
981                 /* propagate start tls */
982                 } else if ( strcasecmp( argv[ 1 ], "propagate" ) == 0 ) {
983                         *flagsp |= ( LDAP_BACK_F_PROPAGATE_TLS | LDAP_BACK_F_TLS_CRITICAL );
984                 
985                 /* try start tls */
986                 } else if ( strcasecmp( argv[ 1 ], "try-propagate" ) == 0 ) {
987                         *flagsp &= ~LDAP_BACK_F_TLS_CRITICAL;
988                         *flagsp |= LDAP_BACK_F_PROPAGATE_TLS;
989
990                 } else {
991                         Debug( LDAP_DEBUG_ANY,
992                 "%s: line %d: \"tls <what>\": unknown argument \"%s\".\n",
993                                 fname, lineno, argv[ 1 ] );
994                         return( 1 );
995                 }
996
997                 if ( argc > 2 ) {
998                         metatarget_t    *mt = NULL;
999                         int             i;
1000
1001                         if ( mi->mi_ntargets - 1 < 0 ) {
1002                                 Debug( LDAP_DEBUG_ANY,
1003                 "%s: line %d: need \"uri\" directive first\n",
1004                                         fname, lineno, 0 );
1005                                 return 1;
1006                         }
1007
1008                         mt = mi->mi_targets[ mi->mi_ntargets - 1 ];
1009
1010                         for ( i = 2; i < argc; i++ ) {
1011                                 if ( bindconf_tls_parse( argv[i], &mt->mt_tls ))
1012                                         return 1;
1013                         }
1014                         bindconf_tls_defaults( &mt->mt_tls );
1015                 }
1016
1017         } else if ( strcasecmp( argv[ 0 ], "t-f-support" ) == 0 ) {
1018                 unsigned        *flagsp = mi->mi_ntargets ?
1019                                 &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_flags
1020                                 : &mi->mi_flags;
1021
1022                 if ( argc != 2 ) {
1023                         Debug( LDAP_DEBUG_ANY,
1024                 "%s: line %d: \"t-f-support {FALSE|true|discover}\" needs 1 argument.\n",
1025                                 fname, lineno, 0 );
1026                         return( 1 );
1027                 }
1028
1029                 switch ( check_true_false( argv[ 1 ] ) ) {
1030                 case 0:
1031                         *flagsp &= ~LDAP_BACK_F_T_F_MASK2;
1032                         break;
1033
1034                 case 1:
1035                         *flagsp |= LDAP_BACK_F_T_F;
1036                         break;
1037
1038                 default:
1039                         if ( strcasecmp( argv[ 1 ], "discover" ) == 0 ) {
1040                                 *flagsp |= LDAP_BACK_F_T_F_DISCOVER;
1041
1042                         } else {
1043                                 Debug( LDAP_DEBUG_ANY,
1044         "%s: line %d: unknown value \"%s\" for \"t-f-support {no|yes|discover}\".\n",
1045                                         fname, lineno, argv[ 1 ] );
1046                                 return 1;
1047                         }
1048                         break;
1049                 }
1050
1051         /* onerr? */
1052         } else if ( strcasecmp( argv[ 0 ], "onerr" ) == 0 ) {
1053                 if ( argc != 2 ) {
1054                         Debug( LDAP_DEBUG_ANY,
1055         "%s: line %d: \"onerr {CONTINUE|report|stop}\" takes 1 argument\n",
1056                                 fname, lineno, 0 );
1057                         return( 1 );
1058                 }
1059
1060                 if ( strcasecmp( argv[ 1 ], "continue" ) == 0 ) {
1061                         mi->mi_flags &= ~META_BACK_F_ONERR_MASK;
1062
1063                 } else if ( strcasecmp( argv[ 1 ], "stop" ) == 0 ) {
1064                         mi->mi_flags |= META_BACK_F_ONERR_STOP;
1065
1066                 } else if ( strcasecmp( argv[ 1 ], "report" ) == 0 ) {
1067                         mi->mi_flags |= META_BACK_F_ONERR_REPORT;
1068
1069                 } else {
1070                         Debug( LDAP_DEBUG_ANY,
1071         "%s: line %d: \"onerr {CONTINUE|report|stop}\": invalid arg \"%s\".\n",
1072                                 fname, lineno, argv[ 1 ] );
1073                         return 1;
1074                 }
1075
1076         /* bind-defer? */
1077         } else if ( strcasecmp( argv[ 0 ], "pseudoroot-bind-defer" ) == 0
1078                 || strcasecmp( argv[ 0 ], "root-bind-defer" ) == 0 )
1079         {
1080                 if ( argc != 2 ) {
1081                         Debug( LDAP_DEBUG_ANY,
1082         "%s: line %d: \"[pseudo]root-bind-defer {TRUE|false}\" takes 1 argument\n",
1083                                 fname, lineno, 0 );
1084                         return( 1 );
1085                 }
1086
1087                 switch ( check_true_false( argv[ 1 ] ) ) {
1088                 case 0:
1089                         mi->mi_flags &= ~META_BACK_F_DEFER_ROOTDN_BIND;
1090                         break;
1091
1092                 case 1:
1093                         mi->mi_flags |= META_BACK_F_DEFER_ROOTDN_BIND;
1094                         break;
1095
1096                 default:
1097                         Debug( LDAP_DEBUG_ANY,
1098         "%s: line %d: \"[pseudo]root-bind-defer {TRUE|false}\": invalid arg \"%s\".\n",
1099                                 fname, lineno, argv[ 1 ] );
1100                         return 1;
1101                 }
1102
1103         /* single-conn? */
1104         } else if ( strcasecmp( argv[ 0 ], "single-conn" ) == 0 ) {
1105                 if ( argc != 2 ) {
1106                         Debug( LDAP_DEBUG_ANY,
1107         "%s: line %d: \"single-conn {FALSE|true}\" takes 1 argument\n",
1108                                 fname, lineno, 0 );
1109                         return( 1 );
1110                 }
1111
1112                 if ( mi->mi_ntargets > 0 ) {
1113                         Debug( LDAP_DEBUG_ANY,
1114         "%s: line %d: \"single-conn\" must appear before target definitions\n",
1115                                 fname, lineno, 0 );
1116                         return( 1 );
1117                 }
1118
1119                 switch ( check_true_false( argv[ 1 ] ) ) {
1120                 case 0:
1121                         mi->mi_flags &= ~LDAP_BACK_F_SINGLECONN;
1122                         break;
1123
1124                 case 1:
1125                         mi->mi_flags |= LDAP_BACK_F_SINGLECONN;
1126                         break;
1127
1128                 default:
1129                         Debug( LDAP_DEBUG_ANY,
1130         "%s: line %d: \"single-conn {FALSE|true}\": invalid arg \"%s\".\n",
1131                                 fname, lineno, argv[ 1 ] );
1132                         return 1;
1133                 }
1134
1135         /* use-temporaries? */
1136         } else if ( strcasecmp( argv[ 0 ], "use-temporary-conn" ) == 0 ) {
1137                 if ( argc != 2 ) {
1138                         Debug( LDAP_DEBUG_ANY,
1139         "%s: line %d: \"use-temporary-conn {FALSE|true}\" takes 1 argument\n",
1140                                 fname, lineno, 0 );
1141                         return( 1 );
1142                 }
1143
1144                 if ( mi->mi_ntargets > 0 ) {
1145                         Debug( LDAP_DEBUG_ANY,
1146         "%s: line %d: \"use-temporary-conn\" must appear before target definitions\n",
1147                                 fname, lineno, 0 );
1148                         return( 1 );
1149                 }
1150
1151                 switch ( check_true_false( argv[ 1 ] ) ) {
1152                 case 0:
1153                         mi->mi_flags &= ~LDAP_BACK_F_USE_TEMPORARIES;
1154                         break;
1155
1156                 case 1:
1157                         mi->mi_flags |= LDAP_BACK_F_USE_TEMPORARIES;
1158                         break;
1159
1160                 default:
1161                         Debug( LDAP_DEBUG_ANY,
1162         "%s: line %d: \"use-temporary-conn {FALSE|true}\": invalid arg \"%s\".\n",
1163                                 fname, lineno, argv[ 1 ] );
1164                         return 1;
1165                 }
1166
1167         /* privileged connections pool max size ? */
1168         } else if ( strcasecmp( argv[ 0 ], "conn-pool-max" ) == 0 ) {
1169                 if ( argc != 2 ) {
1170                         Debug( LDAP_DEBUG_ANY,
1171         "%s: line %d: \"conn-pool-max <n>\" takes 1 argument\n",
1172                                 fname, lineno, 0 );
1173                         return( 1 );
1174                 }
1175
1176                 if ( mi->mi_ntargets > 0 ) {
1177                         Debug( LDAP_DEBUG_ANY,
1178         "%s: line %d: \"conn-pool-max\" must appear before target definitions\n",
1179                                 fname, lineno, 0 );
1180                         return( 1 );
1181                 }
1182
1183                 if ( lutil_atoi( &mi->mi_conn_priv_max, argv[1] )
1184                         || mi->mi_conn_priv_max < LDAP_BACK_CONN_PRIV_MIN
1185                         || mi->mi_conn_priv_max > LDAP_BACK_CONN_PRIV_MAX )
1186                 {
1187                         Debug( LDAP_DEBUG_ANY,
1188         "%s: line %d: \"conn-pool-max <n>\": invalid arg \"%s\".\n",
1189                                 fname, lineno, argv[ 1 ] );
1190                         return 1;
1191                 }
1192
1193         } else if ( strcasecmp( argv[ 0 ], "cancel" ) == 0 ) {
1194                 unsigned        flag = 0;
1195                 unsigned        *flagsp = mi->mi_ntargets ?
1196                                 &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_flags
1197                                 : &mi->mi_flags;
1198
1199                 if ( argc != 2 ) {
1200                         Debug( LDAP_DEBUG_ANY,
1201         "%s: line %d: \"cancel {abandon|ignore|exop}\" takes 1 argument\n",
1202                                 fname, lineno, 0 );
1203                         return( 1 );
1204                 }
1205
1206                 if ( strcasecmp( argv[ 1 ], "abandon" ) == 0 ) {
1207                         flag = LDAP_BACK_F_CANCEL_ABANDON;
1208
1209                 } else if ( strcasecmp( argv[ 1 ], "ignore" ) == 0 ) {
1210                         flag = LDAP_BACK_F_CANCEL_IGNORE;
1211
1212                 } else if ( strcasecmp( argv[ 1 ], "exop" ) == 0 ) {
1213                         flag = LDAP_BACK_F_CANCEL_EXOP;
1214
1215                 } else if ( strcasecmp( argv[ 1 ], "exop-discover" ) == 0 ) {
1216                         flag = LDAP_BACK_F_CANCEL_EXOP_DISCOVER;
1217
1218                 } else {
1219                         Debug( LDAP_DEBUG_ANY,
1220         "%s: line %d: \"cancel {abandon|ignore|exop[-discover]}\": unknown mode \"%s\" \n",
1221                                 fname, lineno, argv[ 1 ] );
1222                         return( 1 );
1223                 }
1224
1225                 *flagsp &= ~LDAP_BACK_F_CANCEL_MASK2;
1226                 *flagsp |= flag;
1227
1228         } else if ( strcasecmp( argv[ 0 ], "timeout" ) == 0 ) {
1229                 char    *sep;
1230                 time_t  *tv = mi->mi_ntargets ?
1231                                 mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_timeout
1232                                 : mi->mi_timeout;
1233                 int     c;
1234
1235                 if ( argc < 2 ) {
1236                         Debug( LDAP_DEBUG_ANY,
1237         "%s: line %d: \"timeout [{add|bind|delete|modify|modrdn}=]<val> [...]\" takes at least 1 argument\n",
1238                                 fname, lineno, 0 );
1239                         return( 1 );
1240                 }
1241
1242                 for ( c = 1; c < argc; c++ ) {
1243                         time_t          *t = NULL;
1244                         unsigned long   val;
1245
1246                         sep = strchr( argv[ c ], '=' );
1247                         if ( sep != NULL ) {
1248                                 size_t  len = sep - argv[ c ];
1249
1250                                 if ( strncasecmp( argv[ c ], "bind", len ) == 0 ) {
1251                                         t = &tv[ SLAP_OP_BIND ];
1252                                 /* unbind makes little sense */
1253                                 } else if ( strncasecmp( argv[ c ], "add", len ) == 0 ) {
1254                                         t = &tv[ SLAP_OP_ADD ];
1255                                 } else if ( strncasecmp( argv[ c ], "delete", len ) == 0 ) {
1256                                         t = &tv[ SLAP_OP_DELETE ];
1257                                 } else if ( strncasecmp( argv[ c ], "modrdn", len ) == 0 ) {
1258                                         t = &tv[ SLAP_OP_MODRDN ];
1259                                 } else if ( strncasecmp( argv[ c ], "modify", len ) == 0 ) {
1260                                         t = &tv[ SLAP_OP_MODIFY ];
1261                                 } else if ( strncasecmp( argv[ c ], "compare", len ) == 0 ) {
1262                                         t = &tv[ SLAP_OP_COMPARE ];
1263                                 } else if ( strncasecmp( argv[ c ], "search", len ) == 0 ) {
1264                                         t = &tv[ SLAP_OP_SEARCH ];
1265                                 /* abandon makes little sense */
1266 #if 0                           /* not implemented yet */
1267                                 } else if ( strncasecmp( argv[ c ], "extended", len ) == 0 ) {
1268                                         t = &tv[ SLAP_OP_EXTENDED ];
1269 #endif
1270                                 } else {
1271                                         char    buf[ SLAP_TEXT_BUFLEN ];
1272                                         snprintf( buf, sizeof( buf ),
1273                                                 "unknown/unhandled operation \"%s\" for timeout #%d",
1274                                                 argv[ c ], c - 1 );
1275                                         Debug( LDAP_DEBUG_ANY,
1276                                                 "%s: line %d: %s.\n",
1277                                                 fname, lineno, buf );
1278                                         return 1;
1279                                 }
1280                                 sep++;
1281         
1282                         } else {
1283                                 sep = argv[ c ];
1284                         }
1285         
1286                         if ( lutil_parse_time( sep, &val ) != 0 ) {
1287                                 Debug( LDAP_DEBUG_ANY,
1288                 "%s: line %d: unable to parse value \"%s\" for timeout.\n",
1289                                         fname, lineno, sep );
1290                                 return 1;
1291                         }
1292                 
1293                         if ( t ) {
1294                                 *t = (time_t)val;
1295         
1296                         } else {
1297                                 int     i;
1298         
1299                                 for ( i = 0; i < SLAP_OP_LAST; i++ ) {
1300                                         tv[ i ] = (time_t)val;
1301                                 }
1302                         }
1303                 }
1304         
1305         /* name to use as pseudo-root dn */
1306         } else if ( strcasecmp( argv[ 0 ], "pseudorootdn" ) == 0 ) {
1307                 int             i = mi->mi_ntargets - 1;
1308
1309                 if ( i < 0 ) {
1310                         Debug( LDAP_DEBUG_ANY,
1311         "%s: line %d: need \"uri\" directive first\n",
1312                                 fname, lineno, 0 );
1313                         return 1;
1314                 }
1315                 
1316                 if ( argc != 2 ) {
1317                         Debug( LDAP_DEBUG_ANY,
1318         "%s: line %d: missing name in \"pseudorootdn <name>\" line\n",
1319                                 fname, lineno, 0 );
1320                         return 1;
1321                 }
1322
1323                 /*
1324                  * exact replacement:
1325                  *
1326
1327 idassert-bind   bindmethod=simple
1328                 binddn=<pseudorootdn>
1329                 credentials=<pseudorootpw>
1330                 mode=none
1331                 flags=non-prescriptive
1332 idassert-authzFrom      "dn:<rootdn>"
1333
1334                  * so that only when authc'd as <rootdn> the proxying occurs
1335                  * rebinding as the <pseudorootdn> without proxyAuthz.
1336                  */
1337
1338                 Debug( LDAP_DEBUG_ANY,
1339                         "%s: line %d: \"pseudorootdn\", \"pseudorootpw\" are no longer supported; "
1340                         "use \"idassert-bind\" and \"idassert-authzFrom\" instead.\n",
1341                         fname, lineno, 0 );
1342
1343                 {
1344                         char    binddn[ SLAP_TEXT_BUFLEN ];
1345                         char    *cargv[] = {
1346                                 "idassert-bind",
1347                                 "bindmethod=simple",
1348                                 NULL,
1349                                 "mode=none",
1350                                 "flags=non-prescriptive",
1351                                 NULL
1352                         };
1353                         int     cargc = 5;
1354                         int     rc;
1355
1356                         if ( BER_BVISNULL( &be->be_rootndn ) ) {
1357                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: \"pseudorootpw\": \"rootdn\" must be defined first.\n",
1358                                         fname, lineno, 0 );
1359                                 return 1;
1360                         }
1361
1362                         if ( sizeof( binddn ) <= (unsigned) snprintf( binddn,
1363                                         sizeof( binddn ), "binddn=%s", argv[ 1 ] ))
1364                         {
1365                                 Debug( LDAP_DEBUG_ANY, "%s: line %d: \"pseudorootdn\" too long.\n",
1366                                         fname, lineno, 0 );
1367                                 return 1;
1368                         }
1369                         cargv[ 2 ] = binddn;
1370
1371                         rc = mi->mi_ldap_extra->idassert_parse_cf( fname, lineno, cargc, cargv, &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert );
1372                         if ( rc == 0 ) {
1373                                 struct berval   bv;
1374
1375                                 if ( mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert_authz != NULL ) {
1376                                         Debug( LDAP_DEBUG_ANY, "%s: line %d: \"idassert-authzFrom\" already defined (discarded).\n",
1377                                                 fname, lineno, 0 );
1378                                         ber_bvarray_free( mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert_authz );
1379                                         mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert_authz = NULL;
1380                                 }
1381
1382                                 assert( !BER_BVISNULL( &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert_authcDN ) );
1383
1384                                 bv.bv_len = STRLENOF( "dn:" ) + be->be_rootndn.bv_len;
1385                                 bv.bv_val = ber_memalloc( bv.bv_len + 1 );
1386                                 AC_MEMCPY( bv.bv_val, "dn:", STRLENOF( "dn:" ) );
1387                                 AC_MEMCPY( &bv.bv_val[ STRLENOF( "dn:" ) ], be->be_rootndn.bv_val, be->be_rootndn.bv_len + 1 );
1388
1389                                 ber_bvarray_add( &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert_authz, &bv );
1390                         }
1391
1392                         return rc;
1393                 }
1394
1395         /* password to use as pseudo-root */
1396         } else if ( strcasecmp( argv[ 0 ], "pseudorootpw" ) == 0 ) {
1397                 int             i = mi->mi_ntargets - 1;
1398
1399                 if ( i < 0 ) {
1400                         Debug( LDAP_DEBUG_ANY,
1401         "%s: line %d: need \"uri\" directive first\n",
1402                                 fname, lineno, 0 );
1403                         return 1;
1404                 }
1405                 
1406                 if ( argc != 2 ) {
1407                         Debug( LDAP_DEBUG_ANY,
1408         "%s: line %d: missing password in \"pseudorootpw <password>\" line\n",
1409                             fname, lineno, 0 );
1410                         return 1;
1411                 }
1412
1413                 Debug( LDAP_DEBUG_ANY,
1414                         "%s: line %d: \"pseudorootdn\", \"pseudorootpw\" are no longer supported; "
1415                         "use \"idassert-bind\" and \"idassert-authzFrom\" instead.\n",
1416                         fname, lineno, 0 );
1417
1418                 if ( BER_BVISNULL( &mi->mi_targets[ i ]->mt_idassert_authcDN ) ) {
1419                         Debug( LDAP_DEBUG_ANY, "%s: line %d: \"pseudorootpw\": \"pseudorootdn\" must be defined first.\n",
1420                                 fname, lineno, 0 );
1421                         return 1;
1422                 }
1423
1424                 if ( !BER_BVISNULL( &mi->mi_targets[ i ]->mt_idassert_passwd ) ) {
1425                         memset( mi->mi_targets[ i ]->mt_idassert_passwd.bv_val, 0,
1426                                 mi->mi_targets[ i ]->mt_idassert_passwd.bv_len );
1427                         ber_memfree( mi->mi_targets[ i ]->mt_idassert_passwd.bv_val );
1428                 }
1429                 ber_str2bv( argv[ 1 ], 0, 1, &mi->mi_targets[ i ]->mt_idassert_passwd );
1430
1431         /* idassert-bind */
1432         } else if ( strcasecmp( argv[ 0 ], "idassert-bind" ) == 0 ) {
1433                 if ( mi->mi_ntargets == 0 ) {
1434                         Debug( LDAP_DEBUG_ANY,
1435                                 "%s: line %d: \"idassert-bind\" "
1436                                 "must appear inside a target specification.\n",
1437                                 fname, lineno, 0 );
1438                         return 1;
1439                 }
1440
1441                 return mi->mi_ldap_extra->idassert_parse_cf( fname, lineno, argc, argv, &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert );
1442
1443         /* idassert-authzFrom */
1444         } else if ( strcasecmp( argv[ 0 ], "idassert-authzFrom" ) == 0 ) {
1445                 if ( mi->mi_ntargets == 0 ) {
1446                         Debug( LDAP_DEBUG_ANY,
1447                                 "%s: line %d: \"idassert-bind\" "
1448                                 "must appear inside a target specification.\n",
1449                                 fname, lineno, 0 );
1450                         return 1;
1451                 }
1452
1453                 switch ( argc ) {
1454                 case 2:
1455                         break;
1456
1457                 case 1:
1458                         Debug( LDAP_DEBUG_ANY,
1459                                 "%s: line %d: missing <id> in \"idassert-authzFrom <id>\".\n",
1460                                 fname, lineno, 0 );
1461                         return 1;
1462
1463                 default:
1464                         Debug( LDAP_DEBUG_ANY,
1465                                 "%s: line %d: extra cruft after <id> in \"idassert-authzFrom <id>\".\n",
1466                                 fname, lineno, 0 );
1467                         return 1;
1468                 }
1469
1470                 return mi->mi_ldap_extra->idassert_authzfrom_parse_cf( fname, lineno, argv[ 1 ], &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_idassert );
1471
1472         /* quarantine */
1473         } else if ( strcasecmp( argv[ 0 ], "quarantine" ) == 0 ) {
1474                 char                    buf[ SLAP_TEXT_BUFLEN ] = { '\0' };
1475                 slap_retry_info_t       *ri = mi->mi_ntargets ?
1476                                 &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_quarantine
1477                                 : &mi->mi_quarantine;
1478
1479                 if ( ( mi->mi_ntargets == 0 && META_BACK_QUARANTINE( mi ) )
1480                         || ( mi->mi_ntargets > 0 && META_BACK_TGT_QUARANTINE( mi->mi_targets[ mi->mi_ntargets - 1 ] ) ) )
1481                 {
1482                         Debug( LDAP_DEBUG_ANY,
1483                                 "%s: line %d: quarantine already defined.\n",
1484                                 fname, lineno, 0 );
1485                         return 1;
1486                 }
1487
1488                 switch ( argc ) {
1489                 case 2:
1490                         break;
1491
1492                 case 1:
1493                         Debug( LDAP_DEBUG_ANY,
1494                                 "%s: line %d: missing arg in \"quarantine <pattern list>\".\n",
1495                                 fname, lineno, 0 );
1496                         return 1;
1497
1498                 default:
1499                         Debug( LDAP_DEBUG_ANY,
1500                                 "%s: line %d: extra cruft after \"quarantine <pattern list>\".\n",
1501                                 fname, lineno, 0 );
1502                         return 1;
1503                 }
1504
1505                 if ( ri != &mi->mi_quarantine ) {
1506                         ri->ri_interval = NULL;
1507                         ri->ri_num = NULL;
1508                 }
1509
1510                 if ( mi->mi_ntargets > 0 && !META_BACK_QUARANTINE( mi ) ) {
1511                         ldap_pvt_thread_mutex_init( &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_quarantine_mutex );
1512                 }
1513
1514                 if ( mi->mi_ldap_extra->retry_info_parse( argv[ 1 ], ri, buf, sizeof( buf ) ) ) {
1515                         Debug( LDAP_DEBUG_ANY,
1516                                 "%s line %d: %s.\n",
1517                                 fname, lineno, buf );
1518                         return 1;
1519                 }
1520
1521                 if ( mi->mi_ntargets == 0 ) {
1522                         mi->mi_flags |= LDAP_BACK_F_QUARANTINE;
1523
1524                 } else {
1525                         mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_flags |= LDAP_BACK_F_QUARANTINE;
1526                 }
1527
1528 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
1529         /* session tracking request */
1530         } else if ( strcasecmp( argv[ 0 ], "session-tracking-request" ) == 0 ) {
1531                 unsigned        *flagsp = mi->mi_ntargets ?
1532                                 &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_flags
1533                                 : &mi->mi_flags;
1534
1535                 if ( argc != 2 ) {
1536                         Debug( LDAP_DEBUG_ANY,
1537         "%s: line %d: \"session-tracking-request {TRUE|false}\" needs 1 argument.\n",
1538                                 fname, lineno, 0 );
1539                         return( 1 );
1540                 }
1541
1542                 /* this is the default; we add it because the default might change... */
1543                 switch ( check_true_false( argv[ 1 ] ) ) {
1544                 case 1:
1545                         *flagsp |= LDAP_BACK_F_ST_REQUEST;
1546                         break;
1547
1548                 case 0:
1549                         *flagsp &= ~LDAP_BACK_F_ST_REQUEST;
1550                         break;
1551
1552                 default:
1553                         Debug( LDAP_DEBUG_ANY,
1554                 "%s: line %d: \"session-tracking-request {TRUE|false}\": unknown argument \"%s\".\n",
1555                                 fname, lineno, argv[ 1 ] );
1556                         return( 1 );
1557                 }
1558 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
1559         
1560         /* dn massaging */
1561         } else if ( strcasecmp( argv[ 0 ], "suffixmassage" ) == 0 ) {
1562                 BackendDB       *tmp_bd;
1563                 int             i = mi->mi_ntargets - 1, c, rc;
1564                 struct berval   dn, nvnc, pvnc, nrnc, prnc;
1565
1566                 if ( i < 0 ) {
1567                         Debug( LDAP_DEBUG_ANY,
1568         "%s: line %d: need \"uri\" directive first\n",
1569                                 fname, lineno, 0 );
1570                         return 1;
1571                 }
1572                 
1573                 /*
1574                  * syntax:
1575                  * 
1576                  *      suffixmassage <suffix> <massaged suffix>
1577                  *
1578                  * the <suffix> field must be defined as a valid suffix
1579                  * (or suffixAlias?) for the current database;
1580                  * the <massaged suffix> shouldn't have already been
1581                  * defined as a valid suffix or suffixAlias for the 
1582                  * current server
1583                  */
1584                 if ( argc != 3 ) {
1585                         Debug( LDAP_DEBUG_ANY,
1586         "%s: line %d: syntax is \"suffixMassage <suffix> <massaged suffix>\"\n",
1587                                 fname, lineno, 0 );
1588                         return 1;
1589                 }
1590
1591                 ber_str2bv( argv[ 1 ], 0, 0, &dn );
1592                 if ( dnPrettyNormal( NULL, &dn, &pvnc, &nvnc, NULL ) != LDAP_SUCCESS ) {
1593                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1594                                         "suffix \"%s\" is invalid\n",
1595                                         fname, lineno, argv[ 1 ] );
1596                         return 1;
1597                 }
1598
1599                 for ( c = 0; !BER_BVISNULL( &be->be_nsuffix[ c ] ); c++ ) {
1600                         if ( dnIsSuffix( &nvnc, &be->be_nsuffix[ 0 ] ) ) {
1601                                 break;
1602                         }
1603                 }
1604
1605                 if ( BER_BVISNULL( &be->be_nsuffix[ c ] ) ) {
1606                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1607         "<suffix> \"%s\" must be within the database naming context, in "
1608         "\"suffixMassage <suffix> <massaged suffix>\"\n",
1609                                 fname, lineno, pvnc.bv_val );
1610                         free( pvnc.bv_val );
1611                         free( nvnc.bv_val );
1612                         return 1;                                               
1613                 }
1614
1615                 ber_str2bv( argv[ 2 ], 0, 0, &dn );
1616                 if ( dnPrettyNormal( NULL, &dn, &prnc, &nrnc, NULL ) != LDAP_SUCCESS ) {
1617                         Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1618                                 "massaged suffix \"%s\" is invalid\n",
1619                                 fname, lineno, argv[ 2 ] );
1620                         free( pvnc.bv_val );
1621                         free( nvnc.bv_val );
1622                         return 1;
1623                 }
1624         
1625                 tmp_bd = select_backend( &nrnc, 0 );
1626                 if ( tmp_bd != NULL && tmp_bd->be_private == be->be_private ) {
1627                         Debug( LDAP_DEBUG_ANY, 
1628         "%s: line %d: warning: <massaged suffix> \"%s\" resolves to this database, in "
1629         "\"suffixMassage <suffix> <massaged suffix>\"\n",
1630                                 fname, lineno, prnc.bv_val );
1631                 }
1632
1633                 /*
1634                  * The suffix massaging is emulated by means of the
1635                  * rewrite capabilities
1636                  */
1637                 rc = suffix_massage_config( mi->mi_targets[ i ]->mt_rwmap.rwm_rw,
1638                                 &pvnc, &nvnc, &prnc, &nrnc );
1639
1640                 free( pvnc.bv_val );
1641                 free( nvnc.bv_val );
1642                 free( prnc.bv_val );
1643                 free( nrnc.bv_val );
1644
1645                 return rc;
1646                 
1647         /* rewrite stuff ... */
1648         } else if ( strncasecmp( argv[ 0 ], "rewrite", 7 ) == 0 ) {
1649                 int             i = mi->mi_ntargets - 1;
1650
1651                 if ( i < 0 ) {
1652                         Debug( LDAP_DEBUG_ANY, "%s: line %d: \"rewrite\" "
1653                                 "statement outside target definition.\n",
1654                                 fname, lineno, 0 );
1655                         return 1;
1656                 }
1657                 
1658                 return rewrite_parse( mi->mi_targets[ i ]->mt_rwmap.rwm_rw,
1659                                 fname, lineno, argc, argv );
1660
1661         /* objectclass/attribute mapping */
1662         } else if ( strcasecmp( argv[ 0 ], "map" ) == 0 ) {
1663                 int             i = mi->mi_ntargets - 1;
1664
1665                 if ( i < 0 ) {
1666                         Debug( LDAP_DEBUG_ANY,
1667         "%s: line %d: need \"uri\" directive first\n",
1668                                 fname, lineno, 0 );
1669                         return 1;
1670                 }
1671
1672                 return ldap_back_map_config( &mi->mi_targets[ i ]->mt_rwmap.rwm_oc, 
1673                                 &mi->mi_targets[ i ]->mt_rwmap.rwm_at,
1674                                 fname, lineno, argc, argv );
1675
1676         } else if ( strcasecmp( argv[ 0 ], "nretries" ) == 0 ) {
1677                 int             i = mi->mi_ntargets - 1;
1678                 int             nretries = META_RETRY_UNDEFINED;
1679
1680                 if ( argc != 2 ) {
1681                         Debug( LDAP_DEBUG_ANY,
1682         "%s: line %d: need value in \"nretries <value>\"\n",
1683                                 fname, lineno, 0 );
1684                         return 1;
1685                 }
1686
1687                 if ( strcasecmp( argv[ 1 ], "forever" ) == 0 ) {
1688                         nretries = META_RETRY_FOREVER;
1689
1690                 } else if ( strcasecmp( argv[ 1 ], "never" ) == 0 ) {
1691                         nretries = META_RETRY_NEVER;
1692
1693                 } else {
1694                         if ( lutil_atoi( &nretries, argv[ 1 ] ) != 0 ) {
1695                                 Debug( LDAP_DEBUG_ANY,
1696         "%s: line %d: unable to parse value \"%s\" in \"nretries <value>\"\n",
1697                                         fname, lineno, argv[ 1 ] );
1698                                 return 1;
1699                         }
1700                 }
1701
1702                 if ( i < 0 ) {
1703                         mi->mi_nretries = nretries;
1704
1705                 } else {
1706                         mi->mi_targets[ i ]->mt_nretries = nretries;
1707                 }
1708
1709         } else if ( strcasecmp( argv[ 0 ], "protocol-version" ) == 0 ) {
1710                 int     *version = mi->mi_ntargets ?
1711                                 &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_version
1712                                 : &mi->mi_version;
1713
1714                 if ( argc != 2 ) {
1715                         Debug( LDAP_DEBUG_ANY,
1716         "%s: line %d: need value in \"protocol-version <version>\"\n",
1717                                 fname, lineno, 0 );
1718                         return 1;
1719                 }
1720
1721                 if ( lutil_atoi( version, argv[ 1 ] ) != 0 ) {
1722                         Debug( LDAP_DEBUG_ANY,
1723         "%s: line %d: unable to parse version \"%s\" in \"protocol-version <version>\"\n",
1724                                 fname, lineno, argv[ 1 ] );
1725                         return 1;
1726                 }
1727
1728                 if ( *version != 0 && ( *version < LDAP_VERSION_MIN || *version > LDAP_VERSION_MAX ) ) {
1729                         Debug( LDAP_DEBUG_ANY,
1730         "%s: line %d: unsupported version \"%s\" in \"protocol-version <version>\"\n",
1731                                 fname, lineno, argv[ 1 ] );
1732                         return 1;
1733                 }
1734
1735         /* do not return search references */
1736         } else if ( strcasecmp( argv[ 0 ], "norefs" ) == 0 ) {
1737                 unsigned        *flagsp = mi->mi_ntargets ?
1738                                 &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_flags
1739                                 : &mi->mi_flags;
1740
1741                 if ( argc != 2 ) {
1742                         Debug( LDAP_DEBUG_ANY,
1743         "%s: line %d: \"norefs {TRUE|false}\" needs 1 argument.\n",
1744                                 fname, lineno, 0 );
1745                         return( 1 );
1746                 }
1747
1748                 /* this is the default; we add it because the default might change... */
1749                 switch ( check_true_false( argv[ 1 ] ) ) {
1750                 case 1:
1751                         *flagsp |= LDAP_BACK_F_NOREFS;
1752                         break;
1753
1754                 case 0:
1755                         *flagsp &= ~LDAP_BACK_F_NOREFS;
1756                         break;
1757
1758                 default:
1759                         Debug( LDAP_DEBUG_ANY,
1760                 "%s: line %d: \"norefs {TRUE|false}\": unknown argument \"%s\".\n",
1761                                 fname, lineno, argv[ 1 ] );
1762                         return( 1 );
1763                 }
1764
1765         /* do not propagate undefined search filters */
1766         } else if ( strcasecmp( argv[ 0 ], "noundeffilter" ) == 0 ) {
1767                 unsigned        *flagsp = mi->mi_ntargets ?
1768                                 &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_flags
1769                                 : &mi->mi_flags;
1770
1771                 if ( argc != 2 ) {
1772                         Debug( LDAP_DEBUG_ANY,
1773         "%s: line %d: \"noundeffilter {TRUE|false}\" needs 1 argument.\n",
1774                                 fname, lineno, 0 );
1775                         return( 1 );
1776                 }
1777
1778                 /* this is the default; we add it because the default might change... */
1779                 switch ( check_true_false( argv[ 1 ] ) ) {
1780                 case 1:
1781                         *flagsp |= LDAP_BACK_F_NOUNDEFFILTER;
1782                         break;
1783
1784                 case 0:
1785                         *flagsp &= ~LDAP_BACK_F_NOUNDEFFILTER;
1786                         break;
1787
1788                 default:
1789                         Debug( LDAP_DEBUG_ANY,
1790                 "%s: line %d: \"noundeffilter {TRUE|false}\": unknown argument \"%s\".\n",
1791                                 fname, lineno, argv[ 1 ] );
1792                         return( 1 );
1793                 }
1794
1795 #ifdef SLAPD_META_CLIENT_PR
1796         } else if ( strcasecmp( argv[ 0 ], "client-pr" ) == 0 ) {
1797                 int *ps = mi->mi_ntargets ?
1798                                 &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_ps
1799                                 : &mi->mi_ps;
1800
1801                 if ( argc != 2 ) {
1802                         Debug( LDAP_DEBUG_ANY,
1803         "%s: line %d: \"client-pr {accept-unsolicited|disable|<size>}\" needs 1 argument.\n",
1804                                 fname, lineno, 0 );
1805                         return( 1 );
1806                 }
1807
1808                 if ( strcasecmp( argv[ 1 ], "accept-unsolicited" ) == 0 ) {
1809                         *ps = META_CLIENT_PR_ACCEPT_UNSOLICITED;
1810
1811                 } else if ( strcasecmp( argv[ 1 ], "disable" ) == 0 ) {
1812                         *ps = META_CLIENT_PR_DISABLE;
1813
1814                 } else if ( lutil_atoi( ps, argv[ 1 ] ) || *ps < -1 ) {
1815                         Debug( LDAP_DEBUG_ANY,
1816         "%s: line %d: \"client-pr {accept-unsolicited|disable|<size>}\" invalid arg \"%s\".\n",
1817                                 fname, lineno, argv[ 1 ] );
1818                         return( 1 );
1819                 }
1820 #endif /* SLAPD_META_CLIENT_PR */
1821
1822         /* anything else */
1823         } else {
1824                 return SLAP_CONF_UNKNOWN;
1825         }
1826
1827         return 0;
1828 }
1829
1830 int
1831 ldap_back_map_config(
1832                 struct ldapmap  *oc_map,
1833                 struct ldapmap  *at_map,
1834                 const char      *fname,
1835                 int             lineno,
1836                 int             argc,
1837                 char            **argv )
1838 {
1839         struct ldapmap          *map;
1840         struct ldapmapping      *mapping;
1841         char                    *src, *dst;
1842         int                     is_oc = 0;
1843
1844         if ( argc < 3 || argc > 4 ) {
1845                 Debug( LDAP_DEBUG_ANY,
1846         "%s: line %d: syntax is \"map {objectclass | attribute} [<local> | *] {<foreign> | *}\"\n",
1847                         fname, lineno, 0 );
1848                 return 1;
1849         }
1850
1851         if ( strcasecmp( argv[ 1 ], "objectclass" ) == 0 ) {
1852                 map = oc_map;
1853                 is_oc = 1;
1854
1855         } else if ( strcasecmp( argv[ 1 ], "attribute" ) == 0 ) {
1856                 map = at_map;
1857
1858         } else {
1859                 Debug( LDAP_DEBUG_ANY, "%s: line %d: syntax is "
1860                         "\"map {objectclass | attribute} [<local> | *] "
1861                         "{<foreign> | *}\"\n",
1862                         fname, lineno, 0 );
1863                 return 1;
1864         }
1865
1866         if ( !is_oc && map->map == NULL ) {
1867                 /* only init if required */
1868                 ldap_back_map_init( map, &mapping );
1869         }
1870
1871         if ( strcmp( argv[ 2 ], "*" ) == 0 ) {
1872                 if ( argc < 4 || strcmp( argv[ 3 ], "*" ) == 0 ) {
1873                         map->drop_missing = ( argc < 4 );
1874                         goto success_return;
1875                 }
1876                 src = dst = argv[ 3 ];
1877
1878         } else if ( argc < 4 ) {
1879                 src = "";
1880                 dst = argv[ 2 ];
1881
1882         } else {
1883                 src = argv[ 2 ];
1884                 dst = ( strcmp( argv[ 3 ], "*" ) == 0 ? src : argv[ 3 ] );
1885         }
1886
1887         if ( ( map == at_map )
1888                 && ( strcasecmp( src, "objectclass" ) == 0
1889                         || strcasecmp( dst, "objectclass" ) == 0 ) )
1890         {
1891                 Debug( LDAP_DEBUG_ANY,
1892                         "%s: line %d: objectclass attribute cannot be mapped\n",
1893                         fname, lineno, 0 );
1894         }
1895
1896         mapping = (struct ldapmapping *)ch_calloc( 2,
1897                 sizeof(struct ldapmapping) );
1898         if ( mapping == NULL ) {
1899                 Debug( LDAP_DEBUG_ANY,
1900                         "%s: line %d: out of memory\n",
1901                         fname, lineno, 0 );
1902                 return 1;
1903         }
1904         ber_str2bv( src, 0, 1, &mapping[ 0 ].src );
1905         ber_str2bv( dst, 0, 1, &mapping[ 0 ].dst );
1906         mapping[ 1 ].src = mapping[ 0 ].dst;
1907         mapping[ 1 ].dst = mapping[ 0 ].src;
1908
1909         /*
1910          * schema check
1911          */
1912         if ( is_oc ) {
1913                 if ( src[ 0 ] != '\0' ) {
1914                         if ( oc_bvfind( &mapping[ 0 ].src ) == NULL ) {
1915                                 Debug( LDAP_DEBUG_ANY,
1916         "%s: line %d: warning, source objectClass '%s' "
1917         "should be defined in schema\n",
1918                                         fname, lineno, src );
1919
1920                                 /*
1921                                  * FIXME: this should become an err
1922                                  */
1923                                 goto error_return;
1924                         }
1925                 }
1926
1927                 if ( oc_bvfind( &mapping[ 0 ].dst ) == NULL ) {
1928                         Debug( LDAP_DEBUG_ANY,
1929         "%s: line %d: warning, destination objectClass '%s' "
1930         "is not defined in schema\n",
1931                                 fname, lineno, dst );
1932                 }
1933         } else {
1934                 int                     rc;
1935                 const char              *text = NULL;
1936                 AttributeDescription    *ad = NULL;
1937
1938                 if ( src[ 0 ] != '\0' ) {
1939                         rc = slap_bv2ad( &mapping[ 0 ].src, &ad, &text );
1940                         if ( rc != LDAP_SUCCESS ) {
1941                                 Debug( LDAP_DEBUG_ANY,
1942         "%s: line %d: warning, source attributeType '%s' "
1943         "should be defined in schema\n",
1944                                         fname, lineno, src );
1945
1946                                 /*
1947                                  * FIXME: this should become an err
1948                                  */
1949                                 /*
1950                                  * we create a fake "proxied" ad 
1951                                  * and add it here.
1952                                  */
1953
1954                                 rc = slap_bv2undef_ad( &mapping[ 0 ].src,
1955                                                 &ad, &text, SLAP_AD_PROXIED );
1956                                 if ( rc != LDAP_SUCCESS ) {
1957                                         char    buf[ SLAP_TEXT_BUFLEN ];
1958
1959                                         snprintf( buf, sizeof( buf ),
1960                                                 "source attributeType \"%s\": %d (%s)",
1961                                                 src, rc, text ? text : "" );
1962                                         Debug( LDAP_DEBUG_ANY,
1963                                                 "%s: line %d: %s\n",
1964                                                 fname, lineno, buf );
1965                                         goto error_return;
1966                                 }
1967                         }
1968
1969                         ad = NULL;
1970                 }
1971
1972                 rc = slap_bv2ad( &mapping[ 0 ].dst, &ad, &text );
1973                 if ( rc != LDAP_SUCCESS ) {
1974                         Debug( LDAP_DEBUG_ANY,
1975         "%s: line %d: warning, destination attributeType '%s' "
1976         "is not defined in schema\n",
1977                                 fname, lineno, dst );
1978
1979                         /*
1980                          * we create a fake "proxied" ad 
1981                          * and add it here.
1982                          */
1983
1984                         rc = slap_bv2undef_ad( &mapping[ 0 ].dst,
1985                                         &ad, &text, SLAP_AD_PROXIED );
1986                         if ( rc != LDAP_SUCCESS ) {
1987                                 char    buf[ SLAP_TEXT_BUFLEN ];
1988
1989                                 snprintf( buf, sizeof( buf ),
1990                                         "source attributeType \"%s\": %d (%s)\n",
1991                                         dst, rc, text ? text : "" );
1992                                 Debug( LDAP_DEBUG_ANY,
1993                                         "%s: line %d: %s\n",
1994                                         fname, lineno, buf );
1995                                 return 1;
1996                         }
1997                 }
1998         }
1999
2000         if ( (src[ 0 ] != '\0' && avl_find( map->map, (caddr_t)&mapping[ 0 ], mapping_cmp ) != NULL)
2001                         || avl_find( map->remap, (caddr_t)&mapping[ 1 ], mapping_cmp ) != NULL)
2002         {
2003                 Debug( LDAP_DEBUG_ANY,
2004                         "%s: line %d: duplicate mapping found.\n",
2005                         fname, lineno, 0 );
2006                 goto error_return;
2007         }
2008
2009         if ( src[ 0 ] != '\0' ) {
2010                 avl_insert( &map->map, (caddr_t)&mapping[ 0 ],
2011                                         mapping_cmp, mapping_dup );
2012         }
2013         avl_insert( &map->remap, (caddr_t)&mapping[ 1 ],
2014                                 mapping_cmp, mapping_dup );
2015
2016 success_return:;
2017         return 0;
2018
2019 error_return:;
2020         if ( mapping ) {
2021                 ch_free( mapping[ 0 ].src.bv_val );
2022                 ch_free( mapping[ 0 ].dst.bv_val );
2023                 ch_free( mapping );
2024         }
2025
2026         return 1;
2027 }
2028
2029
2030 #ifdef ENABLE_REWRITE
2031 static char *
2032 suffix_massage_regexize( const char *s )
2033 {
2034         char *res, *ptr;
2035         const char *p, *r;
2036         int i;
2037
2038         if ( s[ 0 ] == '\0' ) {
2039                 return ch_strdup( "^(.+)$" );
2040         }
2041
2042         for ( i = 0, p = s; 
2043                         ( r = strchr( p, ',' ) ) != NULL; 
2044                         p = r + 1, i++ )
2045                 ;
2046
2047         res = ch_calloc( sizeof( char ),
2048                         strlen( s )
2049                         + STRLENOF( "((.+),)?" )
2050                         + STRLENOF( "[ ]?" ) * i
2051                         + STRLENOF( "$" ) + 1 );
2052
2053         ptr = lutil_strcopy( res, "((.+),)?" );
2054         for ( i = 0, p = s;
2055                         ( r = strchr( p, ',' ) ) != NULL;
2056                         p = r + 1 , i++ ) {
2057                 ptr = lutil_strncopy( ptr, p, r - p + 1 );
2058                 ptr = lutil_strcopy( ptr, "[ ]?" );
2059
2060                 if ( r[ 1 ] == ' ' ) {
2061                         r++;
2062                 }
2063         }
2064         ptr = lutil_strcopy( ptr, p );
2065         ptr[ 0 ] = '$';
2066         ptr++;
2067         ptr[ 0 ] = '\0';
2068
2069         return res;
2070 }
2071
2072 static char *
2073 suffix_massage_patternize( const char *s, const char *p )
2074 {
2075         ber_len_t       len;
2076         char            *res, *ptr;
2077
2078         len = strlen( p );
2079
2080         if ( s[ 0 ] == '\0' ) {
2081                 len++;
2082         }
2083
2084         res = ch_calloc( sizeof( char ), len + STRLENOF( "%1" ) + 1 );
2085         if ( res == NULL ) {
2086                 return NULL;
2087         }
2088
2089         ptr = lutil_strcopy( res, ( p[ 0 ] == '\0' ? "%2" : "%1" ) );
2090         if ( s[ 0 ] == '\0' ) {
2091                 ptr[ 0 ] = ',';
2092                 ptr++;
2093         }
2094         lutil_strcopy( ptr, p );
2095
2096         return res;
2097 }
2098
2099 int
2100 suffix_massage_config( 
2101                 struct rewrite_info *info,
2102                 struct berval *pvnc,
2103                 struct berval *nvnc,
2104                 struct berval *prnc,
2105                 struct berval *nrnc
2106 )
2107 {
2108         char *rargv[ 5 ];
2109         int line = 0;
2110
2111         rargv[ 0 ] = "rewriteEngine";
2112         rargv[ 1 ] = "on";
2113         rargv[ 2 ] = NULL;
2114         rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
2115
2116         rargv[ 0 ] = "rewriteContext";
2117         rargv[ 1 ] = "default";
2118         rargv[ 2 ] = NULL;
2119         rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
2120
2121         rargv[ 0 ] = "rewriteRule";
2122         rargv[ 1 ] = suffix_massage_regexize( pvnc->bv_val );
2123         rargv[ 2 ] = suffix_massage_patternize( pvnc->bv_val, prnc->bv_val );
2124         rargv[ 3 ] = ":";
2125         rargv[ 4 ] = NULL;
2126         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
2127         ch_free( rargv[ 1 ] );
2128         ch_free( rargv[ 2 ] );
2129
2130         if ( BER_BVISEMPTY( pvnc ) ) {
2131                 rargv[ 0 ] = "rewriteRule";
2132                 rargv[ 1 ] = "^$";
2133                 rargv[ 2 ] = prnc->bv_val;
2134                 rargv[ 3 ] = ":";
2135                 rargv[ 4 ] = NULL;
2136                 rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
2137         }
2138         
2139         rargv[ 0 ] = "rewriteContext";
2140         rargv[ 1 ] = "searchEntryDN";
2141         rargv[ 2 ] = NULL;
2142         rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
2143
2144         rargv[ 0 ] = "rewriteRule";
2145         rargv[ 1 ] = suffix_massage_regexize( prnc->bv_val );
2146         rargv[ 2 ] = suffix_massage_patternize( prnc->bv_val, pvnc->bv_val );
2147         rargv[ 3 ] = ":";
2148         rargv[ 4 ] = NULL;
2149         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
2150         ch_free( rargv[ 1 ] );
2151         ch_free( rargv[ 2 ] );
2152
2153         if ( BER_BVISEMPTY( prnc ) ) {
2154                 rargv[ 0 ] = "rewriteRule";
2155                 rargv[ 1 ] = "^$";
2156                 rargv[ 2 ] = pvnc->bv_val;
2157                 rargv[ 3 ] = ":";
2158                 rargv[ 4 ] = NULL;
2159                 rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
2160         }
2161         
2162         /* backward compatibility */
2163         rargv[ 0 ] = "rewriteContext";
2164         rargv[ 1 ] = "searchResult";
2165         rargv[ 2 ] = "alias";
2166         rargv[ 3 ] = "searchEntryDN";
2167         rargv[ 4 ] = NULL;
2168         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
2169         
2170         rargv[ 0 ] = "rewriteContext";
2171         rargv[ 1 ] = "matchedDN";
2172         rargv[ 2 ] = "alias";
2173         rargv[ 3 ] = "searchEntryDN";
2174         rargv[ 4 ] = NULL;
2175         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
2176
2177         rargv[ 0 ] = "rewriteContext";
2178         rargv[ 1 ] = "searchAttrDN";
2179         rargv[ 2 ] = "alias";
2180         rargv[ 3 ] = "searchEntryDN";
2181         rargv[ 4 ] = NULL;
2182         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
2183
2184         /* NOTE: this corresponds to #undef'ining RWM_REFERRAL_REWRITE;
2185          * see servers/slapd/overlays/rwm.h for details */
2186         rargv[ 0 ] = "rewriteContext";
2187         rargv[ 1 ] = "referralAttrDN";
2188         rargv[ 2 ] = NULL;
2189         rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
2190
2191         rargv[ 0 ] = "rewriteContext";
2192         rargv[ 1 ] = "referralDN";
2193         rargv[ 2 ] = NULL;
2194         rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
2195         
2196         return 0;
2197 }
2198 #endif /* ENABLE_REWRITE */
2199