]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldap/config.c
Happy new year
[openldap] / servers / slapd / back-ldap / config.c
1 /* config.c - ldap backend configuration file routine */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2003-2004 The OpenLDAP Foundation.
6  * Portions Copyright 1999-2003 Howard Chu.
7  * Portions Copyright 2000-2003 Pierangelo Masarati.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted only as authorized by the OpenLDAP
12  * Public License.
13  *
14  * A copy of this license is available in the file LICENSE in the
15  * top-level directory of the distribution or, alternatively, at
16  * <http://www.OpenLDAP.org/license.html>.
17  */
18 /* ACKNOWLEDGEMENTS:
19  * This work was initially developed by the Howard Chu for inclusion
20  * in OpenLDAP Software and subsequently enhanced by Pierangelo
21  * Masarati.
22  */
23
24 #include "portable.h"
25
26 #include <stdio.h>
27
28 #include <ac/string.h>
29 #include <ac/socket.h>
30
31 #include "slap.h"
32 #include "back-ldap.h"
33 #include "lutil.h"
34
35 static SLAP_EXTOP_MAIN_FN ldap_back_exop_whoami;
36
37 int
38 ldap_back_db_config(
39     BackendDB   *be,
40     const char  *fname,
41     int         lineno,
42     int         argc,
43     char        **argv
44 )
45 {
46         struct ldapinfo *li = (struct ldapinfo *) be->be_private;
47
48         if ( li == NULL ) {
49                 fprintf( stderr, "%s: line %d: ldap backend info is null!\n",
50                     fname, lineno );
51                 return( 1 );
52         }
53
54         /* server address to query (depricated, use "uri" directive) */
55         if ( strcasecmp( argv[0], "server" ) == 0 ) {
56                 if (argc != 2) {
57                         fprintf( stderr,
58         "%s: line %d: missing address in \"server <address>\" line\n",
59                             fname, lineno );
60                         return( 1 );
61                 }
62                 if (li->url != NULL)
63                         ch_free(li->url);
64                 li->url = ch_calloc(strlen(argv[1]) + 9, sizeof(char));
65                 if (li->url != NULL) {
66                         strcpy(li->url, "ldap://");
67                         strcat(li->url, argv[1]);
68                         strcat(li->url, "/");
69                 }
70
71         /* URI of server to query (preferred over "server" directive) */
72         } else if ( strcasecmp( argv[0], "uri" ) == 0 ) {
73                 if (argc != 2) {
74                         fprintf( stderr,
75         "%s: line %d: missing address in \"uri <address>\" line\n",
76                             fname, lineno );
77                         return( 1 );
78                 }
79                 if (li->url != NULL)
80                         ch_free(li->url);
81                 li->url = ch_strdup(argv[1]);
82
83         /* name to use for ldap_back_group */
84         } else if ( strcasecmp( argv[0], "binddn" ) == 0 ) {
85                 if (argc != 2) {
86                         fprintf( stderr,
87         "%s: line %d: missing name in \"binddn <name>\" line\n",
88                             fname, lineno );
89                         return( 1 );
90                 }
91                 ber_str2bv( argv[1], 0, 1, &li->binddn );
92
93         /* password to use for ldap_back_group */
94         } else if ( strcasecmp( argv[0], "bindpw" ) == 0 ) {
95                 if (argc != 2) {
96                         fprintf( stderr,
97         "%s: line %d: missing password in \"bindpw <password>\" line\n",
98                             fname, lineno );
99                         return( 1 );
100                 }
101                 ber_str2bv( argv[1], 0, 1, &li->bindpw );
102
103 #ifdef LDAP_BACK_PROXY_AUTHZ
104         /* name to use for proxyAuthz propagation */
105         } else if ( strcasecmp( argv[0], "proxyauthzdn" ) == 0 ) {
106                 if (argc != 2) {
107                         fprintf( stderr,
108         "%s: line %d: missing name in \"proxyauthzdn <name>\" line\n",
109                             fname, lineno );
110                         return( 1 );
111                 }
112                 ber_str2bv( argv[1], 0, 1, &li->proxyauthzdn );
113
114         /* password to use for proxyAuthz propagation */
115         } else if ( strcasecmp( argv[0], "proxyauthzpw" ) == 0 ) {
116                 if (argc != 2) {
117                         fprintf( stderr,
118         "%s: line %d: missing password in \"proxyauthzpw <password>\" line\n",
119                             fname, lineno );
120                         return( 1 );
121                 }
122                 ber_str2bv( argv[1], 0, 1, &li->proxyauthzpw );
123 #endif /* LDAP_BACK_PROXY_AUTHZ */
124
125         /* save bind creds for referral rebinds? */
126         } else if ( strcasecmp( argv[0], "rebind-as-user" ) == 0 ) {
127                 if (argc != 1) {
128                         fprintf( stderr,
129         "%s: line %d: rebind-as-user takes no arguments\n",
130                             fname, lineno );
131                         return( 1 );
132                 }
133                 li->savecred = 1;
134         
135         /* intercept exop_who_am_i? */
136         } else if ( strcasecmp( argv[0], "proxy-whoami" ) == 0 ) {
137                 if (argc != 1) {
138                         fprintf( stderr,
139         "%s: line %d: proxy-whoami takes no arguments\n",
140                             fname, lineno );
141                         return( 1 );
142                 }
143                 load_extop( (struct berval *)&slap_EXOP_WHOAMI,
144                         0, ldap_back_exop_whoami );
145         
146         /* dn massaging */
147         } else if ( strcasecmp( argv[0], "suffixmassage" ) == 0 ) {
148                 BackendDB *tmp_be;
149                 struct berval bvnc, nvnc, pvnc, brnc, nrnc, prnc;
150 #ifdef ENABLE_REWRITE
151                 int rc;
152 #endif /* ENABLE_REWRITE */
153                 
154                 /*
155                  * syntax:
156                  * 
157                  *      suffixmassage <suffix> <massaged suffix>
158                  *
159                  * the <suffix> field must be defined as a valid suffix
160                  * (or suffixAlias?) for the current database;
161                  * the <massaged suffix> shouldn't have already been
162                  * defined as a valid suffix or suffixAlias for the 
163                  * current server
164                  */
165                 if ( argc != 3 ) {
166                         fprintf( stderr, "%s: line %d: syntax is"
167                                        " \"suffixMassage <suffix>"
168                                        " <massaged suffix>\"\n",
169                                 fname, lineno );
170                         return( 1 );
171                 }
172                 
173                 ber_str2bv( argv[1], 0, 0, &bvnc );
174                 if ( dnPrettyNormal( NULL, &bvnc, &pvnc, &nvnc, NULL ) != LDAP_SUCCESS ) {
175                         fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n",
176                                 fname, lineno, bvnc.bv_val );
177                         return( 1 );
178                 }
179                 tmp_be = select_backend( &nvnc, 0, 0 );
180                 if ( tmp_be != NULL && tmp_be != be ) {
181                         fprintf( stderr, "%s: line %d: suffix already in use"
182                                        " by another backend in"
183                                        " \"suffixMassage <suffix>"
184                                        " <massaged suffix>\"\n",
185                                 fname, lineno );
186                         free( nvnc.bv_val );
187                         free( pvnc.bv_val );
188                         return( 1 );
189                 }
190
191                 ber_str2bv( argv[2], 0, 0, &brnc );
192                 if ( dnPrettyNormal( NULL, &brnc, &prnc, &nrnc, NULL ) != LDAP_SUCCESS ) {
193                         fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n",
194                                 fname, lineno, brnc.bv_val );
195                         free( nvnc.bv_val );
196                         free( pvnc.bv_val );
197                         return( 1 );
198                 }
199
200 #if 0
201                 tmp_be = select_backend( &nrnc, 0, 0 );
202                 if ( tmp_be != NULL ) {
203                         fprintf( stderr, "%s: line %d: massaged suffix"
204                                        " already in use by another backend in" 
205                                        " \"suffixMassage <suffix>"
206                                        " <massaged suffix>\"\n",
207                                 fname, lineno );
208                         free( nvnc.bv_val );
209                         free( pvnc.bv_val );
210                         free( nrnc.bv_val );
211                         free( prnc.bv_val );
212                         return( 1 );
213                 }
214 #endif
215
216 #ifdef ENABLE_REWRITE
217                 /*
218                  * The suffix massaging is emulated by means of the
219                  * rewrite capabilities
220                  * FIXME: no extra rewrite capabilities should be added
221                  * to the database
222                  */
223                 rc = suffix_massage_config( li->rwmap.rwm_rw,
224                                 &pvnc, &nvnc, &prnc, &nrnc );
225                 free( nvnc.bv_val );
226                 free( pvnc.bv_val );
227                 free( nrnc.bv_val );
228                 free( prnc.bv_val );
229
230                 return( rc );
231
232 #else /* !ENABLE_REWRITE */
233                 ber_bvarray_add( &li->rwmap.rwm_suffix_massage, &pvnc );
234                 ber_bvarray_add( &li->rwmap.rwm_suffix_massage, &nvnc );
235                 
236                 ber_bvarray_add( &li->rwmap.rwm_suffix_massage, &prnc );
237                 ber_bvarray_add( &li->rwmap.rwm_suffix_massage, &nrnc );
238 #endif /* !ENABLE_REWRITE */
239
240         /* rewrite stuff ... */
241         } else if ( strncasecmp( argv[0], "rewrite", 7 ) == 0 ) {
242 #ifdef ENABLE_REWRITE
243                 return rewrite_parse( li->rwmap.rwm_rw,
244                                 fname, lineno, argc, argv );
245
246 #else /* !ENABLE_REWRITE */
247                 fprintf( stderr, "%s: line %d: rewrite capabilities "
248                                 "are not enabled\n", fname, lineno );
249 #endif /* !ENABLE_REWRITE */
250                 
251         /* objectclass/attribute mapping */
252         } else if ( strcasecmp( argv[0], "map" ) == 0 ) {
253                 return ldap_back_map_config( &li->rwmap.rwm_oc,
254                                 &li->rwmap.rwm_at,
255                                 fname, lineno, argc, argv );
256
257         /* anything else */
258         } else {
259                 return SLAP_CONF_UNKNOWN;
260         }
261         return 0;
262 }
263
264 int
265 ldap_back_map_config(
266                 struct ldapmap  *oc_map,
267                 struct ldapmap  *at_map,
268                 const char      *fname,
269                 int             lineno,
270                 int             argc,
271                 char            **argv )
272 {
273         struct ldapmap          *map;
274         struct ldapmapping      *mapping;
275         char                    *src, *dst;
276         int                     is_oc = 0;
277
278         if ( argc < 3 || argc > 4 ) {
279                 fprintf( stderr,
280         "%s: line %d: syntax is \"map {objectclass | attribute} [<local> | *] {<foreign> | *}\"\n",
281                         fname, lineno );
282                 return 1;
283         }
284
285         if ( strcasecmp( argv[1], "objectclass" ) == 0 ) {
286                 map = oc_map;
287                 is_oc = 1;
288
289         } else if ( strcasecmp( argv[1], "attribute" ) == 0 ) {
290                 map = at_map;
291
292         } else {
293                 fprintf( stderr, "%s: line %d: syntax is "
294                         "\"map {objectclass | attribute} [<local> | *] "
295                         "{<foreign> | *}\"\n",
296                         fname, lineno );
297                 return 1;
298         }
299
300         if ( strcmp( argv[2], "*" ) == 0 ) {
301                 if ( argc < 4 || strcmp( argv[3], "*" ) == 0 ) {
302                         map->drop_missing = ( argc < 4 );
303                         return 0;
304                 }
305                 src = dst = argv[3];
306
307         } else if ( argc < 4 ) {
308                 src = "";
309                 dst = argv[2];
310
311         } else {
312                 src = argv[2];
313                 dst = ( strcmp( argv[3], "*" ) == 0 ? src : argv[3] );
314         }
315
316         if ( ( map == at_map )
317                         && ( strcasecmp( src, "objectclass" ) == 0
318                         || strcasecmp( dst, "objectclass" ) == 0 ) )
319         {
320                 fprintf( stderr,
321                         "%s: line %d: objectclass attribute cannot be mapped\n",
322                         fname, lineno );
323         }
324
325         mapping = (struct ldapmapping *)ch_calloc( 2,
326                 sizeof(struct ldapmapping) );
327         if ( mapping == NULL ) {
328                 fprintf( stderr,
329                         "%s: line %d: out of memory\n",
330                         fname, lineno );
331                 return 1;
332         }
333         ber_str2bv( src, 0, 1, &mapping->src );
334         ber_str2bv( dst, 0, 1, &mapping->dst );
335         mapping[1].src = mapping->dst;
336         mapping[1].dst = mapping->src;
337
338         /*
339          * schema check
340          */
341         if ( is_oc ) {
342                 if ( src[0] != '\0' ) {
343                         if ( oc_bvfind( &mapping->src ) == NULL ) {
344                                 fprintf( stderr,
345         "%s: line %d: warning, source objectClass '%s' "
346         "should be defined in schema\n",
347                                         fname, lineno, src );
348
349                                 /*
350                                  * FIXME: this should become an err
351                                  */
352                         }
353                 }
354
355                 if ( oc_bvfind( &mapping->dst ) == NULL ) {
356                         fprintf( stderr,
357         "%s: line %d: warning, destination objectClass '%s' "
358         "is not defined in schema\n",
359                                 fname, lineno, dst );
360                 }
361         } else {
362                 int                     rc;
363                 const char              *text = NULL;
364                 AttributeDescription    *ad = NULL;
365
366                 if ( src[0] != '\0' ) {
367                         rc = slap_bv2ad( &mapping->src, &ad, &text );
368                         if ( rc != LDAP_SUCCESS ) {
369                                 fprintf( stderr,
370         "%s: line %d: warning, source attributeType '%s' "
371         "should be defined in schema\n",
372                                         fname, lineno, src );
373
374                                 /*
375                                  * FIXME: this should become an err
376                                  */
377                         }
378
379                         ad = NULL;
380                 }
381
382                 rc = slap_bv2ad( &mapping->dst, &ad, &text );
383                 if ( rc != LDAP_SUCCESS ) {
384                         fprintf( stderr,
385         "%s: line %d: warning, destination attributeType '%s' "
386         "is not defined in schema\n",
387                                 fname, lineno, dst );
388                 }
389         }
390
391         if ( (src[0] != '\0' && avl_find( map->map, (caddr_t)mapping, mapping_cmp ) != NULL)
392                         || avl_find( map->remap, (caddr_t)&mapping[1], mapping_cmp ) != NULL)
393         {
394                 fprintf( stderr,
395                         "%s: line %d: duplicate mapping found (ignored)\n",
396                         fname, lineno );
397                 /* FIXME: free stuff */
398                 goto error_return;
399         }
400
401         if ( src[0] != '\0' ) {
402                 avl_insert( &map->map, (caddr_t)mapping,
403                                         mapping_cmp, mapping_dup );
404         }
405         avl_insert( &map->remap, (caddr_t)&mapping[1],
406                                 mapping_cmp, mapping_dup );
407
408         return 0;
409
410 error_return:;
411         if ( mapping ) {
412                 ch_free( mapping->src.bv_val );
413                 ch_free( mapping->dst.bv_val );
414                 ch_free( mapping );
415         }
416
417         return 1;
418 }
419
420 static int
421 ldap_back_exop_whoami(
422         Operation *op,
423         SlapReply *rs )
424 {
425         struct berval *bv = NULL;
426
427         if ( op->oq_extended.rs_reqdata != NULL ) {
428                 /* no request data should be provided */
429                 rs->sr_text = "no request data expected";
430                 return rs->sr_err = LDAP_PROTOCOL_ERROR;
431         }
432
433         rs->sr_err = backend_check_restrictions( op, rs, 
434                         (struct berval *)&slap_EXOP_WHOAMI );
435         if( rs->sr_err != LDAP_SUCCESS ) return rs->sr_err;
436
437         /* if auth'd by back-ldap and request is proxied, forward it */
438         if ( op->o_conn->c_authz_backend && !strcmp(op->o_conn->c_authz_backend->be_type, "ldap" ) && !dn_match(&op->o_ndn, &op->o_conn->c_ndn)) {
439                 struct ldapconn *lc;
440
441                 LDAPControl c, *ctrls[2] = {NULL, NULL};
442                 LDAPMessage *res;
443                 Operation op2 = *op;
444                 ber_int_t msgid;
445
446                 ctrls[0] = &c;
447                 op2.o_ndn = op->o_conn->c_ndn;
448                 lc = ldap_back_getconn(&op2, rs);
449                 if (!lc || !ldap_back_dobind( lc, op, rs )) {
450                         return -1;
451                 }
452                 c.ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
453                 c.ldctl_iscritical = 1;
454                 c.ldctl_value.bv_val = ch_malloc(op->o_ndn.bv_len+4);
455                 c.ldctl_value.bv_len = op->o_ndn.bv_len + 3;
456                 strcpy(c.ldctl_value.bv_val, "dn:");
457                 strcpy(c.ldctl_value.bv_val+3, op->o_ndn.bv_val);
458
459                 rs->sr_err = ldap_whoami(lc->ld, ctrls, NULL, &msgid);
460                 if (rs->sr_err == LDAP_SUCCESS) {
461                         if (ldap_result(lc->ld, msgid, 1, NULL, &res) == -1) {
462                                 ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
463                                         &rs->sr_err);
464                         } else {
465                                 rs->sr_err = ldap_parse_whoami(lc->ld, res, &bv);
466                                 ldap_msgfree(res);
467                         }
468                 }
469                 ch_free(c.ldctl_value.bv_val);
470                 if (rs->sr_err != LDAP_SUCCESS) {
471                         rs->sr_err = ldap_back_map_result(rs);
472                 }
473         } else {
474         /* else just do the same as before */
475                 bv = (struct berval *) ch_malloc( sizeof(struct berval) );
476                 if( op->o_dn.bv_len ) {
477                         bv->bv_len = op->o_dn.bv_len + sizeof("dn:")-1;
478                         bv->bv_val = ch_malloc( bv->bv_len + 1 );
479                         AC_MEMCPY( bv->bv_val, "dn:", sizeof("dn:")-1 );
480                         AC_MEMCPY( &bv->bv_val[sizeof("dn:")-1], op->o_dn.bv_val,
481                                 op->o_dn.bv_len );
482                         bv->bv_val[bv->bv_len] = '\0';
483                 } else {
484                         bv->bv_len = 0;
485                         bv->bv_val = NULL;
486                 }
487         }
488
489         rs->sr_rspdata = bv;
490         return rs->sr_err;
491 }
492
493
494 #ifdef ENABLE_REWRITE
495 static char *
496 suffix_massage_regexize( const char *s )
497 {
498         char *res, *ptr;
499         const char *p, *r;
500         int i;
501
502         for ( i = 0, p = s; 
503                         ( r = strchr( p, ',' ) ) != NULL; 
504                         p = r + 1, i++ )
505                 ;
506
507         res = ch_calloc( sizeof( char ), strlen( s ) + 4 + 4*i + 1 );
508
509         ptr = lutil_strcopy( res, "(.*)" );
510         for ( i = 0, p = s;
511                         ( r = strchr( p, ',' ) ) != NULL;
512                         p = r + 1 , i++ ) {
513                 ptr = lutil_strncopy( ptr, p, r - p + 1 );
514                 ptr = lutil_strcopy( ptr, "[ ]?" );
515
516                 if ( r[ 1 ] == ' ' ) {
517                         r++;
518                 }
519         }
520         lutil_strcopy( ptr, p );
521
522         return res;
523 }
524
525 static char *
526 suffix_massage_patternize( const char *s )
527 {
528         ber_len_t       len;
529         char            *res;
530
531         len = strlen( s );
532
533         res = ch_calloc( sizeof( char ), len + sizeof( "%1" ) );
534         if ( res == NULL ) {
535                 return NULL;
536         }
537
538         strcpy( res, "%1" );
539         strcpy( res + sizeof( "%1" ) - 1, s );
540
541         return res;
542 }
543
544 int
545 suffix_massage_config( 
546                 struct rewrite_info *info,
547                 struct berval *pvnc,
548                 struct berval *nvnc,
549                 struct berval *prnc,
550                 struct berval *nrnc
551 )
552 {
553         char *rargv[ 5 ];
554         int line = 0;
555
556         rargv[ 0 ] = "rewriteEngine";
557         rargv[ 1 ] = "on";
558         rargv[ 2 ] = NULL;
559         rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
560
561         rargv[ 0 ] = "rewriteContext";
562         rargv[ 1 ] = "default";
563         rargv[ 2 ] = NULL;
564         rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
565
566         rargv[ 0 ] = "rewriteRule";
567         rargv[ 1 ] = suffix_massage_regexize( pvnc->bv_val );
568         rargv[ 2 ] = suffix_massage_patternize( prnc->bv_val );
569         rargv[ 3 ] = ":";
570         rargv[ 4 ] = NULL;
571         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
572         ch_free( rargv[ 1 ] );
573         ch_free( rargv[ 2 ] );
574         
575         rargv[ 0 ] = "rewriteContext";
576         rargv[ 1 ] = "searchResult";
577         rargv[ 2 ] = NULL;
578         rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
579         
580         rargv[ 0 ] = "rewriteRule";
581         rargv[ 1 ] = suffix_massage_regexize( prnc->bv_val );
582         rargv[ 2 ] = suffix_massage_patternize( pvnc->bv_val );
583         rargv[ 3 ] = ":";
584         rargv[ 4 ] = NULL;
585         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
586         ch_free( rargv[ 1 ] );
587         ch_free( rargv[ 2 ] );
588
589 #if 0
590         /*
591          * FIXME: this is no longer required since now we map filters
592          * based on the parsed filter structure, so we can deal directly
593          * with attribute types and values.  The rewriteContext 
594          * "searchFilter" now refers to the value of attrbutes
595          * with DN syntax.
596          */
597
598         /*
599          * the filter should be rewritten as
600          * 
601          * rewriteRule
602          *      "(.*)member=([^)]+),o=Foo Bar,[ ]?c=US(.*)"
603          *      "%1member=%2,dc=example,dc=com%3"
604          *
605          * where "o=Foo Bar, c=US" is the virtual naming context,
606          * and "dc=example, dc=com" is the real naming context
607          */
608         rargv[ 0 ] = "rewriteContext";
609         rargv[ 1 ] = "searchFilter";
610         rargv[ 2 ] = NULL;
611         rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
612
613 #if 1 /* rewrite filters */
614         {
615                 /*
616                  * Note: this is far more optimistic than desirable:
617                  * for any AVA value ending with the virtual naming
618                  * context the terminal part will be replaced by the
619                  * real naming context; a better solution would be to
620                  * walk the filter looking for DN-valued attributes,
621                  * and only rewrite those that require rewriting
622                  */
623                 char    vbuf_[BUFSIZ], *vbuf = vbuf_,
624                         rbuf_[BUFSIZ], *rbuf = rbuf_;
625                 int     len;
626
627                 len = snprintf( vbuf, sizeof( vbuf_ ), 
628                                 "(.*)%s\\)(.*)", nvnc->bv_val );
629                 if ( len == -1 ) {
630                         /* 
631                          * traditional behavior: snprintf returns -1 
632                          * if buffer is insufficient
633                          */
634                         return -1;
635
636                 } else if ( len >= (int)sizeof( vbuf_ ) ) {
637                         /* 
638                          * C99: snprintf returns the required size 
639                          */
640                         vbuf = ch_malloc( len + 1 );
641                         len = snprintf( vbuf, len,
642                                         "(.*)%s\\)(.*)", nvnc->bv_val );
643                         assert( len > 0 );
644                 }
645
646                 len = snprintf( rbuf, sizeof( rbuf_ ), "%%1%s)%%2", 
647                                 nrnc->bv_val );
648                 if ( len == -1 ) {
649                         return -1;
650
651                 } else if ( len >= (int)sizeof( rbuf_ ) ) {
652                         rbuf = ch_malloc( len + 1 );
653                         len = snprintf( rbuf, sizeof( rbuf_ ), "%%1%s)%%2", 
654                                         nrnc->bv_val );
655                         assert( len > 0 );
656                 }
657                 
658                 rargv[ 0 ] = "rewriteRule";
659                 rargv[ 1 ] = vbuf;
660                 rargv[ 2 ] = rbuf;
661                 rargv[ 3 ] = ":";
662                 rargv[ 4 ] = NULL;
663                 rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
664
665                 if ( vbuf != vbuf_ ) {
666                         ch_free( vbuf );
667                 }
668
669                 if ( rbuf != rbuf_ ) {
670                         ch_free( rbuf );
671                 }
672         }
673 #endif /* rewrite filters */
674 #endif
675
676 #if 0 /*  "matched" is not normalized */
677         rargv[ 0 ] = "rewriteContext";
678         rargv[ 1 ] = "matchedDn";
679         rargv[ 2 ] = "alias";
680         rargv[ 3 ] = "searchResult";
681         rargv[ 4 ] = NULL;
682         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
683 #else /* normalize "matched" */
684
685         rargv[ 0 ] = "rewriteContext";
686         rargv[ 1 ] = "matchedDN";
687         rargv[ 2 ] = "alias";
688         rargv[ 3 ] = "searchResult";
689         rargv[ 4 ] = NULL;
690         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
691
692         rargv[ 0 ] = "rewriteContext";
693         rargv[ 1 ] = "searchAttrDN";
694         rargv[ 2 ] = "alias";
695         rargv[ 3 ] = "searchResult";
696         rargv[ 4 ] = NULL;
697         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
698
699 #if 0
700         rargv[ 0 ] = "rewriteRule";
701         rargv[ 1 ] = suffix_massage_regexize( prnc->bv_val );
702         rargv[ 2 ] = suffix_massage_patternize( nvnc->bv_val );
703         rargv[ 3 ] = ":";
704         rargv[ 4 ] = NULL;
705         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
706         ch_free( rargv[ 1 ] );
707         ch_free( rargv[ 2 ] );
708 #endif /* 0 */
709 #endif /* normalize "matched" */
710
711         return 0;
712 }
713 #endif /* ENABLE_REWRITE */