]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldap/config.c
95a3f265002bef7fa44212691663cbff69e31519
[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 #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 static int
41 parse_idassert( BackendDB *be, const char *fname, int lineno,
42                 int argc, char **argv );
43
44 int
45 ldap_back_db_config(
46     BackendDB   *be,
47     const char  *fname,
48     int         lineno,
49     int         argc,
50     char        **argv
51 )
52 {
53         struct ldapinfo *li = (struct ldapinfo *) be->be_private;
54
55         if ( li == NULL ) {
56                 fprintf( stderr, "%s: line %d: ldap backend info is null!\n",
57                     fname, lineno );
58                 return( 1 );
59         }
60
61         /* server address to query (depricated, use "uri" directive) */
62         if ( strcasecmp( argv[0], "server" ) == 0 ) {
63                 ber_len_t       l;
64
65                 if (argc != 2) {
66                         fprintf( stderr,
67         "%s: line %d: missing address in \"server <address>\" line\n",
68                             fname, lineno );
69                         return( 1 );
70                 }
71                 if (li->url != NULL)
72                         ch_free(li->url);
73                 l = strlen( argv[1] ) + STRLENOF( "ldap:///") + 1;
74                 li->url = ch_calloc( l, sizeof( char ) );
75                 if (li->url == NULL) {
76                         fprintf( stderr, "%s: line %d: malloc failed\n" );
77                         return 1;
78                 }
79
80                 snprintf( li->url, l, "ldap://%s/", argv[1] );
81
82         /* URI of server to query (preferred over "server" directive) */
83         } else if ( strcasecmp( argv[0], "uri" ) == 0 ) {
84                 LDAPURLDesc     tmplud, *tmpludp;
85                 int             urlrc;
86
87                 if (argc != 2) {
88                         fprintf( stderr, "%s: line %d: "
89                                 "missing uri "
90                                 "in \"uri <uri>\" line\n",
91                                 fname, lineno );
92                         return( 1 );
93                 }
94                 if ( li->url != NULL ) {
95                         ch_free( li->url );
96                 }
97                 if ( li->lud != NULL ) {
98                         ldap_free_urllist( li->lud );
99                 }
100
101 #if 0
102                 /* PARANOID: DN and more are not required nor allowed */
103                 urlrc = ldap_url_parselist_ext( &li->lud, argv[ 1 ], "\t" );
104 #else
105                 urlrc =  ldap_url_parselist( &li->lud, argv[ 1 ] );
106 #endif
107                 if ( urlrc != LDAP_URL_SUCCESS ) {
108                         char    *why;
109
110                         switch ( urlrc ) {
111                         case LDAP_URL_ERR_MEM:
112                                 why = "no memory";
113                                 break;
114                         case LDAP_URL_ERR_PARAM:
115                                 why = "parameter is bad";
116                                 break;
117                         case LDAP_URL_ERR_BADSCHEME:
118                                 why = "URL doesn't begin with \"[c]ldap[si]://\"";
119                                 break;
120                         case LDAP_URL_ERR_BADENCLOSURE:
121                                 why = "URL is missing trailing \">\"";
122                                 break;
123                         case LDAP_URL_ERR_BADURL:
124                                 why = "URL is bad";
125                         case LDAP_URL_ERR_BADHOST:
126                                 why = "host/port is bad";
127                                 break;
128                         case LDAP_URL_ERR_BADATTRS:
129                                 why = "bad (or missing) attributes";
130                                 break;
131                         case LDAP_URL_ERR_BADSCOPE:
132                                 why = "scope string is invalid (or missing)";
133                                 break;
134                         case LDAP_URL_ERR_BADFILTER:
135                                 why = "bad or missing filter";
136                                 break;
137                         case LDAP_URL_ERR_BADEXTS:
138                                 why = "bad or missing extensions";
139                                 break;
140                         default:
141                                 why = "unknown reason";
142                                 break;
143                         }
144                         fprintf( stderr, "%s: line %d: "
145                                 "unable to parse uri \"%s\" "
146                                 "in \"uri <uri>\" line: %s\n",
147                                 fname, lineno, argv[ 1 ], why );
148                         return 1;
149                 }
150
151                 for ( tmpludp = li->lud; tmpludp; tmpludp = tmpludp->lud_next ) {
152                         if ( ( tmpludp->lud_dn != NULL && tmpludp->lud_dn[0] != '\0' )
153                                         || tmpludp->lud_attrs != NULL
154                                         || tmpludp->lud_filter != NULL
155                                         || tmpludp->lud_exts != NULL )
156                         {
157                                 fprintf( stderr, "%s: line %d: "
158                                         "warning, only protocol, "
159                                         "host and port allowed "
160                                         "in \"uri <uri>\" statement "
161                                         "for \"%s\"\n",
162                                         fname, lineno, argv[1] );
163                         }
164                 }
165
166 #if 0
167                 for ( tmpludp = li->lud; tmpludp; tmpludp = tmpludp->lud_next ) {
168                         char            *tmpurl;
169                         ber_len_t       oldlen = 0, len;
170
171                         tmplud = *tmpludp;
172                         tmplud.lud_dn = "";
173                         tmplud.lud_attrs = NULL;
174                         tmplud.lud_filter = NULL;
175                         if ( !ldap_is_ldapi_url( argv[ 1 ] ) ) {
176                                 tmplud.lud_exts = NULL;
177                                 tmplud.lud_crit_exts = 0;
178                         }
179
180                         tmpurl = ldap_url_desc2str( &tmplud );
181
182                         if ( tmpurl == NULL ) {
183                                 fprintf( stderr, "%s: line %d: "
184                                         "unable to rebuild uri "
185                                         "in \"uri <uri>\" statement "
186                                         "for \"%s\"\n",
187                                         fname, lineno, argv[ 1 ] );
188                                 return 1;
189                         }
190
191                         len = strlen( tmpurl );
192                         if ( li->url ) {
193                                 oldlen = strlen( li->url ) + STRLENOF( " " );
194                         }
195                         li->url = ch_realloc( li->url, oldlen + len + 1);
196                         if ( oldlen ) {
197                                 li->url[oldlen - 1] = " ";
198                         }
199                         AC_MEMCPY( &li->url[oldlen], tmpurl, len + 1 );
200                         ch_free( tmpurl );
201                 }
202 #else
203                 li->url = ch_strdup( argv[ 1 ] );
204 #endif
205
206         /* name to use for ldap_back_group */
207         } else if ( strcasecmp( argv[0], "acl-authcdn" ) == 0
208                         || strcasecmp( argv[0], "binddn" ) == 0 ) {
209                 if (argc != 2) {
210                         fprintf( stderr,
211         "%s: line %d: missing name in \"%s <name>\" line\n",
212                             fname, lineno, argv[0] );
213                         return( 1 );
214                 }
215                 ber_str2bv( argv[1], 0, 1, &li->acl_authcDN );
216
217         /* password to use for ldap_back_group */
218         } else if ( strcasecmp( argv[0], "acl-passwd" ) == 0
219                         || strcasecmp( argv[0], "bindpw" ) == 0 ) {
220                 if (argc != 2) {
221                         fprintf( stderr,
222         "%s: line %d: missing password in \"%s <password>\" line\n",
223                             fname, lineno, argv[0] );
224                         return( 1 );
225                 }
226                 ber_str2bv( argv[1], 0, 1, &li->acl_passwd );
227
228 #ifdef LDAP_BACK_PROXY_AUTHZ
229         /* identity assertion stuff... */
230         } else if ( strncasecmp( argv[0], "idassert-", STRLENOF( "idassert-" ) ) == 0
231                         || strncasecmp( argv[0], "proxyauthz", STRLENOF( "proxyauthz" ) ) == 0 ) {
232                 return parse_idassert( be, fname, lineno, argc, argv );
233 #endif /* LDAP_BACK_PROXY_AUTHZ */
234
235         /* save bind creds for referral rebinds? */
236         } else if ( strcasecmp( argv[0], "rebind-as-user" ) == 0 ) {
237                 if (argc != 1) {
238                         fprintf( stderr,
239         "%s: line %d: rebind-as-user takes no arguments\n",
240                             fname, lineno );
241                         return( 1 );
242                 }
243                 li->savecred = 1;
244         
245         /* intercept exop_who_am_i? */
246         } else if ( strcasecmp( argv[0], "proxy-whoami" ) == 0 ) {
247                 if (argc != 1) {
248                         fprintf( stderr,
249         "%s: line %d: proxy-whoami takes no arguments\n",
250                             fname, lineno );
251                         return( 1 );
252                 }
253                 load_extop( (struct berval *)&slap_EXOP_WHOAMI,
254                         0, ldap_back_exop_whoami );
255         
256         /* dn massaging */
257         } else if ( strcasecmp( argv[0], "suffixmassage" ) == 0 ) {
258                 BackendDB *tmp_be;
259                 struct berval bvnc, nvnc, pvnc, brnc, nrnc, prnc;
260 #ifdef ENABLE_REWRITE
261                 int rc;
262 #endif /* ENABLE_REWRITE */
263                 
264                 /*
265                  * syntax:
266                  * 
267                  *      suffixmassage <suffix> <massaged suffix>
268                  *
269                  * the <suffix> field must be defined as a valid suffix
270                  * (or suffixAlias?) for the current database;
271                  * the <massaged suffix> shouldn't have already been
272                  * defined as a valid suffix or suffixAlias for the 
273                  * current server
274                  */
275                 if ( argc != 3 ) {
276                         fprintf( stderr, "%s: line %d: syntax is"
277                                        " \"suffixMassage <suffix>"
278                                        " <massaged suffix>\"\n",
279                                 fname, lineno );
280                         return( 1 );
281                 }
282                 
283                 ber_str2bv( argv[1], 0, 0, &bvnc );
284                 if ( dnPrettyNormal( NULL, &bvnc, &pvnc, &nvnc, NULL ) != LDAP_SUCCESS ) {
285                         fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n",
286                                 fname, lineno, bvnc.bv_val );
287                         return( 1 );
288                 }
289                 tmp_be = select_backend( &nvnc, 0, 0 );
290                 if ( tmp_be != NULL && tmp_be != be ) {
291                         fprintf( stderr, "%s: line %d: suffix already in use"
292                                        " by another backend in"
293                                        " \"suffixMassage <suffix>"
294                                        " <massaged suffix>\"\n",
295                                 fname, lineno );
296                         free( nvnc.bv_val );
297                         free( pvnc.bv_val );
298                         return( 1 );
299                 }
300
301                 ber_str2bv( argv[2], 0, 0, &brnc );
302                 if ( dnPrettyNormal( NULL, &brnc, &prnc, &nrnc, NULL ) != LDAP_SUCCESS ) {
303                         fprintf( stderr, "%s: line %d: suffix DN %s is invalid\n",
304                                 fname, lineno, brnc.bv_val );
305                         free( nvnc.bv_val );
306                         free( pvnc.bv_val );
307                         return( 1 );
308                 }
309
310 #if 0
311                 tmp_be = select_backend( &nrnc, 0, 0 );
312                 if ( tmp_be != NULL ) {
313                         fprintf( stderr, "%s: line %d: massaged suffix"
314                                        " already in use by another backend in" 
315                                        " \"suffixMassage <suffix>"
316                                        " <massaged suffix>\"\n",
317                                 fname, lineno );
318                         free( nvnc.bv_val );
319                         free( pvnc.bv_val );
320                         free( nrnc.bv_val );
321                         free( prnc.bv_val );
322                         return( 1 );
323                 }
324 #endif
325
326 #ifdef ENABLE_REWRITE
327                 /*
328                  * The suffix massaging is emulated by means of the
329                  * rewrite capabilities
330                  * FIXME: no extra rewrite capabilities should be added
331                  * to the database
332                  */
333                 rc = suffix_massage_config( li->rwmap.rwm_rw,
334                                 &pvnc, &nvnc, &prnc, &nrnc );
335                 free( nvnc.bv_val );
336                 free( pvnc.bv_val );
337                 free( nrnc.bv_val );
338                 free( prnc.bv_val );
339
340                 return( rc );
341
342 #else /* !ENABLE_REWRITE */
343                 ber_bvarray_add( &li->rwmap.rwm_suffix_massage, &pvnc );
344                 ber_bvarray_add( &li->rwmap.rwm_suffix_massage, &nvnc );
345                 
346                 ber_bvarray_add( &li->rwmap.rwm_suffix_massage, &prnc );
347                 ber_bvarray_add( &li->rwmap.rwm_suffix_massage, &nrnc );
348 #endif /* !ENABLE_REWRITE */
349
350         /* rewrite stuff ... */
351         } else if ( strncasecmp( argv[0], "rewrite", 7 ) == 0 ) {
352 #ifdef ENABLE_REWRITE
353                 return rewrite_parse( li->rwmap.rwm_rw,
354                                 fname, lineno, argc, argv );
355
356 #else /* !ENABLE_REWRITE */
357                 fprintf( stderr, "%s: line %d: rewrite capabilities "
358                                 "are not enabled\n", fname, lineno );
359 #endif /* !ENABLE_REWRITE */
360                 
361         /* objectclass/attribute mapping */
362         } else if ( strcasecmp( argv[0], "map" ) == 0 ) {
363                 return ldap_back_map_config( &li->rwmap.rwm_oc,
364                                 &li->rwmap.rwm_at,
365                                 fname, lineno, argc, argv );
366
367         /* anything else */
368         } else {
369                 return SLAP_CONF_UNKNOWN;
370         }
371         return 0;
372 }
373
374 int
375 ldap_back_map_config(
376                 struct ldapmap  *oc_map,
377                 struct ldapmap  *at_map,
378                 const char      *fname,
379                 int             lineno,
380                 int             argc,
381                 char            **argv )
382 {
383         struct ldapmap          *map;
384         struct ldapmapping      *mapping;
385         char                    *src, *dst;
386         int                     is_oc = 0;
387
388         if ( argc < 3 || argc > 4 ) {
389                 fprintf( stderr,
390         "%s: line %d: syntax is \"map {objectclass | attribute} [<local> | *] {<foreign> | *}\"\n",
391                         fname, lineno );
392                 return 1;
393         }
394
395         if ( strcasecmp( argv[1], "objectclass" ) == 0 ) {
396                 map = oc_map;
397                 is_oc = 1;
398
399         } else if ( strcasecmp( argv[1], "attribute" ) == 0 ) {
400                 map = at_map;
401
402         } else {
403                 fprintf( stderr, "%s: line %d: syntax is "
404                         "\"map {objectclass | attribute} [<local> | *] "
405                         "{<foreign> | *}\"\n",
406                         fname, lineno );
407                 return 1;
408         }
409
410         if ( strcmp( argv[2], "*" ) == 0 ) {
411                 if ( argc < 4 || strcmp( argv[3], "*" ) == 0 ) {
412                         map->drop_missing = ( argc < 4 );
413                         return 0;
414                 }
415                 src = dst = argv[3];
416
417         } else if ( argc < 4 ) {
418                 src = "";
419                 dst = argv[2];
420
421         } else {
422                 src = argv[2];
423                 dst = ( strcmp( argv[3], "*" ) == 0 ? src : argv[3] );
424         }
425
426         if ( ( map == at_map )
427                         && ( strcasecmp( src, "objectclass" ) == 0
428                         || strcasecmp( dst, "objectclass" ) == 0 ) )
429         {
430                 fprintf( stderr,
431                         "%s: line %d: objectclass attribute cannot be mapped\n",
432                         fname, lineno );
433         }
434
435         mapping = (struct ldapmapping *)ch_calloc( 2,
436                 sizeof(struct ldapmapping) );
437         if ( mapping == NULL ) {
438                 fprintf( stderr,
439                         "%s: line %d: out of memory\n",
440                         fname, lineno );
441                 return 1;
442         }
443         ber_str2bv( src, 0, 1, &mapping->src );
444         ber_str2bv( dst, 0, 1, &mapping->dst );
445         mapping[1].src = mapping->dst;
446         mapping[1].dst = mapping->src;
447
448         /*
449          * schema check
450          */
451         if ( is_oc ) {
452                 if ( src[0] != '\0' ) {
453                         if ( oc_bvfind( &mapping->src ) == NULL ) {
454                                 fprintf( stderr,
455         "%s: line %d: warning, source objectClass '%s' "
456         "should be defined in schema\n",
457                                         fname, lineno, src );
458
459                                 /*
460                                  * FIXME: this should become an err
461                                  */
462                                 goto error_return;
463                         }
464                 }
465
466                 if ( oc_bvfind( &mapping->dst ) == NULL ) {
467                         fprintf( stderr,
468         "%s: line %d: warning, destination objectClass '%s' "
469         "is not defined in schema\n",
470                                 fname, lineno, dst );
471                 }
472         } else {
473                 int                     rc;
474                 const char              *text = NULL;
475                 AttributeDescription    *ad = NULL;
476
477                 if ( src[0] != '\0' ) {
478                         rc = slap_bv2ad( &mapping->src, &ad, &text );
479                         if ( rc != LDAP_SUCCESS ) {
480                                 fprintf( stderr,
481         "%s: line %d: warning, source attributeType '%s' "
482         "should be defined in schema\n",
483                                         fname, lineno, src );
484
485                                 /*
486                                  * FIXME: this should become an err
487                                  */
488                                 goto error_return;
489                         }
490
491                         ad = NULL;
492                 }
493
494                 rc = slap_bv2ad( &mapping->dst, &ad, &text );
495                 if ( rc != LDAP_SUCCESS ) {
496                         fprintf( stderr,
497         "%s: line %d: warning, destination attributeType '%s' "
498         "is not defined in schema\n",
499                                 fname, lineno, dst );
500                 }
501         }
502
503         if ( (src[0] != '\0' && avl_find( map->map, (caddr_t)mapping, mapping_cmp ) != NULL)
504                         || avl_find( map->remap, (caddr_t)&mapping[1], mapping_cmp ) != NULL)
505         {
506                 fprintf( stderr,
507                         "%s: line %d: duplicate mapping found (ignored)\n",
508                         fname, lineno );
509                 goto error_return;
510         }
511
512         if ( src[0] != '\0' ) {
513                 avl_insert( &map->map, (caddr_t)mapping,
514                                         mapping_cmp, mapping_dup );
515         }
516         avl_insert( &map->remap, (caddr_t)&mapping[1],
517                                 mapping_cmp, mapping_dup );
518
519         return 0;
520
521 error_return:;
522         if ( mapping ) {
523                 ch_free( mapping->src.bv_val );
524                 ch_free( mapping->dst.bv_val );
525                 ch_free( mapping );
526         }
527
528         return 1;
529 }
530
531 static int
532 ldap_back_exop_whoami(
533         Operation *op,
534         SlapReply *rs )
535 {
536         struct berval *bv = NULL;
537
538         if ( op->oq_extended.rs_reqdata != NULL ) {
539                 /* no request data should be provided */
540                 rs->sr_text = "no request data expected";
541                 return rs->sr_err = LDAP_PROTOCOL_ERROR;
542         }
543
544         rs->sr_err = backend_check_restrictions( op, rs, 
545                         (struct berval *)&slap_EXOP_WHOAMI );
546         if( rs->sr_err != LDAP_SUCCESS ) return rs->sr_err;
547
548         /* if auth'd by back-ldap and request is proxied, forward it */
549         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)) {
550                 struct ldapconn *lc;
551
552                 LDAPControl c, *ctrls[2] = {NULL, NULL};
553                 LDAPMessage *res;
554                 Operation op2 = *op;
555                 ber_int_t msgid;
556
557                 ctrls[0] = &c;
558                 op2.o_ndn = op->o_conn->c_ndn;
559                 lc = ldap_back_getconn(&op2, rs);
560                 if (!lc || !ldap_back_dobind( lc, op, rs )) {
561                         return -1;
562                 }
563                 c.ldctl_oid = LDAP_CONTROL_PROXY_AUTHZ;
564                 c.ldctl_iscritical = 1;
565                 c.ldctl_value.bv_val = ch_malloc(op->o_ndn.bv_len+4);
566                 c.ldctl_value.bv_len = op->o_ndn.bv_len + 3;
567                 strcpy(c.ldctl_value.bv_val, "dn:");
568                 strcpy(c.ldctl_value.bv_val+3, op->o_ndn.bv_val);
569
570                 rs->sr_err = ldap_whoami(lc->ld, ctrls, NULL, &msgid);
571                 if (rs->sr_err == LDAP_SUCCESS) {
572                         if (ldap_result(lc->ld, msgid, 1, NULL, &res) == -1) {
573                                 ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
574                                         &rs->sr_err);
575                                 ldap_back_freeconn( op, lc );
576                                 lc = NULL;
577
578                         } else {
579                                 rs->sr_err = ldap_parse_whoami(lc->ld, res, &bv);
580                                 ldap_msgfree(res);
581                         }
582                 }
583                 ch_free(c.ldctl_value.bv_val);
584                 if (rs->sr_err != LDAP_SUCCESS) {
585                         rs->sr_err = slap_map_api2result( rs );
586                 }
587         } else {
588         /* else just do the same as before */
589                 bv = (struct berval *) ch_malloc( sizeof(struct berval) );
590                 if( op->o_dn.bv_len ) {
591                         bv->bv_len = op->o_dn.bv_len + sizeof("dn:") - 1;
592                         bv->bv_val = ch_malloc( bv->bv_len + 1 );
593                         AC_MEMCPY( bv->bv_val, "dn:", sizeof("dn:") - 1 );
594                         AC_MEMCPY( &bv->bv_val[sizeof("dn:") - 1], op->o_dn.bv_val,
595                                 op->o_dn.bv_len );
596                         bv->bv_val[bv->bv_len] = '\0';
597                 } else {
598                         bv->bv_len = 0;
599                         bv->bv_val = NULL;
600                 }
601         }
602
603         rs->sr_rspdata = bv;
604         return rs->sr_err;
605 }
606
607
608 #ifdef ENABLE_REWRITE
609 static char *
610 suffix_massage_regexize( const char *s )
611 {
612         char *res, *ptr;
613         const char *p, *r;
614         int i;
615
616         for ( i = 0, p = s; 
617                         ( r = strchr( p, ',' ) ) != NULL; 
618                         p = r + 1, i++ )
619                 ;
620
621         res = ch_calloc( sizeof( char ), strlen( s ) + 4 + 4*i + 1 );
622
623         ptr = lutil_strcopy( res, "(.*)" );
624         for ( i = 0, p = s;
625                         ( r = strchr( p, ',' ) ) != NULL;
626                         p = r + 1 , i++ ) {
627                 ptr = lutil_strncopy( ptr, p, r - p + 1 );
628                 ptr = lutil_strcopy( ptr, "[ ]?" );
629
630                 if ( r[ 1 ] == ' ' ) {
631                         r++;
632                 }
633         }
634         lutil_strcopy( ptr, p );
635
636         return res;
637 }
638
639 static char *
640 suffix_massage_patternize( const char *s )
641 {
642         ber_len_t       len;
643         char            *res;
644
645         len = strlen( s );
646
647         res = ch_calloc( sizeof( char ), len + sizeof( "%1" ) );
648         if ( res == NULL ) {
649                 return NULL;
650         }
651
652         strcpy( res, "%1" );
653         strcpy( res + sizeof( "%1" ) - 1, s );
654
655         return res;
656 }
657
658 int
659 suffix_massage_config( 
660                 struct rewrite_info *info,
661                 struct berval *pvnc,
662                 struct berval *nvnc,
663                 struct berval *prnc,
664                 struct berval *nrnc
665 )
666 {
667         char *rargv[ 5 ];
668         int line = 0;
669
670         rargv[ 0 ] = "rewriteEngine";
671         rargv[ 1 ] = "on";
672         rargv[ 2 ] = NULL;
673         rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
674
675         rargv[ 0 ] = "rewriteContext";
676         rargv[ 1 ] = "default";
677         rargv[ 2 ] = NULL;
678         rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
679
680         rargv[ 0 ] = "rewriteRule";
681         rargv[ 1 ] = suffix_massage_regexize( pvnc->bv_val );
682         rargv[ 2 ] = suffix_massage_patternize( prnc->bv_val );
683         rargv[ 3 ] = ":";
684         rargv[ 4 ] = NULL;
685         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
686         ch_free( rargv[ 1 ] );
687         ch_free( rargv[ 2 ] );
688         
689         rargv[ 0 ] = "rewriteContext";
690         rargv[ 1 ] = "searchResult";
691         rargv[ 2 ] = NULL;
692         rewrite_parse( info, "<suffix massage>", ++line, 2, rargv );
693         
694         rargv[ 0 ] = "rewriteRule";
695         rargv[ 1 ] = suffix_massage_regexize( prnc->bv_val );
696         rargv[ 2 ] = suffix_massage_patternize( pvnc->bv_val );
697         rargv[ 3 ] = ":";
698         rargv[ 4 ] = NULL;
699         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
700         ch_free( rargv[ 1 ] );
701         ch_free( rargv[ 2 ] );
702
703         rargv[ 0 ] = "rewriteContext";
704         rargv[ 1 ] = "matchedDN";
705         rargv[ 2 ] = "alias";
706         rargv[ 3 ] = "searchResult";
707         rargv[ 4 ] = NULL;
708         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
709
710         rargv[ 0 ] = "rewriteContext";
711         rargv[ 1 ] = "searchAttrDN";
712         rargv[ 2 ] = "alias";
713         rargv[ 3 ] = "searchResult";
714         rargv[ 4 ] = NULL;
715         rewrite_parse( info, "<suffix massage>", ++line, 4, rargv );
716
717         return 0;
718 }
719 #endif /* ENABLE_REWRITE */
720
721 #ifdef LDAP_BACK_PROXY_AUTHZ
722 static int
723 parse_idassert(
724     BackendDB   *be,
725     const char  *fname,
726     int         lineno,
727     int         argc,
728     char        **argv
729 )
730 {
731         struct ldapinfo *li = (struct ldapinfo *) be->be_private;
732
733         /* identity assertion mode */
734         if ( strcasecmp( argv[0], "idassert-mode" ) == 0 ) {
735                 if ( argc != 2 ) {
736                         Debug( LDAP_DEBUG_ANY,
737                                 "%s: line %d: illegal args number %d in \"idassert-mode <args>\" line.\n",
738                                 fname, lineno, argc );
739                         return 1;
740                 }
741
742                 if ( strcasecmp( argv[1], "legacy" ) == 0 ) {
743                         /* will proxyAuthz as client's identity only if bound */
744                         li->idassert_mode = LDAP_BACK_IDASSERT_LEGACY;
745
746                 } else if ( strcasecmp( argv[1], "self" ) == 0 ) {
747                         /* will proxyAuthz as client's identity */
748                         li->idassert_mode = LDAP_BACK_IDASSERT_SELF;
749
750                 } else if ( strcasecmp( argv[1], "anonymous" ) == 0 ) {
751                         /* will proxyAuthz as anonymous */
752                         li->idassert_mode = LDAP_BACK_IDASSERT_ANONYMOUS;
753
754                 } else if ( strcasecmp( argv[1], "none" ) == 0 ) {
755                         /* will not proxyAuthz */
756                         li->idassert_mode = LDAP_BACK_IDASSERT_NOASSERT;
757
758                 } else {
759                         struct berval   id;
760                         int             rc;
761
762                         /* will proxyAuthz as argv[1] */
763                         ber_str2bv( argv[1], 0, 0, &id );
764
765                         if ( strncasecmp( id.bv_val, "u:", STRLENOF( "u:" ) ) == 0 ) {
766                                 /* force lowercase... */
767                                 id.bv_val[0] = 'u';
768                                 li->idassert_mode = LDAP_BACK_IDASSERT_OTHERID;
769                                 ber_dupbv( &li->idassert_authzID, &id );
770
771                         } else {
772                                 struct berval   dn;
773
774                                 /* default is DN? */
775                                 if ( strncasecmp( id.bv_val, "dn:", STRLENOF( "dn:" ) ) == 0 ) {
776                                         id.bv_val += STRLENOF( "dn:" );
777                                         id.bv_len -= STRLENOF( "dn:" );
778                                 }
779
780                                 rc = dnNormalize( 0, NULL, NULL, &id, &dn, NULL );
781                                 if ( rc != LDAP_SUCCESS ) {
782                                         Debug( LDAP_DEBUG_ANY,
783                                                 "%s: line %d: idassert ID \"%s\" is not a valid DN\n",
784                                                 fname, lineno, argv[1] );
785                                         return 1;
786                                 }
787
788                                 li->idassert_authzID.bv_len = STRLENOF( "dn:" ) + dn.bv_len;
789                                 li->idassert_authzID.bv_val = ch_malloc( li->idassert_authzID.bv_len + 1 );
790                                 AC_MEMCPY( li->idassert_authzID.bv_val, "dn:", STRLENOF( "dn:" ) );
791                                 AC_MEMCPY( &li->idassert_authzID.bv_val[ STRLENOF( "dn:" ) ], dn.bv_val, dn.bv_len + 1 );
792                                 ch_free( dn.bv_val );
793
794                                 li->idassert_mode = LDAP_BACK_IDASSERT_OTHERDN;
795                         }
796                 }
797
798         /* name to use for proxyAuthz propagation */
799         } else if ( strcasecmp( argv[0], "idassert-authcdn" ) == 0
800                         || strcasecmp( argv[0], "proxyauthzdn" ) == 0 )
801         {
802                 struct berval   dn;
803                 int             rc;
804
805                 /* FIXME: "proxyauthzdn" is no longer documented, and
806                  * temporarily supported for backwards compatibility */
807
808                 if ( argc != 2 ) {
809                         fprintf( stderr,
810         "%s: line %d: missing name in \"%s <name>\" line\n",
811                             fname, lineno, argv[0] );
812                         return( 1 );
813                 }
814
815                 if ( !BER_BVISNULL( &li->idassert_authcDN ) ) {
816                         fprintf( stderr, "%s: line %d: "
817                                         "authcDN already defined; replacing...\n",
818                                         fname, lineno );
819                         ch_free( li->idassert_authcDN.bv_val );
820                 }
821                 
822                 ber_str2bv( argv[1], 0, 0, &dn );
823                 rc = dnNormalize( 0, NULL, NULL, &dn, &li->idassert_authcDN, NULL );
824                 if ( rc != LDAP_SUCCESS ) {
825                         Debug( LDAP_DEBUG_ANY,
826                                 "%s: line %d: idassert ID \"%s\" is not a valid DN\n",
827                                 fname, lineno, argv[1] );
828                         return 1;
829                 }
830
831         /* password to use for proxyAuthz propagation */
832         } else if ( strcasecmp( argv[0], "idassert-passwd" ) == 0
833                         || strcasecmp( argv[0], "proxyauthzpw" ) == 0 )
834         {
835                 /* FIXME: "proxyauthzpw" is no longer documented, and
836                  * temporarily supported for backwards compatibility */
837
838                 if ( argc != 2 ) {
839                         fprintf( stderr,
840         "%s: line %d: missing password in \"%s <password>\" line\n",
841                             fname, lineno, argv[0] );
842                         return( 1 );
843                 }
844
845                 if ( !BER_BVISNULL( &li->idassert_passwd ) ) {
846                         fprintf( stderr, "%s: line %d: "
847                                         "passwd already defined; replacing...\n",
848                                         fname, lineno );
849                         ch_free( li->idassert_passwd.bv_val );
850                 }
851                 
852                 ber_str2bv( argv[1], 0, 1, &li->idassert_passwd );
853
854         /* rules to accept identity assertion... */
855         } else if ( strcasecmp( argv[0], "idassert-authzFrom" ) == 0 ) {
856                 struct berval   rule;
857
858                 ber_str2bv( argv[1], 0, 1, &rule );
859
860                 ber_bvarray_add( &li->idassert_authz, &rule );
861
862         } else if ( strcasecmp( argv[0], "idassert-method" ) == 0 ) {
863                 if ( argc < 2 ) {
864                         fprintf( stderr,
865         "%s: line %d: missing method in \"%s <method>\" line\n",
866                             fname, lineno, argv[0] );
867                         return( 1 );
868                 }
869
870                 if ( strcasecmp( argv[1], "none" ) == 0 ) {
871                         /* FIXME: is this useful? */
872                         li->idassert_authmethod = LDAP_AUTH_NONE;
873
874                         if ( argc != 2 ) {
875                                 fprintf( stderr,
876         "%s: line %d: trailing args in \"%s %s ...\" line ignored\"\n",
877                                         fname, lineno, argv[0], argv[1] );
878                         }
879
880                 } else if ( strcasecmp( argv[1], "simple" ) == 0 ) {
881                         li->idassert_authmethod = LDAP_AUTH_SIMPLE;
882
883                         if ( argc != 2 ) {
884                                 fprintf( stderr,
885         "%s: line %d: trailing args in \"%s %s ...\" line ignored\"\n",
886                                         fname, lineno, argv[0], argv[1] );
887                         }
888
889                 } else if ( strcasecmp( argv[1], "sasl" ) == 0 ) {
890 #ifdef HAVE_CYRUS_SASL
891                         int     arg;
892
893                         for ( arg = 2; arg < argc; arg++ ) {
894                                 if ( strncasecmp( argv[arg], "mech=", STRLENOF( "mech=" ) ) == 0 ) {
895                                         char    *val = argv[arg] + STRLENOF( "mech=" );
896
897                                         if ( !BER_BVISNULL( &li->idassert_sasl_mech ) ) {
898                                                 fprintf( stderr, "%s: line %d: "
899                                                                 "SASL mech already defined; replacing...\n",
900                                                                 fname, lineno );
901                                                 ch_free( li->idassert_sasl_mech.bv_val );
902                                         }
903                                         ber_str2bv( val, 0, 1, &li->idassert_sasl_mech );
904
905                                 } else if ( strncasecmp( argv[arg], "realm=", STRLENOF( "realm=" ) ) == 0 ) {
906                                         char    *val = argv[arg] + STRLENOF( "realm=" );
907
908                                         if ( !BER_BVISNULL( &li->idassert_sasl_realm ) ) {
909                                                 fprintf( stderr, "%s: line %d: "
910                                                                 "SASL realm already defined; replacing...\n",
911                                                                 fname, lineno );
912                                                 ch_free( li->idassert_sasl_realm.bv_val );
913                                         }
914                                         ber_str2bv( val, 0, 1, &li->idassert_sasl_realm );
915
916                                 } else if ( strncasecmp( argv[arg], "authcdn=", STRLENOF( "authcdn=" ) ) == 0 ) {
917                                         char            *val = argv[arg] + STRLENOF( "authcdn=" );
918                                         struct berval   dn;
919                                         int             rc;
920
921                                         if ( !BER_BVISNULL( &li->idassert_authcDN ) ) {
922                                                 fprintf( stderr, "%s: line %d: "
923                                                                 "SASL authcDN already defined; replacing...\n",
924                                                                 fname, lineno );
925                                                 ch_free( li->idassert_authcDN.bv_val );
926                                         }
927                                         if ( strncasecmp( argv[arg], "dn:", STRLENOF( "dn:" ) ) == 0 ) {
928                                                 val += STRLENOF( "dn:" );
929                                         }
930
931                                         ber_str2bv( val, 0, 0, &dn );
932                                         rc = dnNormalize( 0, NULL, NULL, &dn, &li->idassert_authcDN, NULL );
933                                         if ( rc != LDAP_SUCCESS ) {
934                                                 Debug( LDAP_DEBUG_ANY,
935                                                         "%s: line %d: SASL authcdn \"%s\" is not a valid DN\n",
936                                                         fname, lineno, val );
937                                                 return 1;
938                                         }
939
940                                 } else if ( strncasecmp( argv[arg], "authcid=", STRLENOF( "authcid=" ) ) == 0 ) {
941                                         char    *val = argv[arg] + STRLENOF( "authcid=" );
942
943                                         if ( !BER_BVISNULL( &li->idassert_authcID ) ) {
944                                                 fprintf( stderr, "%s: line %d: "
945                                                                 "SASL authcID already defined; replacing...\n",
946                                                                 fname, lineno );
947                                                 ch_free( li->idassert_authcID.bv_val );
948                                         }
949                                         if ( strncasecmp( argv[arg], "u:", STRLENOF( "u:" ) ) == 0 ) {
950                                                 val += STRLENOF( "u:" );
951                                         }
952                                         ber_str2bv( val, 0, 1, &li->idassert_authcID );
953
954                                 } else if ( strncasecmp( argv[arg], "cred=", STRLENOF( "cred=" ) ) == 0 ) {
955                                         char    *val = argv[arg] + STRLENOF( "cred=" );
956
957                                         if ( !BER_BVISNULL( &li->idassert_passwd ) ) {
958                                                 fprintf( stderr, "%s: line %d: "
959                                                                 "SASL cred already defined; replacing...\n",
960                                                                 fname, lineno );
961                                                 ch_free( li->idassert_passwd.bv_val );
962                                         }
963                                         ber_str2bv( val, 0, 1, &li->idassert_passwd );
964
965                                 } else if ( strncasecmp( argv[arg], "authz=", STRLENOF( "authz=" ) ) == 0 ) {
966                                         char    *val = argv[arg] + STRLENOF( "authz=" );
967
968                                         if ( strcasecmp( val, "proxyauthz" ) == 0 ) {
969                                                 li->idassert_flags &= ~LDAP_BACK_AUTH_NATIVE_AUTHZ;
970
971                                         } else if ( strcasecmp( val, "native" ) == 0 ) {
972                                                 li->idassert_flags |= LDAP_BACK_AUTH_NATIVE_AUTHZ;
973
974                                         } else {
975                                                 fprintf( stderr, "%s: line %s: "
976                                                         "unknown authz mode \"%s\"\n",
977                                                         fname, lineno, val );
978                                                 return 1;
979                                         }
980
981                                 } else {
982                                         fprintf( stderr, "%s: line %d: "
983                                                         "unknown SASL parameter %s\n",
984                                                         fname, lineno, argv[arg] );
985                                         return 1;
986                                 }
987                         }
988
989                         li->idassert_authmethod = LDAP_AUTH_SASL;
990
991 #else /* !HAVE_CYRUS_SASL */
992                         fprintf( stderr, "%s: line %d: "
993                                         "compile --with-cyrus-sasl to enable SASL auth\n",
994                                         fname, lineno );
995                         return 1;
996 #endif /* !HAVE_CYRUS_SASL */
997
998                 } else {
999                         fprintf( stderr, "%s: line %d: "
1000                                         "unhandled idassert-method method %s\n",
1001                                         fname, lineno, argv[1] );
1002                         return 1;
1003                 }
1004
1005         } else {
1006                 return SLAP_CONF_UNKNOWN;
1007         }
1008
1009         return 0;
1010 }
1011 #endif /* LDAP_BACK_PROXY_AUTHZ */