]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldap/config.c
081c45d9e4dd1a4d3b4aa239cc6239047264c243
[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-2005 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 #undef ldap_debug
35 /* for advanced URL parsing */
36 #include "../../../libraries/libldap/ldap-int.h"
37
38 static SLAP_EXTOP_MAIN_FN ldap_back_exop_whoami;
39
40 int
41 ldap_back_db_config(
42     BackendDB   *be,
43     const char  *fname,
44     int         lineno,
45     int         argc,
46     char        **argv
47 )
48 {
49         struct ldapinfo *li = (struct ldapinfo *) be->be_private;
50
51         if ( li == NULL ) {
52                 fprintf( stderr, "%s: line %d: ldap backend info is null!\n",
53                     fname, lineno );
54                 return( 1 );
55         }
56
57         /* server address to query (depricated, use "uri" directive) */
58         if ( strcasecmp( argv[0], "server" ) == 0 ) {
59                 if (argc != 2) {
60                         fprintf( stderr,
61         "%s: line %d: missing address in \"server <address>\" line\n",
62                             fname, lineno );
63                         return( 1 );
64                 }
65                 if (li->url != NULL)
66                         ch_free(li->url);
67                 li->url = ch_calloc(strlen(argv[1]) + 9, sizeof(char));
68                 if (li->url != NULL) {
69                         strcpy(li->url, "ldap://");
70                         strcat(li->url, argv[1]);
71                         strcat(li->url, "/");
72                 }
73
74         /* URI of server to query (preferred over "server" directive) */
75         } else if ( strcasecmp( argv[0], "uri" ) == 0 ) {
76                 LDAPURLDesc     *tmpludp;
77                 int             urlrc, i;
78
79                 if (argc != 2) {
80                         fprintf( stderr, "%s: line %d: "
81                                 "missing uri "
82                                 "in \"uri <uri>\" line\n",
83                                 fname, lineno );
84                         return( 1 );
85                 }
86                 if ( li->url != NULL ) {
87                         ch_free( li->url );
88                 }
89                 if ( li->lud != NULL ) {
90                         ldap_free_urldesc( li->lud );
91                 }
92
93                 urlrc = ldap_url_parselist( &li->lud, argv[ 1 ] );
94                 if ( urlrc != LDAP_URL_SUCCESS ) {
95                         char    *why;
96
97                         switch ( urlrc ) {
98                         case LDAP_URL_ERR_MEM:
99                                 why = "no memory";
100                                 break;
101                         case LDAP_URL_ERR_PARAM:
102                                 why = "parameter is bad";
103                                 break;
104                         case LDAP_URL_ERR_BADSCHEME:
105                                 why = "URL doesn't begin with \"[c]ldap[si]://\"";
106                                 break;
107                         case LDAP_URL_ERR_BADENCLOSURE:
108                                 why = "URL is missing trailing \">\"";
109                                 break;
110                         case LDAP_URL_ERR_BADURL:
111                                 why = "URL is bad";
112                         case LDAP_URL_ERR_BADHOST:
113                                 why = "host/port is bad";
114                                 break;
115                         case LDAP_URL_ERR_BADATTRS:
116                                 why = "bad (or missing) attributes";
117                                 break;
118                         case LDAP_URL_ERR_BADSCOPE:
119                                 why = "scope string is invalid (or missing)";
120                                 break;
121                         case LDAP_URL_ERR_BADFILTER:
122                                 why = "bad or missing filter";
123                                 break;
124                         case LDAP_URL_ERR_BADEXTS:
125                                 why = "bad or missing extensions";
126                                 break;
127                         default:
128                                 why = "unknown reason";
129                                 break;
130                         }
131                         fprintf( stderr, "%s: line %d: "
132                                         "unable to parse uri \"%s\" "
133                                         "in \"uri <uri>\" line: %s\n",
134                                         fname, lineno, argv[ 1 ], why );
135                         return 1;
136                 }
137
138                 for ( i = 0, tmpludp = li->lud;
139                                 tmpludp;
140                                 i++, tmpludp = tmpludp->lud_next )
141                 {
142                         if ( ( tmpludp->lud_dn != NULL
143                                                 && tmpludp->lud_dn[0] != '\0' )
144                                         || tmpludp->lud_attrs != NULL
145                                         || tmpludp->lud_filter != NULL
146                                         || tmpludp->lud_exts != NULL )
147                         {
148                                 fprintf( stderr, "%s: line %d: "
149                                                 "warning, only protocol, "
150                                                 "host and port allowed "
151                                                 "in \"uri <uri>\" statement "
152                                                 "for uri #%d of \"%s\"\n",
153                                                 fname, lineno, i, argv[1] );
154                         }
155                 }
156
157                 li->url = ch_strdup( argv[ 1 ] );
158
159         /* name to use for ldap_back_group */
160         } else if ( strcasecmp( argv[0], "binddn" ) == 0 ) {
161                 if (argc != 2) {
162                         fprintf( stderr,
163         "%s: line %d: missing name in \"binddn <name>\" line\n",
164                             fname, lineno );
165                         return( 1 );
166                 }
167                 ber_str2bv( argv[1], 0, 1, &li->binddn );
168
169         /* password to use for ldap_back_group */
170         } else if ( strcasecmp( argv[0], "bindpw" ) == 0 ) {
171                 if (argc != 2) {
172                         fprintf( stderr,
173         "%s: line %d: missing password in \"bindpw <password>\" line\n",
174                             fname, lineno );
175                         return( 1 );
176                 }
177                 ber_str2bv( argv[1], 0, 1, &li->bindpw );
178
179 #ifdef LDAP_BACK_PROXY_AUTHZ
180         /* name to use for proxyAuthz propagation */
181         } else if ( strcasecmp( argv[0], "proxyauthzdn" ) == 0 ) {
182                 if (argc != 2) {
183                         fprintf( stderr,
184         "%s: line %d: missing name in \"proxyauthzdn <name>\" line\n",
185                             fname, lineno );
186                         return( 1 );
187                 }
188                 ber_str2bv( argv[1], 0, 1, &li->proxyauthzdn );
189
190         /* password to use for proxyAuthz propagation */
191         } else if ( strcasecmp( argv[0], "proxyauthzpw" ) == 0 ) {
192                 if (argc != 2) {
193                         fprintf( stderr,
194         "%s: line %d: missing password in \"proxyauthzpw <password>\" line\n",
195                             fname, lineno );
196                         return( 1 );
197                 }
198                 ber_str2bv( argv[1], 0, 1, &li->proxyauthzpw );
199 #endif /* LDAP_BACK_PROXY_AUTHZ */
200
201         /* save bind creds for referral rebinds? */
202         } else if ( strcasecmp( argv[0], "rebind-as-user" ) == 0 ) {
203                 if (argc != 1) {
204                         fprintf( stderr,
205         "%s: line %d: rebind-as-user takes no arguments\n",
206                             fname, lineno );
207                         return( 1 );
208                 }
209                 li->savecred = 1;
210         
211         /* intercept exop_who_am_i? */
212         } else if ( strcasecmp( argv[0], "proxy-whoami" ) == 0 ) {
213                 if (argc != 1) {
214                         fprintf( stderr,
215         "%s: line %d: proxy-whoami takes no arguments\n",
216                             fname, lineno );
217                         return( 1 );
218                 }
219                 load_extop( (struct berval *)&slap_EXOP_WHOAMI,
220                         0, ldap_back_exop_whoami );
221         
222         /* dn massaging */
223         } else if ( strcasecmp( argv[0], "suffixmassage" ) == 0 ) {
224                 BackendDB *tmp_be;
225                 struct berval bvnc, nvnc, pvnc, brnc, nrnc, prnc;
226 #ifdef ENABLE_REWRITE
227                 int rc;
228 #endif /* ENABLE_REWRITE */
229                 
230                 /*
231                  * syntax:
232                  * 
233                  *      suffixmassage <suffix> <massaged suffix>
234                  *
235                  * the <suffix> field must be defined as a valid suffix
236                  * (or suffixAlias?) for the current database;
237                  * the <massaged suffix> shouldn't have already been
238                  * defined as a valid suffix or suffixAlias for the 
239                  * current server
240                  */
241                 if ( argc != 3 ) {
242                         fprintf( stderr, "%s: line %d: syntax is"
243                                        " \"suffixMassage <suffix>"
244                                        " <massaged suffix>\"\n",
245                                 fname, lineno );
246                         return( 1 );
247                 }
248                 
249                 ber_str2bv( argv[1], 0, 0, &bvnc );
250                 if ( dnPrettyNormal( NULL, &bvnc, &pvnc, &nvnc, NULL ) != LDAP_SUCCESS ) {
251                         fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n",
252                                 fname, lineno, bvnc.bv_val );
253                         return( 1 );
254                 }
255                 tmp_be = select_backend( &nvnc, 0, 0 );
256                 if ( tmp_be != NULL && tmp_be != be ) {
257                         fprintf( stderr, "%s: line %d: suffix already in use"
258                                        " by another backend in"
259                                        " \"suffixMassage <suffix>"
260                                        " <massaged suffix>\"\n",
261                                 fname, lineno );
262                         free( nvnc.bv_val );
263                         free( pvnc.bv_val );
264                         return( 1 );
265                 }
266
267                 ber_str2bv( argv[2], 0, 0, &brnc );
268                 if ( dnPrettyNormal( NULL, &brnc, &prnc, &nrnc, NULL ) != LDAP_SUCCESS ) {
269                         fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n",
270                                 fname, lineno, brnc.bv_val );
271                         free( nvnc.bv_val );
272                         free( pvnc.bv_val );
273                         return( 1 );
274                 }
275
276 #if 0
277                 tmp_be = select_backend( &nrnc, 0, 0 );
278                 if ( tmp_be != NULL ) {
279                         fprintf( stderr, "%s: line %d: massaged suffix"
280                                        " already in use by another backend in" 
281                                        " \"suffixMassage <suffix>"
282                                        " <massaged suffix>\"\n",
283                                 fname, lineno );
284                         free( nvnc.bv_val );
285                         free( pvnc.bv_val );
286                         free( nrnc.bv_val );
287                         free( prnc.bv_val );
288                         return( 1 );
289                 }
290 #endif
291
292 #ifdef ENABLE_REWRITE
293                 /*
294                  * The suffix massaging is emulated by means of the
295                  * rewrite capabilities
296                  * FIXME: no extra rewrite capabilities should be added
297                  * to the database
298                  */
299                 rc = suffix_massage_config( li->rwmap.rwm_rw,
300                                 &pvnc, &nvnc, &prnc, &nrnc );
301                 free( nvnc.bv_val );
302                 free( pvnc.bv_val );
303                 free( nrnc.bv_val );
304                 free( prnc.bv_val );
305
306                 return( rc );
307
308 #else /* !ENABLE_REWRITE */
309                 ber_bvarray_add( &li->rwmap.rwm_suffix_massage, &pvnc );
310                 ber_bvarray_add( &li->rwmap.rwm_suffix_massage, &nvnc );
311                 
312                 ber_bvarray_add( &li->rwmap.rwm_suffix_massage, &prnc );
313                 ber_bvarray_add( &li->rwmap.rwm_suffix_massage, &nrnc );
314 #endif /* !ENABLE_REWRITE */
315
316         /* rewrite stuff ... */
317         } else if ( strncasecmp( argv[0], "rewrite", 7 ) == 0 ) {
318 #ifdef ENABLE_REWRITE
319                 return rewrite_parse( li->rwmap.rwm_rw,
320                                 fname, lineno, argc, argv );
321
322 #else /* !ENABLE_REWRITE */
323                 fprintf( stderr, "%s: line %d: rewrite capabilities "
324                                 "are not enabled\n", fname, lineno );
325 #endif /* !ENABLE_REWRITE */
326                 
327         /* objectclass/attribute mapping */
328         } else if ( strcasecmp( argv[0], "map" ) == 0 ) {
329                 return ldap_back_map_config( &li->rwmap.rwm_oc,
330                                 &li->rwmap.rwm_at,
331                                 fname, lineno, argc, argv );
332
333         /* anything else */
334         } else {
335                 return SLAP_CONF_UNKNOWN;
336         }
337         return 0;
338 }
339
340 int
341 ldap_back_map_config(
342                 struct ldapmap  *oc_map,
343                 struct ldapmap  *at_map,
344                 const char      *fname,
345                 int             lineno,
346                 int             argc,
347                 char            **argv )
348 {
349         struct ldapmap          *map;
350         struct ldapmapping      *mapping;
351         char                    *src, *dst;
352         int                     is_oc = 0;
353
354         if ( argc < 3 || argc > 4 ) {
355                 fprintf( stderr,
356         "%s: line %d: syntax is \"map {objectclass | attribute} [<local> | *] {<foreign> | *}\"\n",
357                         fname, lineno );
358                 return 1;
359         }
360
361         if ( strcasecmp( argv[1], "objectclass" ) == 0 ) {
362                 map = oc_map;
363                 is_oc = 1;
364
365         } else if ( strcasecmp( argv[1], "attribute" ) == 0 ) {
366                 map = at_map;
367
368         } else {
369                 fprintf( stderr, "%s: line %d: syntax is "
370                         "\"map {objectclass | attribute} [<local> | *] "
371                         "{<foreign> | *}\"\n",
372                         fname, lineno );
373                 return 1;
374         }
375
376         if ( strcmp( argv[2], "*" ) == 0 ) {
377                 if ( argc < 4 || strcmp( argv[3], "*" ) == 0 ) {
378                         map->drop_missing = ( argc < 4 );
379                         return 0;
380                 }
381                 src = dst = argv[3];
382
383         } else if ( argc < 4 ) {
384                 src = "";
385                 dst = argv[2];
386
387         } else {
388                 src = argv[2];
389                 dst = ( strcmp( argv[3], "*" ) == 0 ? src : argv[3] );
390         }
391
392         if ( ( map == at_map )
393                         && ( strcasecmp( src, "objectclass" ) == 0
394                         || strcasecmp( dst, "objectclass" ) == 0 ) )
395         {
396                 fprintf( stderr,
397                         "%s: line %d: objectclass attribute cannot be mapped\n",
398                         fname, lineno );
399         }
400
401         mapping = (struct ldapmapping *)ch_calloc( 2,
402                 sizeof(struct ldapmapping) );
403         if ( mapping == NULL ) {
404                 fprintf( stderr,
405                         "%s: line %d: out of memory\n",
406                         fname, lineno );
407                 return 1;
408         }
409         ber_str2bv( src, 0, 1, &mapping->src );
410         ber_str2bv( dst, 0, 1, &mapping->dst );
411         mapping[1].src = mapping->dst;
412         mapping[1].dst = mapping->src;
413
414         /*
415          * schema check
416          */
417         if ( is_oc ) {
418                 if ( src[0] != '\0' ) {
419                         if ( oc_bvfind( &mapping->src ) == NULL ) {
420                                 fprintf( stderr,
421         "%s: line %d: warning, source objectClass '%s' "
422         "should be defined in schema\n",
423                                         fname, lineno, src );
424
425                                 /*
426                                  * FIXME: this should become an err
427                                  */
428                                 goto error_return;
429                         }
430                 }
431
432                 if ( oc_bvfind( &mapping->dst ) == NULL ) {
433                         fprintf( stderr,
434         "%s: line %d: warning, destination objectClass '%s' "
435         "is not defined in schema\n",
436                                 fname, lineno, dst );
437                 }
438         } else {
439                 int                     rc;
440                 const char              *text = NULL;
441                 AttributeDescription    *ad = NULL;
442
443                 if ( src[0] != '\0' ) {
444                         rc = slap_bv2ad( &mapping->src, &ad, &text );
445                         if ( rc != LDAP_SUCCESS ) {
446                                 fprintf( stderr,
447         "%s: line %d: warning, source attributeType '%s' "
448         "should be defined in schema\n",
449                                         fname, lineno, src );
450
451                                 /*
452                                  * FIXME: this should become an err
453                                  */
454                                 goto error_return;
455                         }
456
457                         ad = NULL;
458                 }
459
460                 rc = slap_bv2ad( &mapping->dst, &ad, &text );
461                 if ( rc != LDAP_SUCCESS ) {
462                         fprintf( stderr,
463         "%s: line %d: warning, destination attributeType '%s' "
464         "is not defined in schema\n",
465                                 fname, lineno, dst );
466                 }
467         }
468
469         if ( (src[0] != '\0' && avl_find( map->map, (caddr_t)mapping, mapping_cmp ) != NULL)
470                         || avl_find( map->remap, (caddr_t)&mapping[1], mapping_cmp ) != NULL)
471         {
472                 fprintf( stderr,
473                         "%s: line %d: duplicate mapping found (ignored)\n",
474                         fname, lineno );
475                 goto error_return;
476         }
477
478         if ( src[0] != '\0' ) {
479                 avl_insert( &map->map, (caddr_t)mapping,
480                                         mapping_cmp, mapping_dup );
481         }
482         avl_insert( &map->remap, (caddr_t)&mapping[1],
483                                 mapping_cmp, mapping_dup );
484
485         return 0;
486
487 error_return:;
488         if ( mapping ) {
489                 ch_free( mapping->src.bv_val );
490                 ch_free( mapping->dst.bv_val );
491                 ch_free( mapping );
492         }
493
494         return 1;
495 }
496
497 static int
498 ldap_back_exop_whoami(
499         Operation *op,
500         SlapReply *rs )
501 {
502         struct berval *bv = NULL;
503
504         if ( op->oq_extended.rs_reqdata != NULL ) {
505                 /* no request data should be provided */
506                 rs->sr_text = "no request data expected";
507                 return rs->sr_err = LDAP_PROTOCOL_ERROR;
508         }
509
510         rs->sr_err = backend_check_restrictions( op, rs, 
511                         (struct berval *)&slap_EXOP_WHOAMI );
512         if( rs->sr_err != LDAP_SUCCESS ) return rs->sr_err;
513
514         /* if auth'd by back-ldap and request is proxied, forward it */
515         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)) {
516                 struct ldapconn *lc;
517
518                 LDAPControl c, *ctrls[2] = {NULL, NULL};
519                 LDAPMessage *res;
520                 Operation op2 = *op;
521                 ber_int_t msgid;
522                 int do_retry = 1;
523
524                 ctrls[0] = &c;
525                 op2.o_ndn = op->o_conn->c_ndn;
526                 lc = ldap_back_getconn(&op2, rs);
527                 if (!lc || !ldap_back_dobind( lc, op, rs )) {
528                         return -1;
529                 }
530                 c.ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
531                 c.ldctl_iscritical = 1;
532                 c.ldctl_value.bv_val = ch_malloc(op->o_ndn.bv_len+4);
533                 c.ldctl_value.bv_len = op->o_ndn.bv_len + 3;
534                 strcpy(c.ldctl_value.bv_val, "dn:");
535                 strcpy(c.ldctl_value.bv_val+3, op->o_ndn.bv_val);
536
537 retry:
538                 rs->sr_err = ldap_whoami(lc->ld, ctrls, NULL, &msgid);
539                 if (rs->sr_err == LDAP_SUCCESS) {
540                         if (ldap_result(lc->ld, msgid, 1, NULL, &res) == -1) {
541                                 ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
542                                         &rs->sr_err);
543                                 if ( rs->sr_err = LDAP_SERVER_DOWN && do_retry ) {
544                                         do_retry = 0;
545                                         if ( ldap_back_retry( lc, op, rs ))
546                                                 goto retry;
547                                 }
548                                 ldap_back_freeconn( op, lc );
549                                 lc = NULL;
550
551                         } else {
552                                 rs->sr_err = ldap_parse_whoami(lc->ld, res, &bv);
553                                 ldap_msgfree(res);
554                         }
555                 }
556                 ch_free(c.ldctl_value.bv_val);
557                 if (rs->sr_err != LDAP_SUCCESS) {
558                         rs->sr_err = slap_map_api2result( rs );
559                 }
560         } else {
561         /* else just do the same as before */
562                 bv = (struct berval *) ch_malloc( sizeof(struct berval) );
563                 if( op->o_dn.bv_len ) {
564                         bv->bv_len = op->o_dn.bv_len + sizeof("dn:") - 1;
565                         bv->bv_val = ch_malloc( bv->bv_len + 1 );
566                         AC_MEMCPY( bv->bv_val, "dn:", sizeof("dn:") - 1 );
567                         AC_MEMCPY( &bv->bv_val[sizeof("dn:") - 1], op->o_dn.bv_val,
568                                 op->o_dn.bv_len );
569                         bv->bv_val[bv->bv_len] = '\0';
570                 } else {
571                         bv->bv_len = 0;
572                         bv->bv_val = NULL;
573                 }
574         }
575
576         rs->sr_rspdata = bv;
577         return rs->sr_err;
578 }
579
580
581 #ifdef ENABLE_REWRITE
582 static char *
583 suffix_massage_regexize( const char *s )
584 {
585         char *res, *ptr;
586         const char *p, *r;
587         int i;
588
589         for ( i = 0, p = s; 
590                         ( r = strchr( p, ',' ) ) != NULL; 
591                         p = r + 1, i++ )
592                 ;
593
594         res = ch_calloc( sizeof( char ), strlen( s ) + 4 + 4*i + 1 );
595
596         ptr = lutil_strcopy( res, "(.*)" );
597         for ( i = 0, p = s;
598                         ( r = strchr( p, ',' ) ) != NULL;
599                         p = r + 1 , i++ ) {
600                 ptr = lutil_strncopy( ptr, p, r - p + 1 );
601                 ptr = lutil_strcopy( ptr, "[ ]?" );
602
603                 if ( r[ 1 ] == ' ' ) {
604                         r++;
605                 }
606         }
607         lutil_strcopy( ptr, p );
608
609         return res;
610 }
611
612 static char *
613 suffix_massage_patternize( const char *s )
614 {
615         ber_len_t       len;
616         char            *res;
617
618         len = strlen( s );
619
620         res = ch_calloc( sizeof( char ), len + sizeof( "%1" ) );
621         if ( res == NULL ) {
622                 return NULL;
623         }
624
625         strcpy( res, "%1" );
626         strcpy( res + sizeof( "%1" ) - 1, s );
627
628         return res;
629 }
630
631 int
632 suffix_massage_config( 
633                 struct rewrite_info *info,
634                 struct berval *pvnc,
635                 struct berval *nvnc,
636                 struct berval *prnc,
637                 struct berval *nrnc
638 )
639 {
640         char *rargv[ 5 ];
641         int line = 0;
642
643         rargv[ 0 ] = "rewriteEngine";
644         rargv[ 1 ] = "on";
645         rargv[ 2 ] = NULL;
646         rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
647
648         rargv[ 0 ] = "rewriteContext";
649         rargv[ 1 ] = "default";
650         rargv[ 2 ] = NULL;
651         rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
652
653         rargv[ 0 ] = "rewriteRule";
654         rargv[ 1 ] = suffix_massage_regexize( pvnc->bv_val );
655         rargv[ 2 ] = suffix_massage_patternize( prnc->bv_val );
656         rargv[ 3 ] = ":";
657         rargv[ 4 ] = NULL;
658         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
659         ch_free( rargv[ 1 ] );
660         ch_free( rargv[ 2 ] );
661         
662         rargv[ 0 ] = "rewriteContext";
663         rargv[ 1 ] = "searchResult";
664         rargv[ 2 ] = NULL;
665         rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
666         
667         rargv[ 0 ] = "rewriteRule";
668         rargv[ 1 ] = suffix_massage_regexize( prnc->bv_val );
669         rargv[ 2 ] = suffix_massage_patternize( pvnc->bv_val );
670         rargv[ 3 ] = ":";
671         rargv[ 4 ] = NULL;
672         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
673         ch_free( rargv[ 1 ] );
674         ch_free( rargv[ 2 ] );
675
676         rargv[ 0 ] = "rewriteContext";
677         rargv[ 1 ] = "matchedDN";
678         rargv[ 2 ] = "alias";
679         rargv[ 3 ] = "searchResult";
680         rargv[ 4 ] = NULL;
681         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
682
683         rargv[ 0 ] = "rewriteContext";
684         rargv[ 1 ] = "searchAttrDN";
685         rargv[ 2 ] = "alias";
686         rargv[ 3 ] = "searchResult";
687         rargv[ 4 ] = NULL;
688         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
689
690         return 0;
691 }
692 #endif /* ENABLE_REWRITE */