]> git.sur5r.net Git - openldap/blob - servers/slapd/back-ldap/config.c
Extend value_match to extract an asserted value from a full value
[openldap] / servers / slapd / back-ldap / config.c
1 /* config.c - ldap backend configuration file routine */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7 /* This is an altered version */
8 /*
9  * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
10  * 
11  * Permission is granted to anyone to use this software for any purpose
12  * on any computer system, and to alter it and redistribute it, subject
13  * to the following restrictions:
14  * 
15  * 1. The author is not responsible for the consequences of use of this
16  *    software, no matter how awful, even if they arise from flaws in it.
17  * 
18  * 2. The origin of this software must not be misrepresented, either by
19  *    explicit claim or by omission.  Since few users ever read sources,
20  *    credits should appear in the documentation.
21  * 
22  * 3. Altered versions must be plainly marked as such, and must not be
23  *    misrepresented as being the original software.  Since few users
24  *    ever read sources, credits should appear in the documentation.
25  * 
26  * 4. This notice may not be removed or altered.
27  *
28  *
29  *
30  * Copyright 2000, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
31  * 
32  * This software is being modified by Pierangelo Masarati.
33  * The previously reported conditions apply to the modified code as well.
34  * Changes in the original code are highlighted where required.
35  * Credits for the original code go to the author, Howard Chu.
36  */
37
38 #include "portable.h"
39
40 #include <stdio.h>
41
42 #include <ac/string.h>
43 #include <ac/socket.h>
44
45 #include "slap.h"
46 #include "back-ldap.h"
47
48 int
49 ldap_back_db_config(
50     BackendDB   *be,
51     const char  *fname,
52     int         lineno,
53     int         argc,
54     char        **argv
55 )
56 {
57         struct ldapinfo *li = (struct ldapinfo *) be->be_private;
58
59         if ( li == NULL ) {
60                 fprintf( stderr, "%s: line %d: ldap backend info is null!\n",
61                     fname, lineno );
62                 return( 1 );
63         }
64
65         /* server address to query (depricated, use "uri" directive) */
66         if ( strcasecmp( argv[0], "server" ) == 0 ) {
67                 if (argc != 2) {
68                         fprintf( stderr,
69         "%s: line %d: missing address in \"server <address>\" line\n",
70                             fname, lineno );
71                         return( 1 );
72                 }
73                 if (li->url != NULL)
74                         ch_free(li->url);
75                 li->url = ch_calloc(strlen(argv[1]) + 9, sizeof(char));
76                 if (li->url != NULL) {
77                         strcpy(li->url, "ldap://");
78                         strcat(li->url, argv[1]);
79                         strcat(li->url, "/");
80                 }
81
82         /* URI of server to query (preferred over "server" directive) */
83         } else if ( strcasecmp( argv[0], "uri" ) == 0 ) {
84                 if (argc != 2) {
85                         fprintf( stderr,
86         "%s: line %d: missing address in \"uri <address>\" line\n",
87                             fname, lineno );
88                         return( 1 );
89                 }
90                 if (li->url != NULL)
91                         ch_free(li->url);
92                 li->url = ch_strdup(argv[1]);
93
94         /* name to use for ldap_back_group */
95         } else if ( strcasecmp( argv[0], "binddn" ) == 0 ) {
96                 if (argc != 2) {
97                         fprintf( stderr,
98         "%s: line %d: missing name in \"binddn <name>\" line\n",
99                             fname, lineno );
100                         return( 1 );
101                 }
102                 li->binddn = ch_strdup(argv[1]);
103
104         /* password to use for ldap_back_group */
105         } else if ( strcasecmp( argv[0], "bindpw" ) == 0 ) {
106                 if (argc != 2) {
107                         fprintf( stderr,
108         "%s: line %d: missing password in \"bindpw <password>\" line\n",
109                             fname, lineno );
110                         return( 1 );
111                 }
112                 li->bindpw = ch_strdup(argv[1]);
113         
114         /* dn massaging */
115         } else if ( strcasecmp( argv[0], "suffixmassage" ) == 0 ) {
116 #ifndef ENABLE_REWRITE
117                 char *dn, *massaged_dn;
118 #endif /* ENABLE_REWRITE */
119                 BackendDB *tmp_be;
120                 
121                 /*
122                  * syntax:
123                  * 
124                  *      suffixmassage <suffix> <massaged suffix>
125                  *
126                  * the <suffix> field must be defined as a valid suffix
127                  * (or suffixAlias?) for the current database;
128                  * the <massaged suffix> shouldn't have already been
129                  * defined as a valid suffix or suffixAlias for the 
130                  * current server
131                  */
132                 if ( argc != 3 ) {
133                         fprintf( stderr, "%s: line %d: syntax is"
134                                        " \"suffixMassage <suffix>"
135                                        " <massaged suffix>\"\n",
136                                 fname, lineno );
137                         return( 1 );
138                 }
139                 
140                 tmp_be = select_backend( argv[1], 0 );
141                 if ( tmp_be != NULL && tmp_be != be ) {
142                         fprintf( stderr, "%s: line %d: suffix already in use"
143                                        " by another backend in"
144                                        " \"suffixMassage <suffix>"
145                                        " <massaged suffix>\"\n",
146                                 fname, lineno );
147                         return( 1 );                                            
148                 }
149
150                 tmp_be = select_backend( argv[2], 0 );
151                 if ( tmp_be != NULL ) {
152                         fprintf( stderr, "%s: line %d: massaged suffix"
153                                        " already in use by another backend in" 
154                                        " \"suffixMassage <suffix>"
155                                        " <massaged suffix>\"\n",
156                                 fname, lineno );
157                         return( 1 );
158                 }
159
160 #ifdef ENABLE_REWRITE
161                 /*
162                  * The suffix massaging is emulated by means of the
163                  * rewrite capabilities
164                  * FIXME: no extra rewrite capabilities should be added
165                  * to the database
166                  */
167                 return suffix_massage_config( li->rwinfo, argc, argv );
168 #else /* !ENABLE_REWRITE */
169                 dn = ch_strdup( argv[1] );
170                 charray_add( &li->suffix_massage, dn );
171                 (void) dn_normalize( dn );
172                 charray_add( &li->suffix_massage, dn );
173                 
174                 massaged_dn = ch_strdup( argv[2] );
175                 charray_add( &li->suffix_massage, massaged_dn );
176                 (void) dn_normalize( massaged_dn );
177                 charray_add( &li->suffix_massage, massaged_dn );
178                 
179                 free( dn );
180                 free( massaged_dn );
181 #endif /* !ENABLE_REWRITE */
182
183 #ifdef ENABLE_REWRITE
184         /* rewrite stuff ... */
185         } else if ( strncasecmp( argv[0], "rewrite", 7 ) == 0 ) {
186                 return rewrite_parse( li->rwinfo, fname, lineno, argc, argv );
187 #endif /* ENABLE_REWRITE */
188                 
189         /* objectclass/attribute mapping */
190         } else if ( strcasecmp( argv[0], "map" ) == 0 ) {
191                 struct ldapmap *map;
192                 struct ldapmapping *mapping;
193                 char *src, *dst;
194
195                 if ( argc < 3 || argc > 4 ) {
196                         fprintf( stderr,
197         "%s: line %d: syntax is \"map {objectclass | attribute} {<source> | *} [<dest> | *]\"\n",
198                                 fname, lineno );
199                         return( 1 );
200                 }
201
202                 if ( strcasecmp( argv[1], "objectclass" ) == 0 ) {
203                         map = &li->oc_map;
204                 } else if ( strcasecmp( argv[1], "attribute" ) == 0 ) {
205                         map = &li->at_map;
206                 } else {
207                         fprintf( stderr,
208         "%s: line %d: syntax is \"map {objectclass | attribute} {<source> | *} [<dest> | *]\"\n",
209                                 fname, lineno );
210                         return( 1 );
211                 }
212
213                 if ( strcasecmp( argv[2], "*" ) != 0 ) {
214                         src = argv[2];
215                         if ( argc < 4 )
216                                 dst = "";
217                         else if ( strcasecmp( argv[3], "*" ) == 0 )
218                                 dst = src;
219                         else
220                                 dst = argv[3];
221                 } else {
222                         if ( argc < 4 ) {
223                                 map->drop_missing = 1;
224                                 return 0;
225                         }
226                         if ( strcasecmp( argv[3], "*" ) == 0 ) {
227                                 map->drop_missing = 0;
228                                 return 0;
229                         }
230
231                         src = argv[3];
232                         dst = src;
233                 }
234
235                 if ( ( map == &li->at_map )
236                         && ( strcasecmp( src, "objectclass" ) == 0
237                                 || strcasecmp( dst, "objectclass" ) == 0 ) )
238                 {
239                         fprintf( stderr,
240                                 "%s: line %d: objectclass attribute cannot be mapped\n",
241                                 fname, lineno );
242                 }
243
244                 mapping = (struct ldapmapping *)ch_calloc( 2, sizeof(struct ldapmapping) );
245                 if ( mapping == NULL ) {
246                         fprintf( stderr,
247                                 "%s: line %d: out of memory\n",
248                                 fname, lineno );
249                         return( 1 );
250                 }
251                 mapping->src = ch_strdup(src);
252                 mapping->dst = ch_strdup(dst);
253                 if ( *dst != 0 ) {
254                         mapping[1].src = mapping->dst;
255                         mapping[1].dst = mapping->src;
256                 } else {
257                         mapping[1].src = mapping->src;
258                         mapping[1].dst = mapping->dst;
259                 }
260
261                 if ( avl_find( map->map, (caddr_t)mapping, mapping_cmp ) != NULL
262                         || avl_find( map->remap, (caddr_t)&mapping[1], mapping_cmp ) != NULL)
263                 {
264                         fprintf( stderr,
265                                 "%s: line %d: duplicate mapping found (ignored)\n",
266                                 fname, lineno );
267                         return 0;
268                 }
269
270                 avl_insert( &map->map, (caddr_t)mapping,
271                                         mapping_cmp, mapping_dup );
272                 avl_insert( &map->remap, (caddr_t)&mapping[1],
273                                         mapping_cmp, mapping_dup );
274
275         /* anything else */
276         } else {
277                 fprintf( stderr,
278 "%s: line %d: unknown directive \"%s\" in ldap database definition (ignored)\n",
279                     fname, lineno, argv[0] );
280         }
281         return 0;
282 }
283
284 int
285 mapping_cmp ( const void *c1, const void *c2 )
286 {
287         struct ldapmapping *map1 = (struct ldapmapping *)c1;
288         struct ldapmapping *map2 = (struct ldapmapping *)c2;
289
290         return ( strcasecmp(map1->src, map2->src) );
291 }
292
293 int
294 mapping_dup ( void *c1, void *c2 )
295 {
296         struct ldapmapping *map1 = (struct ldapmapping *)c1;
297         struct ldapmapping *map2 = (struct ldapmapping *)c2;
298
299         return( ( strcasecmp(map1->src, map2->src) == 0 ) ? -1 : 0 );
300 }
301
302 char *
303 ldap_back_map ( struct ldapmap *map, char *s, int remap )
304 {
305         Avlnode *tree;
306         struct ldapmapping *mapping, fmapping;
307
308         if (remap)
309                 tree = map->remap;
310         else
311                 tree = map->map;
312
313         fmapping.src = s;
314         mapping = (struct ldapmapping *)avl_find( tree, (caddr_t)&fmapping, mapping_cmp );
315         if (mapping != NULL) {
316                 if ( *mapping->dst == 0 )
317                         return(NULL);
318                 return(mapping->dst);
319         }
320
321         if (map->drop_missing)
322                 return(NULL);
323
324         return(s);
325 }
326
327 char *
328 ldap_back_map_filter(
329                 struct ldapmap *at_map,
330                 struct ldapmap *oc_map,
331                 char *f,
332                 int remap
333 )
334 {
335         char *nf, *m, *p, *q, *s, c;
336         int len, extra, plen, in_quote;
337
338         if (f == NULL)
339                 return(NULL);
340
341         len = strlen(f);
342         extra = len;
343         len *= 2;
344         nf = ch_malloc( len + 1 );
345         if (nf == NULL)
346                 return(NULL);
347
348         /* this loop assumes the filter ends with one
349          * of the delimiter chars -- probably ')'.
350          */
351
352         s = nf;
353         q = NULL;
354         in_quote = 0;
355         for (p = f; (c = *p); p++) {
356                 if (c == '"') {
357                         in_quote = !in_quote;
358                         if (q != NULL) {
359                                 plen = p - q;
360                                 memcpy(s, q, plen);
361                                 s += plen;
362                                 q = NULL;
363                         }
364                         *s++ = c;
365                 } else if (in_quote) {
366                         /* ignore everything in quotes --
367                          * what about attrs in DNs?
368                          */
369                         *s++ = c;
370                 } else if (c != '(' && c != ')'
371                         && c != '=' && c != '>' && c != '<'
372                         && c != '|' && c != '&')
373                 {
374                         if (q == NULL)
375                                 q = p;
376                 } else {
377                         if (q != NULL) {
378                                 *p = 0;
379                                 m = ldap_back_map(at_map, q, remap);
380                                 if (m == NULL)
381                                         m = ldap_back_map(oc_map, q, remap);
382                                 if (m == NULL) {
383                                         m = q;
384                                 }
385                                 extra += p - q;
386                                 plen = strlen(m);
387                                 extra -= plen;
388                                 if (extra < 0) {
389                                         while (extra < 0) {
390                                                 extra += len;
391                                                 len *= 2;
392                                         }
393                                         s -= (long)nf;
394                                         nf = ch_realloc(nf, len + 1);
395                                         if (nf == NULL) {
396                                                 free(nf);
397                                                 return(NULL);
398                                         }
399                                         s += (long)nf;
400                                 }
401                                 memcpy(s, m, plen);
402                                 s += plen;
403                                 *p = c;
404                                 q = NULL;
405                         }
406                         *s++ = c;
407                 }
408         }
409         *s = 0;
410         return(nf);
411 }
412
413 char **
414 ldap_back_map_attrs(
415                 struct ldapmap *at_map,
416                 char **a,
417                 int remap
418 )
419 {
420         int i, j, count;
421         char **na, *mapped;
422
423         if (a == NULL)
424                 return(NULL);
425
426         for (count = 0; a[count] != NULL; count++) {
427                 /*  */
428         }
429
430         na = (char **)ch_calloc( count + 1, sizeof(char *) );
431         if (na == NULL)
432                 return(NULL);
433
434         for (i = 0, j = 0; i < count; i++) {
435                 mapped = ldap_back_map(at_map, a[i], remap);
436                 if (mapped != NULL) {
437                         mapped = ch_strdup(mapped);
438                         if (mapped == NULL) {
439                                 charray_free(na);
440                                 return(NULL);
441                         }
442                         na[j] = mapped;
443                         j++;
444                 }
445         }
446         return(na);
447 }
448
449 #ifdef ENABLE_REWRITE
450 static char *
451 suffix_massage_regexize( const char *s )
452 {
453         char *res, *p, *r;
454         int i;
455
456         for ( i = 0, p = ( char * )s; 
457                         ( r = strchr( p, ',' ) ) != NULL; 
458                         p = r + 1, i++ )
459                 ;
460
461         res = ch_calloc( sizeof( char ), strlen( s ) + 4 + 4*i + 1 );
462
463         strcpy( res, "(.*)" );
464         for ( i = 0, p = ( char * )s;
465                         ( r = strchr( p, ',' ) ) != NULL;
466                         p = r + 1 , i++ ) {
467                 strncat( res, p, r - p + 1 );
468                 strcat( res, "[ ]?" );
469
470                 if ( r[ 1 ] == ' ' ) {
471                         r++;
472                 }
473         }
474         strcat( res, p );
475
476         return res;
477 }
478
479 static char *
480 suffix_massage_patternize( const char *s, int normalize )
481 {
482         char *res;
483
484         res = ch_calloc( sizeof( char ), strlen( s ) + 3 );
485
486         sprintf( res, "%%1%s", s );
487
488         if ( normalize ) {
489                 char *out = dn_normalize( res + 2 );
490                 if ( out != res + 2 ) {
491                         strcpy( res + 2, out );
492                         free( out );
493                 }
494         }
495
496         return res;
497 }
498
499 int
500 suffix_massage_config( 
501                 struct rewrite_info *info,
502                 int argc,
503                 char **argv
504 )
505 {
506         char *rargv[ 5 ];
507
508         rargv[ 0 ] = "rewriteEngine";
509         rargv[ 1 ] = "on";
510         rargv[ 2 ] = NULL;
511         rewrite_parse( info, "<suffix massage>", 1, 2, rargv );
512
513         rargv[ 0 ] = "rewriteContext";
514         rargv[ 1 ] = "default";
515         rargv[ 2 ] = NULL;
516         rewrite_parse( info, "<suffix massage>", 2, 2, rargv );
517
518         rargv[ 0 ] = "rewriteRule";
519         rargv[ 1 ] = suffix_massage_regexize( argv[ 1 ] );
520         rargv[ 2 ] = suffix_massage_patternize( argv[ 2 ], 0 );
521         rargv[ 3 ] = ":";
522         rargv[ 4 ] = NULL;
523         rewrite_parse( info, "<suffix massage>", 3, 4, rargv );
524         ch_free( rargv[ 1 ] );
525         ch_free( rargv[ 2 ] );
526         
527         rargv[ 0 ] = "rewriteContext";
528         rargv[ 1 ] = "searchResult";
529         rargv[ 2 ] = NULL;
530         rewrite_parse( info, "<suffix massage>", 4, 2, rargv );
531         
532         rargv[ 0 ] = "rewriteRule";
533         rargv[ 1 ] = suffix_massage_regexize( argv[ 2 ] );
534         rargv[ 2 ] = suffix_massage_patternize( argv[ 1 ], 0 );
535         rargv[ 3 ] = ":";
536         rargv[ 4 ] = NULL;
537         rewrite_parse( info, "<suffix massage>", 5, 4, rargv );
538         ch_free( rargv[ 1 ] );
539         ch_free( rargv[ 2 ] );
540
541         /*
542          * the filter should be rewritten as
543          * 
544          * rewriteRule
545          *      "(.*)member=([^)]+),o=Foo Bar,[ ]?c=US(.*)"
546          *      "%1member=%2,dc=example,dc=com%3"
547          *
548          * where "o=Foo Bar, c=US" is the virtual naming context,
549          * and "dc=example, dc=com" is the real naming context
550          */
551         rargv[ 0 ] = "rewriteContext";
552         rargv[ 1 ] = "searchFilter";
553         rargv[ 2 ] = NULL;
554         rewrite_parse( info, "<suffix massage>", 6, 2, rargv );
555
556 #if 0 /*  matched is not normalized */
557         rargv[ 0 ] = "rewriteContext";
558         rargv[ 1 ] = "matchedDn";
559         rargv[ 2 ] = "alias";
560         rargv[ 3 ] = "searchResult";
561         rargv[ 4 ] = NULL;
562         rewrite_parse( info, "<suffix massage>", 7, 4, rargv );
563 #else /* normalize matched */
564         rargv[ 0 ] = "rewriteContext";
565         rargv[ 1 ] = "matchedDn";
566         rargv[ 2 ] = NULL;
567         rewrite_parse( info, "<suffix massage>", 7, 2, rargv );
568
569         rargv[ 0 ] = "rewriteRule";
570         rargv[ 1 ] = suffix_massage_regexize( argv[ 2 ] );
571         rargv[ 2 ] = suffix_massage_patternize( argv[ 1 ], 1 );
572         rargv[ 3 ] = ":";
573         rargv[ 4 ] = NULL;
574         rewrite_parse( info, "<suffix massage>", 8, 4, rargv );
575         ch_free( rargv[ 1 ] );
576         ch_free( rargv[ 2 ] );
577 #endif /* normalize matched */
578
579         return 0;
580 }
581 #endif /* ENABLE_REWRITE */
582