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