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