]> git.sur5r.net Git - openldap/blob - servers/slapd/back-meta/config.c
Sync with HEAD
[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-2005 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 #undef ldap_debug       /* silence a warning in ldap-int.h */
34 #include "../../../libraries/libldap/ldap-int.h"
35 #include "back-meta.h"
36
37 static int
38 new_target( 
39         metatarget_t    *mt )
40 {
41         struct ldapmapping      *mapping;
42         char                    *rargv[ 3 ];
43
44         memset( mt, 0, sizeof( metatarget_t ) );
45
46         mt->mt_rwmap.rwm_rw = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
47         if ( mt->mt_rwmap.rwm_rw == NULL ) {
48                 return -1;
49         }
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_back_map_init( &mt->mt_rwmap.rwm_at, &mapping );
68
69         return 0;
70 }
71
72 static int
73 check_true_false( char *str )
74 {
75         if ( strcasecmp( str, "true" ) == 0 || strcasecmp( str, "yes" ) == 0 ) {
76                 return 1;
77         }
78
79         if ( strcasecmp( str, "false" ) == 0 || strcasecmp( str, "no" ) == 0 ) {
80                 return 0;
81         }
82
83         return -1;
84 }
85
86
87 int
88 meta_back_db_config(
89                 BackendDB       *be,
90                 const char      *fname,
91                 int             lineno,
92                 int             argc,
93                 char            **argv
94 )
95 {
96         metainfo_t      *mi = ( metainfo_t * )be->be_private;
97
98         if ( mi == NULL ) {
99                 fprintf( stderr, 
100         "%s: line %d: meta backend info is null!\n",
101                     fname, lineno );
102                 return 1;
103         }
104
105         /* URI of server to query */
106         if ( strcasecmp( argv[ 0 ], "uri" ) == 0 ) {
107                 int             i = mi->mi_ntargets;
108 #if 0
109                 int             j;
110 #endif /* uncomment if uri MUST be a branch of suffix */
111                 LDAPURLDesc     *ludp, *tmpludp;
112                 struct berval   dn;
113                 int             rc;
114                 int             c;
115                 
116                 if ( argc != 2 ) {
117                         fprintf( stderr,
118         "%s: line %d: missing address"
119         " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
120                                 fname, lineno );
121                         return 1;
122                 }
123
124                 if ( be->be_nsuffix == NULL ) {
125                         fprintf( stderr,
126         "%s: line %d: the suffix must be defined before any target.\n",
127                                 fname, lineno );
128                         return 1;
129                 }
130                 
131                 ++mi->mi_ntargets;
132
133                 mi->mi_targets = ( metatarget_t * )ch_realloc( mi->mi_targets, 
134                         sizeof( metatarget_t ) * mi->mi_ntargets );
135                 if ( mi->mi_targets == NULL ) {
136                         fprintf( stderr,
137         "%s: line %d: out of memory while storing server name"
138         " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
139                                 fname, lineno );
140                         return 1;
141                 }
142
143                 if ( new_target( &mi->mi_targets[ i ] ) != 0 ) {
144                         fprintf( stderr,
145         "%s: line %d: unable to init server"
146         " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
147                                 fname, lineno );
148                         return 1;
149                 }
150
151                 mi->mi_targets[ i ].mt_nretries = mi->mi_nretries;
152                 mi->mi_targets[ i ].mt_flags = mi->flags;
153                 mi->mi_targets[ i ].mt_version = mi->mi_version;
154
155                 for ( c = 0; c < META_OP_LAST; c++ ) {
156                         mi->mi_targets[ i ].mt_timeout[ c ] = mi->mi_timeout[ c ];
157                 }
158
159                 /*
160                  * uri MUST be legal!
161                  */
162                 if ( ldap_url_parselist_ext( &ludp, argv[ 1 ], "\t" ) != LDAP_SUCCESS ) {
163                         fprintf( stderr,
164         "%s: line %d: unable to parse URI"
165         " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
166                                 fname, lineno );
167                         return 1;
168                 }
169
170                 /*
171                  * uri MUST have the <dn> part!
172                  */
173                 if ( ludp->lud_dn == NULL ) {
174                         fprintf( stderr,
175         "%s: line %d: missing <naming context> "
176         " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
177                                 fname, lineno );
178                         return 1;
179
180                 } else if ( ludp->lud_dn[ 0 ] == '\0' ) {
181                         int     j = -1;
182
183                         for ( j = 0; !BER_BVISNULL( &be->be_nsuffix[ j ] ); j++ ) {
184                                 if ( BER_BVISEMPTY( &be->be_nsuffix[ j ] ) ) {
185                                         break;
186                                 }
187                         }
188
189                         if ( BER_BVISNULL( &be->be_nsuffix[ j ] ) ) {
190                                 fprintf( stderr,
191                 "%s: line %d: missing <naming context> "
192                 " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
193                                         fname, lineno );
194                                 return 1;
195                         }
196                 }
197
198                 /*
199                  * copies and stores uri and suffix
200                  */
201                 ber_str2bv( ludp->lud_dn, 0, 0, &dn );
202                 rc = dnPrettyNormal( NULL, &dn, &mi->mi_targets[ i ].mt_psuffix,
203                         &mi->mi_targets[ i ].mt_nsuffix, NULL );
204                 if( rc != LDAP_SUCCESS ) {
205                         fprintf( stderr, "%s: line %d: "
206                                         "target '%s' DN is invalid\n",
207                                         fname, lineno, argv[ 1 ] );
208                         return( 1 );
209                 }
210
211                 ludp->lud_dn[ 0 ] = '\0';
212
213                 switch ( ludp->lud_scope ) {
214                 case LDAP_SCOPE_DEFAULT:
215                         mi->mi_targets[ i ].mt_scope = LDAP_SCOPE_SUBTREE;
216                         break;
217
218                 case LDAP_SCOPE_SUBTREE:
219 #ifdef LDAP_SCOPE_SUBORDINATE
220                 case LDAP_SCOPE_SUBORDINATE:
221 #endif /* LDAP_SCOPE_SUBORDINATE */
222                         mi->mi_targets[ i ].mt_scope = ludp->lud_scope;
223                         break;
224
225                 default:
226                         fprintf( stderr, "%s: line %d: "
227                                         "invalid scope for target '%s'\n",
228                                         fname, lineno, argv[ 1 ] );
229                         return( 1 );
230                 }
231
232                 /* check all, to apply the scope check on the first one */
233                 for ( tmpludp = ludp; tmpludp; tmpludp = tmpludp->lud_next ) {
234                         if ( tmpludp->lud_dn != NULL && tmpludp->lud_dn[ 0 ] != '\0' ) {
235                                 fprintf( stderr, "%s: line %d: "
236                                                 "multiple URIs must have "
237                                                 "no DN part\n",
238                                         fname, lineno );
239                                 return( 1 );
240
241                         }
242                 }
243
244                 mi->mi_targets[ i ].mt_uri = ldap_url_list2urls( ludp );
245                 ldap_free_urllist( ludp );
246                 if ( mi->mi_targets[ i ].mt_uri == NULL) {
247                         fprintf( stderr, "%s: line %d: no memory?\n",
248                                         fname, lineno );
249                         return( 1 );
250                 }
251                 
252                 /*
253                  * uri MUST be a branch of suffix!
254                  */
255 #if 0 /* too strict a constraint */
256                 if ( select_backend( &mi->mi_targets[ i ].suffix, 0, 0 ) != be ) {
257                         fprintf( stderr,
258         "%s: line %d: <naming context> of URI does not refer to current backend"
259         " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
260                                 fname, lineno );
261                         return 1;
262                 }
263 #else
264                 /*
265                  * uri MUST be a branch of a suffix!
266                  */
267                 if ( select_backend( &mi->mi_targets[ i ].mt_nsuffix, 0, 0 ) == NULL ) {
268                         fprintf( stderr,
269         "%s: line %d: <naming context> of URI does not resolve to a backend"
270         " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
271                                 fname, lineno );
272                         return 1;
273                 }
274 #endif
275
276         /* default target directive */
277         } else if ( strcasecmp( argv[ 0 ], "default-target" ) == 0 ) {
278                 int             i = mi->mi_ntargets - 1;
279                 
280                 if ( argc == 1 ) {
281                         if ( i < 0 ) {
282                                 fprintf( stderr,
283         "%s: line %d: \"default-target\" alone need be"
284         " inside a \"uri\" directive\n",
285                                         fname, lineno );
286                                 return 1;
287                         }
288                         mi->mi_defaulttarget = i;
289                 } else {
290                         if ( strcasecmp( argv[ 1 ], "none" ) == 0 ) {
291                                 if ( i >= 0 ) {
292                                         fprintf( stderr,
293         "%s: line %d: \"default-target none\""
294         " should go before uri definitions\n",
295                                                 fname, lineno );
296                                 }
297                                 mi->mi_defaulttarget = META_DEFAULT_TARGET_NONE;
298
299                         } else {
300                                 char    *next;
301                                 int     n = strtol( argv[ 1 ], &next, 10 );
302                                 if ( n < 0 || n >= i - 1 ) {
303                                         fprintf( stderr,
304         "%s: line %d: illegal target number %d\n",
305                                                 fname, lineno, n );
306                                         return 1;
307                                 }
308                                 mi->mi_defaulttarget = n;
309                         }
310                 }
311                 
312         /* ttl of dn cache */
313         } else if ( strcasecmp( argv[ 0 ], "dncache-ttl" ) == 0 ) {
314                 if ( argc != 2 ) {
315                         fprintf( stderr,
316         "%s: line %d: missing ttl in \"dncache-ttl <ttl>\" line\n",
317                                 fname, lineno );
318                         return 1;
319                 }
320                 
321                 if ( strcasecmp( argv[ 1 ], "forever" ) == 0 ) {
322                         mi->mi_cache.ttl = META_DNCACHE_FOREVER;
323                 } else if ( strcasecmp( argv[ 1 ], "disabled" ) == 0 ) {
324                         mi->mi_cache.ttl = META_DNCACHE_DISABLED;
325                 } else {
326                         mi->mi_cache.ttl = atol( argv[ 1 ] );
327                 }
328
329         /* network timeout when connecting to ldap servers */
330         } else if ( strcasecmp( argv[ 0 ], "network-timeout" ) == 0 ) {
331                 if ( argc != 2 ) {
332                         fprintf( stderr,
333         "%s: line %d: missing network timeout in \"network-timeout <seconds>\" line\n",
334                                 fname, lineno );
335                         return 1;
336                 }
337                 mi->mi_network_timeout = atol(argv[ 1 ]);
338
339         /* name to use for meta_back_group */
340         } else if ( strcasecmp( argv[ 0 ], "acl-authcDN" ) == 0
341                         || strcasecmp( argv[ 0 ], "binddn" ) == 0 )
342         {
343                 int             i = mi->mi_ntargets - 1;
344                 struct berval   dn;
345
346                 if ( i < 0 ) {
347                         fprintf( stderr,
348         "%s: line %d: need \"uri\" directive first\n",
349                                 fname, lineno );
350                         return 1;
351                 }
352                 
353                 if ( argc != 2 ) {
354                         fprintf( stderr,
355         "%s: line %d: missing name in \"binddn <name>\" line\n",
356                                 fname, lineno );
357                         return 1;
358                 }
359
360                 if ( strcasecmp( argv[ 0 ], "binddn" ) == 0 ) {
361                         fprintf( stderr, "%s: line %d: "
362                                 "\"binddn\" statement is deprecated; "
363                                 "use \"acl-authcDN\" instead\n",
364                                 fname, lineno );
365                         /* FIXME: some day we'll need to throw an error */
366                 }
367
368                 dn.bv_val = argv[ 1 ];
369                 dn.bv_len = strlen( argv[ 1 ] );
370                 if ( dnNormalize( 0, NULL, NULL, &dn, &mi->mi_targets[ i ].mt_binddn,
371                         NULL ) != LDAP_SUCCESS )
372                 {
373                         fprintf( stderr, "%s: line %d: "
374                                         "bind DN '%s' is invalid\n",
375                                         fname, lineno, argv[ 1 ] );
376                         return( 1 );
377                 }
378
379         /* password to use for meta_back_group */
380         } else if ( strcasecmp( argv[ 0 ], "acl-passwd" ) == 0
381                         || strcasecmp( argv[ 0 ], "bindpw" ) == 0 )
382         {
383                 int             i = mi->mi_ntargets - 1;
384
385                 if ( i < 0 ) {
386                         fprintf( stderr,
387         "%s: line %d: need \"uri\" directive first\n",
388                                 fname, lineno );
389                         return 1;
390                 }
391                 
392                 if ( argc != 2 ) {
393                         fprintf( stderr,
394         "%s: line %d: missing password in \"bindpw <password>\" line\n",
395                             fname, lineno );
396                         return 1;
397                 }
398
399                 if ( strcasecmp( argv[ 0 ], "bindpw" ) == 0 ) {
400                         fprintf( stderr, "%s: line %d: "
401                                 "\"bindpw\" statement is deprecated; "
402                                 "use \"acl-passwd\" instead\n",
403                                 fname, lineno );
404                         /* FIXME: some day we'll need to throw an error */
405                 }
406
407                 ber_str2bv( argv[ 1 ], 0L, 1, &mi->mi_targets[ i ].mt_bindpw );
408                 
409         /* save bind creds for referral rebinds? */
410         } else if ( strcasecmp( argv[ 0 ], "rebind-as-user" ) == 0 ) {
411                 if ( argc > 2 ) {
412                         fprintf( stderr,
413         "%s: line %d: \"rebind-as-user {NO|yes}\" takes 1 argument.\n",
414                             fname, lineno );
415                         return( 1 );
416                 }
417
418                 if ( argc == 1 ) {
419                         fprintf( stderr,
420         "%s: line %d: deprecated use of \"rebind-as-user {FALSE|true}\" with no arguments.\n",
421                             fname, lineno );
422                         mi->flags |= LDAP_BACK_F_SAVECRED;
423
424                 } else {
425                         switch ( check_true_false( argv[ 1 ] ) ) {
426                         case 0:
427                                 mi->flags &= ~LDAP_BACK_F_SAVECRED;
428                                 break;
429
430                         case 1:
431                                 mi->flags |= LDAP_BACK_F_SAVECRED;
432                                 break;
433
434                         default:
435                                 fprintf( stderr,
436         "%s: line %d: \"rebind-as-user {FALSE|true}\" unknown argument \"%s\".\n",
437                                     fname, lineno, argv[ 1 ] );
438                                 return 1;
439                         }
440                 }
441
442         } else if ( strcasecmp( argv[ 0 ], "chase-referrals" ) == 0 ) {
443                 unsigned        *flagsp = mi->mi_ntargets ?
444                                 &mi->mi_targets[ mi->mi_ntargets - 1 ].mt_flags
445                                 : &mi->flags;
446
447                 if ( argc != 2 ) {
448                         fprintf( stderr,
449         "%s: line %d: \"chase-referrals {TRUE|false}\" needs 1 argument.\n",
450                                         fname, lineno );
451                         return( 1 );
452                 }
453
454                 /* this is the default; we add it because the default might change... */
455                 switch ( check_true_false( argv[ 1 ] ) ) {
456                 case 1:
457                         *flagsp |= LDAP_BACK_F_CHASE_REFERRALS;
458                         break;
459
460                 case 0:
461                         *flagsp &= ~LDAP_BACK_F_CHASE_REFERRALS;
462                         break;
463
464                 default:
465                         fprintf( stderr,
466                 "%s: line %d: \"chase-referrals {TRUE|false}\": unknown argument \"%s\".\n",
467                                         fname, lineno, argv[ 1 ] );
468                         return( 1 );
469                 }
470         
471         } else if ( strcasecmp( argv[ 0 ], "tls" ) == 0 ) {
472                 unsigned        *flagsp = mi->mi_ntargets ?
473                                 &mi->mi_targets[ mi->mi_ntargets - 1 ].mt_flags
474                                 : &mi->flags;
475
476                 if ( argc != 2 ) {
477                         fprintf( stderr,
478                 "%s: line %d: \"tls <what>\" needs 1 argument.\n",
479                                         fname, lineno );
480                         return( 1 );
481                 }
482
483                 /* start */
484                 if ( strcasecmp( argv[ 1 ], "start" ) == 0 ) {
485                         *flagsp |= ( LDAP_BACK_F_USE_TLS | LDAP_BACK_F_TLS_CRITICAL );
486         
487                 /* try start tls */
488                 } else if ( strcasecmp( argv[ 1 ], "try-start" ) == 0 ) {
489                         *flagsp &= ~LDAP_BACK_F_TLS_CRITICAL;
490                         *flagsp |= LDAP_BACK_F_USE_TLS;
491         
492                 /* propagate start tls */
493                 } else if ( strcasecmp( argv[ 1 ], "propagate" ) == 0 ) {
494                         *flagsp |= ( LDAP_BACK_F_PROPAGATE_TLS | LDAP_BACK_F_TLS_CRITICAL );
495                 
496                 /* try start tls */
497                 } else if ( strcasecmp( argv[ 1 ], "try-propagate" ) == 0 ) {
498                         *flagsp &= ~LDAP_BACK_F_TLS_CRITICAL;
499                         *flagsp |= LDAP_BACK_F_PROPAGATE_TLS;
500
501                 } else {
502                         fprintf( stderr,
503                 "%s: line %d: \"tls <what>\": unknown argument \"%s\".\n",
504                                         fname, lineno, argv[ 1 ] );
505                         return( 1 );
506                 }
507
508         } else if ( strcasecmp( argv[ 0 ], "t-f-support" ) == 0 ) {
509                 unsigned        *flagsp = mi->mi_ntargets ?
510                                 &mi->mi_targets[ mi->mi_ntargets - 1 ].mt_flags
511                                 : &mi->flags;
512
513                 if ( argc != 2 ) {
514                         fprintf( stderr,
515                 "%s: line %d: \"t-f-support {FALSE|true|discover}\" needs 1 argument.\n",
516                                         fname, lineno );
517                         return( 1 );
518                 }
519
520                 switch ( check_true_false( argv[ 1 ] ) ) {
521                 case 0:
522                         *flagsp &= ~(LDAP_BACK_F_SUPPORT_T_F|LDAP_BACK_F_SUPPORT_T_F_DISCOVER);
523                         break;
524
525                 case 1:
526                         *flagsp |= LDAP_BACK_F_SUPPORT_T_F;
527                         break;
528
529                 default:
530                         if ( strcasecmp( argv[ 1 ], "discover" ) == 0 ) {
531                                 *flagsp |= LDAP_BACK_F_SUPPORT_T_F_DISCOVER;
532
533                         } else {
534                                 fprintf( stderr,
535         "%s: line %d: unknown value \"%s\" for \"t-f-support {no|yes|discover}\".\n",
536                                         fname, lineno, argv[ 1 ] );
537                                 return 1;
538                         }
539                         break;
540                 }
541
542         /* onerr? */
543         } else if ( strcasecmp( argv[ 0 ], "onerr" ) == 0 ) {
544                 if ( argc != 2 ) {
545                         fprintf( stderr,
546         "%s: line %d: \"onerr {CONTINUE|stop}\" takes 1 argument\n",
547                             fname, lineno );
548                         return( 1 );
549                 }
550
551                 if ( strcasecmp( argv[ 1 ], "continue" ) == 0 ) {
552                         mi->flags &= ~META_BACK_F_ONERR_STOP;
553
554                 } else if ( strcasecmp( argv[ 1 ], "stop" ) == 0 ) {
555                         mi->flags |= META_BACK_F_ONERR_STOP;
556
557                 } else {
558                         fprintf( stderr,
559         "%s: line %d: \"onerr {CONTINUE|stop}\": invalid arg \"%s\".\n",
560                                 fname, lineno, argv[ 1 ] );
561                         return 1;
562                 }
563
564         /* bind-defer? */
565         } else if ( strcasecmp( argv[ 0 ], "pseudoroot-bind-defer" ) == 0 ) {
566                 if ( argc != 2 ) {
567                         fprintf( stderr,
568         "%s: line %d: \"pseudoroot-bind-defer {FALSE|true}\" takes 1 argument\n",
569                             fname, lineno );
570                         return( 1 );
571                 }
572
573                 switch ( check_true_false( argv[ 1 ] ) ) {
574                 case 0:
575                         mi->flags &= ~META_BACK_F_DEFER_ROOTDN_BIND;
576                         break;
577
578                 case 1:
579                         mi->flags |= META_BACK_F_DEFER_ROOTDN_BIND;
580                         break;
581
582                 default:
583                         fprintf( stderr,
584         "%s: line %d: \"pseudoroot-bind-defer {FALSE|true}\": invalid arg \"%s\".\n",
585                                 fname, lineno, argv[ 1 ] );
586                         return 1;
587                 }
588
589         } else if ( strcasecmp( argv[ 0 ], "timeout" ) == 0 ) {
590                 char    *sep, *next;
591                 time_t  *tv = mi->mi_ntargets ?
592                                 mi->mi_targets[ mi->mi_ntargets - 1 ].mt_timeout
593                                 : mi->mi_timeout;
594                 int     c;
595
596                 if ( argc < 2 ) {
597                         fprintf( stderr,
598         "%s: line %d: \"timeout [{add|delete|modify|modrdn}=]<val> [...]\" takes at least 1 argument\n",
599                             fname, lineno );
600                         return( 1 );
601                 }
602
603                 for ( c = 1; c < argc; c++ ) {
604                         time_t  *t = NULL, val;
605
606                         sep = strchr( argv[ c ], '=' );
607                         if ( sep != NULL ) {
608                                 size_t  len = sep - argv[ c ];
609
610                                 if ( strncasecmp( argv[ c ], "add", len ) == 0 ) {
611                                         t = &tv[ META_OP_ADD ];
612                                 } else if ( strncasecmp( argv[ c ], "delete", len ) == 0 ) {
613                                         t = &tv[ META_OP_DELETE ];
614                                 } else if ( strncasecmp( argv[ c ], "modify", len ) == 0 ) {
615                                         t = &tv[ META_OP_MODIFY ];
616                                 } else if ( strncasecmp( argv[ c ], "modrdn", len ) == 0 ) {
617                                         t = &tv[ META_OP_MODRDN ];
618                                 } else {
619                                         fprintf( stderr,
620                 "%s: line %d: unknown operation \"%s\" for timeout #%d.\n",
621                                                 fname, lineno, argv[ c ], c );
622                                         return 1;
623                                 }
624                                 sep++;
625         
626                         } else {
627                                 sep = argv[ c ];
628                         }
629         
630                         val = strtoul( sep, &next, 10 );
631                         if ( next == sep || next[ 0 ] != '\0' ) {
632                                 fprintf( stderr,
633                 "%s: line %d: unable to parse value \"%s\" for timeout.\n",
634                                         fname, lineno, sep );
635                                 return 1;
636                         }
637                 
638                         if ( t ) {
639                                 *t = val;
640         
641                         } else {
642                                 int     i;
643         
644                                 for ( i = 0; i < META_OP_LAST; i++ ) {
645                                         tv[ i ] = val;
646                                 }
647                         }
648                 }
649         
650         /* name to use as pseudo-root dn */
651         } else if ( strcasecmp( argv[ 0 ], "pseudorootdn" ) == 0 ) {
652                 int             i = mi->mi_ntargets - 1;
653                 struct berval   dn;
654
655                 if ( i < 0 ) {
656                         fprintf( stderr,
657         "%s: line %d: need \"uri\" directive first\n",
658                                 fname, lineno );
659                         return 1;
660                 }
661                 
662                 if ( argc != 2 ) {
663                         fprintf( stderr,
664         "%s: line %d: missing name in \"pseudorootdn <name>\" line\n",
665                                 fname, lineno );
666                         return 1;
667                 }
668
669                 dn.bv_val = argv[ 1 ];
670                 dn.bv_len = strlen( argv[ 1 ] );
671                 if ( dnNormalize( 0, NULL, NULL, &dn,
672                         &mi->mi_targets[ i ].mt_pseudorootdn, NULL ) != LDAP_SUCCESS )
673                 {
674                         fprintf( stderr, "%s: line %d: "
675                                         "pseudoroot DN '%s' is invalid\n",
676                                         fname, lineno, argv[ 1 ] );
677                         return( 1 );
678                 }
679
680         /* password to use as pseudo-root */
681         } else if ( strcasecmp( argv[ 0 ], "pseudorootpw" ) == 0 ) {
682                 int             i = mi->mi_ntargets - 1;
683
684                 if ( i < 0 ) {
685                         fprintf( stderr,
686         "%s: line %d: need \"uri\" directive first\n",
687                                 fname, lineno );
688                         return 1;
689                 }
690                 
691                 if ( argc != 2 ) {
692                         fprintf( stderr,
693         "%s: line %d: missing password in \"pseudorootpw <password>\" line\n",
694                             fname, lineno );
695                         return 1;
696                 }
697                 ber_str2bv( argv[ 1 ], 0L, 1, &mi->mi_targets[ i ].mt_pseudorootpw );
698         
699         /* dn massaging */
700         } else if ( strcasecmp( argv[ 0 ], "suffixmassage" ) == 0 ) {
701                 BackendDB       *tmp_be;
702                 int             i = mi->mi_ntargets - 1, rc;
703                 struct berval   dn, nvnc, pvnc, nrnc, prnc;
704
705                 if ( i < 0 ) {
706                         fprintf( stderr,
707         "%s: line %d: need \"uri\" directive first\n",
708                                 fname, lineno );
709                         return 1;
710                 }
711                 
712                 /*
713                  * syntax:
714                  * 
715                  *      suffixmassage <suffix> <massaged suffix>
716                  *
717                  * the <suffix> field must be defined as a valid suffix
718                  * (or suffixAlias?) for the current database;
719                  * the <massaged suffix> shouldn't have already been
720                  * defined as a valid suffix or suffixAlias for the 
721                  * current server
722                  */
723                 if ( argc != 3 ) {
724                         fprintf( stderr,
725         "%s: line %d: syntax is \"suffixMassage <suffix> <massaged suffix>\"\n",
726                                 fname, lineno );
727                         return 1;
728                 }
729
730                 ber_str2bv( argv[ 1 ], 0, 0, &dn );
731                 if ( dnPrettyNormal( NULL, &dn, &pvnc, &nvnc, NULL ) != LDAP_SUCCESS ) {
732                         fprintf( stderr, "%s: line %d: "
733                                         "suffix '%s' is invalid\n",
734                                         fname, lineno, argv[ 1 ] );
735                         return 1;
736                 }
737                 
738                 tmp_be = select_backend( &nvnc, 0, 0 );
739                 if ( tmp_be != NULL && tmp_be != be ) {
740                         fprintf( stderr, 
741         "%s: line %d: suffix already in use by another backend in"
742         " \"suffixMassage <suffix> <massaged suffix>\"\n",
743                                 fname, lineno );
744                         free( pvnc.bv_val );
745                         free( nvnc.bv_val );
746                         return 1;                                               
747                 }
748
749                 ber_str2bv( argv[ 2 ], 0, 0, &dn );
750                 if ( dnPrettyNormal( NULL, &dn, &prnc, &nrnc, NULL ) != LDAP_SUCCESS ) {
751                         fprintf( stderr, "%s: line %d: "
752                                         "massaged suffix '%s' is invalid\n",
753                                         fname, lineno, argv[ 2 ] );
754                         free( pvnc.bv_val );
755                         free( nvnc.bv_val );
756                         return 1;
757                 }
758         
759 #if 0   
760                 tmp_be = select_backend( &nrnc, 0, 0 );
761                 if ( tmp_be != NULL ) {
762                         fprintf( stderr,
763         "%s: line %d: massaged suffix already in use by another backend in" 
764         " \"suffixMassage <suffix> <massaged suffix>\"\n",
765                                 fname, lineno );
766                         free( pvnc.bv_val );
767                         free( nvnc.bv_val );
768                         free( prnc.bv_val );
769                         free( nrnc.bv_val );
770                         return 1;
771                 }
772 #endif
773                 
774                 /*
775                  * The suffix massaging is emulated by means of the
776                  * rewrite capabilities
777                  * FIXME: no extra rewrite capabilities should be added
778                  * to the database
779                  */
780                 rc = suffix_massage_config( mi->mi_targets[ i ].mt_rwmap.rwm_rw,
781                                 &pvnc, &nvnc, &prnc, &nrnc );
782
783                 free( pvnc.bv_val );
784                 free( nvnc.bv_val );
785                 free( prnc.bv_val );
786                 free( nrnc.bv_val );
787
788                 return rc;
789                 
790         /* rewrite stuff ... */
791         } else if ( strncasecmp( argv[ 0 ], "rewrite", 7 ) == 0 ) {
792                 int             i = mi->mi_ntargets - 1;
793
794                 if ( i < 0 ) {
795                         fprintf( stderr, "%s: line %d: \"rewrite\" "
796                                 "statement outside target definition.\n",
797                                 fname, lineno );
798                         return 1;
799                 }
800                 
801                 return rewrite_parse( mi->mi_targets[ i ].mt_rwmap.rwm_rw,
802                                 fname, lineno, argc, argv );
803
804         /* objectclass/attribute mapping */
805         } else if ( strcasecmp( argv[ 0 ], "map" ) == 0 ) {
806                 int             i = mi->mi_ntargets - 1;
807
808                 if ( i < 0 ) {
809                         fprintf( stderr,
810         "%s: line %d: need \"uri\" directive first\n",
811                                 fname, lineno );
812                         return 1;
813                 }
814
815                 return ldap_back_map_config( &mi->mi_targets[ i ].mt_rwmap.rwm_oc, 
816                                 &mi->mi_targets[ i ].mt_rwmap.rwm_at,
817                                 fname, lineno, argc, argv );
818
819         } else if ( strcasecmp( argv[ 0 ], "nretries" ) == 0 ) {
820                 int             i = mi->mi_ntargets - 1;
821                 int             nretries = META_RETRY_UNDEFINED;
822
823                 if ( argc != 2 ) {
824                         fprintf( stderr,
825         "%s: line %d: need value in \"nretries <value>\"\n",
826                                 fname, lineno );
827                         return 1;
828                 }
829
830                 if ( strcasecmp( argv[ 1 ], "forever" ) == 0 ) {
831                         nretries = META_RETRY_FOREVER;
832
833                 } else if ( strcasecmp( argv[ 1 ], "never" ) == 0 ) {
834                         nretries = META_RETRY_NEVER;
835
836                 } else {
837                         char    *next;
838
839                         nretries = strtol( argv[ 1 ], &next, 10 );
840                         if ( next == argv[ 1 ] || next[ 0 ] != '\0' ) {
841                                 fprintf( stderr,
842         "%s: line %d: unable to parse value \"%s\" in \"nretries <value>\"\n",
843                                         fname, lineno, argv[ 1 ] );
844                                 return 1;
845                         }
846                 }
847
848                 if ( i < 0 ) {
849                         mi->mi_nretries = nretries;
850
851                 } else {
852                         mi->mi_targets[ i ].mt_nretries = nretries;
853                 }
854
855         /* anything else */
856         } else {
857                 return SLAP_CONF_UNKNOWN;
858         }
859         return 0;
860 }
861
862 int
863 ldap_back_map_config(
864                 struct ldapmap  *oc_map,
865                 struct ldapmap  *at_map,
866                 const char      *fname,
867                 int             lineno,
868                 int             argc,
869                 char            **argv )
870 {
871         struct ldapmap          *map;
872         struct ldapmapping      *mapping;
873         char                    *src, *dst;
874         int                     is_oc = 0;
875
876         if ( argc < 3 || argc > 4 ) {
877                 fprintf( stderr,
878         "%s: line %d: syntax is \"map {objectclass | attribute} [<local> | *] {<foreign> | *}\"\n",
879                         fname, lineno );
880                 return 1;
881         }
882
883         if ( strcasecmp( argv[ 1 ], "objectclass" ) == 0 ) {
884                 map = oc_map;
885                 is_oc = 1;
886
887         } else if ( strcasecmp( argv[ 1 ], "attribute" ) == 0 ) {
888                 map = at_map;
889
890         } else {
891                 fprintf( stderr, "%s: line %d: syntax is "
892                         "\"map {objectclass | attribute} [<local> | *] "
893                         "{<foreign> | *}\"\n",
894                         fname, lineno );
895                 return 1;
896         }
897
898         if ( strcmp( argv[ 2 ], "*" ) == 0 ) {
899                 if ( argc < 4 || strcmp( argv[ 3 ], "*" ) == 0 ) {
900                         map->drop_missing = ( argc < 4 );
901                         return 0;
902                 }
903                 src = dst = argv[ 3 ];
904
905         } else if ( argc < 4 ) {
906                 src = "";
907                 dst = argv[ 2 ];
908
909         } else {
910                 src = argv[ 2 ];
911                 dst = ( strcmp( argv[ 3 ], "*" ) == 0 ? src : argv[ 3 ] );
912         }
913
914         if ( ( map == at_map )
915                         && ( strcasecmp( src, "objectclass" ) == 0
916                         || strcasecmp( dst, "objectclass" ) == 0 ) )
917         {
918                 fprintf( stderr,
919                         "%s: line %d: objectclass attribute cannot be mapped\n",
920                         fname, lineno );
921         }
922
923         mapping = (struct ldapmapping *)ch_calloc( 2,
924                 sizeof(struct ldapmapping) );
925         if ( mapping == NULL ) {
926                 fprintf( stderr,
927                         "%s: line %d: out of memory\n",
928                         fname, lineno );
929                 return 1;
930         }
931         ber_str2bv( src, 0, 1, &mapping->src );
932         ber_str2bv( dst, 0, 1, &mapping->dst );
933         mapping[ 1 ].src = mapping->dst;
934         mapping[ 1 ].dst = mapping->src;
935
936         /*
937          * schema check
938          */
939         if ( is_oc ) {
940                 if ( src[ 0 ] != '\0' ) {
941                         if ( oc_bvfind( &mapping->src ) == NULL ) {
942                                 fprintf( stderr,
943         "%s: line %d: warning, source objectClass '%s' "
944         "should be defined in schema\n",
945                                         fname, lineno, src );
946
947                                 /*
948                                  * FIXME: this should become an err
949                                  */
950                                 goto error_return;
951                         }
952                 }
953
954                 if ( oc_bvfind( &mapping->dst ) == NULL ) {
955                         fprintf( stderr,
956         "%s: line %d: warning, destination objectClass '%s' "
957         "is not defined in schema\n",
958                                 fname, lineno, dst );
959                 }
960         } else {
961                 int                     rc;
962                 const char              *text = NULL;
963                 AttributeDescription    *ad = NULL;
964
965                 if ( src[ 0 ] != '\0' ) {
966                         rc = slap_bv2ad( &mapping->src, &ad, &text );
967                         if ( rc != LDAP_SUCCESS ) {
968                                 fprintf( stderr,
969         "%s: line %d: warning, source attributeType '%s' "
970         "should be defined in schema\n",
971                                         fname, lineno, src );
972
973                                 /*
974                                  * FIXME: this should become an err
975                                  */
976                                 /*
977                                  * we create a fake "proxied" ad 
978                                  * and add it here.
979                                  */
980
981                                 rc = slap_bv2undef_ad( &mapping->src,
982                                                 &ad, &text, SLAP_AD_PROXIED );
983                                 if ( rc != LDAP_SUCCESS ) {
984                                         fprintf( stderr,
985         "%s: line %d: source attributeType '%s': %d (%s)\n",
986                                                 fname, lineno, src,
987                                                 rc, text ? text : "" );
988                                         goto error_return;
989                                 }
990                         }
991
992                         ad = NULL;
993                 }
994
995                 rc = slap_bv2ad( &mapping->dst, &ad, &text );
996                 if ( rc != LDAP_SUCCESS ) {
997                         fprintf( stderr,
998         "%s: line %d: warning, destination attributeType '%s' "
999         "is not defined in schema\n",
1000                                 fname, lineno, dst );
1001
1002                         /*
1003                          * we create a fake "proxied" ad 
1004                          * and add it here.
1005                          */
1006
1007                         rc = slap_bv2undef_ad( &mapping->dst,
1008                                         &ad, &text, SLAP_AD_PROXIED );
1009                         if ( rc != LDAP_SUCCESS ) {
1010                                 fprintf( stderr,
1011         "%s: line %d: source attributeType '%s': %d (%s)\n",
1012                                         fname, lineno, dst,
1013                                         rc, text ? text : "" );
1014                                 return 1;
1015                         }
1016                 }
1017         }
1018
1019         if ( (src[ 0 ] != '\0' && avl_find( map->map, (caddr_t)mapping, mapping_cmp ) != NULL)
1020                         || avl_find( map->remap, (caddr_t)&mapping[ 1 ], mapping_cmp ) != NULL)
1021         {
1022                 fprintf( stderr,
1023                         "%s: line %d: duplicate mapping found" SLAPD_CONF_UNKNOWN_IGNORED ".\n",
1024                         fname, lineno );
1025                 goto error_return;
1026         }
1027
1028         if ( src[ 0 ] != '\0' ) {
1029                 avl_insert( &map->map, (caddr_t)mapping,
1030                                         mapping_cmp, mapping_dup );
1031         }
1032         avl_insert( &map->remap, (caddr_t)&mapping[ 1 ],
1033                                 mapping_cmp, mapping_dup );
1034
1035         return 0;
1036
1037 error_return:;
1038         if ( mapping ) {
1039                 ch_free( mapping->src.bv_val );
1040                 ch_free( mapping->dst.bv_val );
1041                 ch_free( mapping );
1042         }
1043
1044         return 1;
1045 }
1046
1047
1048 #ifdef ENABLE_REWRITE
1049 static char *
1050 suffix_massage_regexize( const char *s )
1051 {
1052         char *res, *ptr;
1053         const char *p, *r;
1054         int i;
1055
1056         if ( s[ 0 ] == '\0' ) {
1057                 return ch_strdup( "^(.+)$" );
1058         }
1059
1060         for ( i = 0, p = s; 
1061                         ( r = strchr( p, ',' ) ) != NULL; 
1062                         p = r + 1, i++ )
1063                 ;
1064
1065         res = ch_calloc( sizeof( char ),
1066                         strlen( s )
1067                         + STRLENOF( "((.+),)?" )
1068                         + STRLENOF( "[ ]?" ) * i
1069                         + STRLENOF( "$" ) + 1 );
1070
1071         ptr = lutil_strcopy( res, "((.+),)?" );
1072         for ( i = 0, p = s;
1073                         ( r = strchr( p, ',' ) ) != NULL;
1074                         p = r + 1 , i++ ) {
1075                 ptr = lutil_strncopy( ptr, p, r - p + 1 );
1076                 ptr = lutil_strcopy( ptr, "[ ]?" );
1077
1078                 if ( r[ 1 ] == ' ' ) {
1079                         r++;
1080                 }
1081         }
1082         ptr = lutil_strcopy( ptr, p );
1083         ptr[ 0 ] = '$';
1084         ptr++;
1085         ptr[ 0 ] = '\0';
1086
1087         return res;
1088 }
1089
1090 static char *
1091 suffix_massage_patternize( const char *s, const char *p )
1092 {
1093         ber_len_t       len;
1094         char            *res, *ptr;
1095
1096         len = strlen( p );
1097
1098         if ( s[ 0 ] == '\0' ) {
1099                 len++;
1100         }
1101
1102         res = ch_calloc( sizeof( char ), len + STRLENOF( "%1" ) + 1 );
1103         if ( res == NULL ) {
1104                 return NULL;
1105         }
1106
1107         ptr = lutil_strcopy( res, ( p[ 0 ] == '\0' ? "%2" : "%1" ) );
1108         if ( s[ 0 ] == '\0' ) {
1109                 ptr[ 0 ] = ',';
1110                 ptr++;
1111         }
1112         lutil_strcopy( ptr, p );
1113
1114         return res;
1115 }
1116
1117 int
1118 suffix_massage_config( 
1119                 struct rewrite_info *info,
1120                 struct berval *pvnc,
1121                 struct berval *nvnc,
1122                 struct berval *prnc,
1123                 struct berval *nrnc
1124 )
1125 {
1126         char *rargv[ 5 ];
1127         int line = 0;
1128
1129         rargv[ 0 ] = "rewriteEngine";
1130         rargv[ 1 ] = "on";
1131         rargv[ 2 ] = NULL;
1132         rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
1133
1134         rargv[ 0 ] = "rewriteContext";
1135         rargv[ 1 ] = "default";
1136         rargv[ 2 ] = NULL;
1137         rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
1138
1139         rargv[ 0 ] = "rewriteRule";
1140         rargv[ 1 ] = suffix_massage_regexize( pvnc->bv_val );
1141         rargv[ 2 ] = suffix_massage_patternize( pvnc->bv_val, prnc->bv_val );
1142         rargv[ 3 ] = ":";
1143         rargv[ 4 ] = NULL;
1144         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
1145         ch_free( rargv[ 1 ] );
1146         ch_free( rargv[ 2 ] );
1147
1148         if ( BER_BVISEMPTY( pvnc ) ) {
1149                 rargv[ 0 ] = "rewriteRule";
1150                 rargv[ 1 ] = "^$";
1151                 rargv[ 2 ] = prnc->bv_val;
1152                 rargv[ 3 ] = ":";
1153                 rargv[ 4 ] = NULL;
1154                 rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
1155         }
1156         
1157         rargv[ 0 ] = "rewriteContext";
1158         rargv[ 1 ] = "searchEntryDN";
1159         rargv[ 2 ] = NULL;
1160         rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
1161
1162         rargv[ 0 ] = "rewriteRule";
1163         rargv[ 1 ] = suffix_massage_regexize( prnc->bv_val );
1164         rargv[ 2 ] = suffix_massage_patternize( prnc->bv_val, pvnc->bv_val );
1165         rargv[ 3 ] = ":";
1166         rargv[ 4 ] = NULL;
1167         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
1168         ch_free( rargv[ 1 ] );
1169         ch_free( rargv[ 2 ] );
1170
1171         if ( BER_BVISEMPTY( prnc ) ) {
1172                 rargv[ 0 ] = "rewriteRule";
1173                 rargv[ 1 ] = "^$";
1174                 rargv[ 2 ] = pvnc->bv_val;
1175                 rargv[ 3 ] = ":";
1176                 rargv[ 4 ] = NULL;
1177                 rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
1178         }
1179         
1180         /* backward compatibility */
1181         rargv[ 0 ] = "rewriteContext";
1182         rargv[ 1 ] = "searchResult";
1183         rargv[ 2 ] = "alias";
1184         rargv[ 3 ] = "searchEntryDN";
1185         rargv[ 4 ] = NULL;
1186         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
1187         
1188         rargv[ 0 ] = "rewriteContext";
1189         rargv[ 1 ] = "matchedDN";
1190         rargv[ 2 ] = "alias";
1191         rargv[ 3 ] = "searchEntryDN";
1192         rargv[ 4 ] = NULL;
1193         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
1194
1195         rargv[ 0 ] = "rewriteContext";
1196         rargv[ 1 ] = "searchAttrDN";
1197         rargv[ 2 ] = "alias";
1198         rargv[ 3 ] = "searchEntryDN";
1199         rargv[ 4 ] = NULL;
1200         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
1201
1202         /* NOTE: this corresponds to #undef'ining RWM_REFERRAL_REWRITE;
1203          * see servers/slapd/overlays/rwm.h for details */
1204         rargv[ 0 ] = "rewriteContext";
1205         rargv[ 1 ] = "referralAttrDN";
1206         rargv[ 2 ] = NULL;
1207         rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
1208
1209         rargv[ 0 ] = "rewriteContext";
1210         rargv[ 1 ] = "referralDN";
1211         rargv[ 2 ] = NULL;
1212         rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
1213         
1214         return 0;
1215 }
1216 #endif /* ENABLE_REWRITE */
1217