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