]> git.sur5r.net Git - openldap/blob - servers/slapd/back-meta/config.c
Added dnPretty2/dnNormalize2 using preallocated destination berval
[openldap] / servers / slapd / back-meta / config.c
1 /*
2  * Copyright 1998-2001 The OpenLDAP Foundation, All Rights Reserved.
3  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
4  *
5  * Copyright 2001, Pierangelo Masarati, All rights reserved. <ando@sys-net.it>
6  *
7  * This work has been developed to fulfill the requirements
8  * of SysNet s.n.c. <http:www.sys-net.it> and it has been donated
9  * to the OpenLDAP Foundation in the hope that it may be useful
10  * to the Open Source community, but WITHOUT ANY WARRANTY.
11  *
12  * Permission is granted to anyone to use this software for any purpose
13  * on any computer system, and to alter it and redistribute it, subject
14  * to the following restrictions:
15  *
16  * 1. The author and SysNet s.n.c. are not responsible for the consequences
17  *    of use of this software, no matter how awful, even if they arise from 
18  *    flaws in it.
19  *
20  * 2. The origin of this software must not be misrepresented, either by
21  *    explicit claim or by omission.  Since few users ever read sources,
22  *    credits should appear in the documentation.
23  *
24  * 3. Altered versions must be plainly marked as such, and must not be
25  *    misrepresented as being the original software.  Since few users
26  *    ever read sources, credits should appear in the documentation.
27  *    SysNet s.n.c. cannot be responsible for the consequences of the
28  *    alterations.
29  *
30  * 4. This notice may not be removed or altered.
31  *
32  *
33  * This software is based on the backend back-ldap, implemented
34  * by Howard Chu <hyc@highlandsun.com>, and modified by Mark Valence
35  * <kurash@sassafras.com>, Pierangelo Masarati <ando@sys-net.it> and other
36  * contributors. The contribution of the original software to the present
37  * implementation is acknowledged in this copyright statement.
38  *
39  * A special acknowledgement goes to Howard for the overall architecture
40  * (and for borrowing large pieces of code), and to Mark, who implemented
41  * from scratch the attribute/objectclass mapping.
42  *
43  * The original copyright statement follows.
44  *
45  * Copyright 1999, Howard Chu, All rights reserved. <hyc@highlandsun.com>
46  *
47  * Permission is granted to anyone to use this software for any purpose
48  * on any computer system, and to alter it and redistribute it, subject
49  * to the following restrictions:
50  *
51  * 1. The author is not responsible for the consequences of use of this
52  *    software, no matter how awful, even if they arise from flaws in it.
53  *
54  * 2. The origin of this software must not be misrepresented, either by
55  *    explicit claim or by omission.  Since few users ever read sources,
56  *    credits should appear in the documentation.
57  *
58  * 3. Altered versions must be plainly marked as such, and must not be
59  *    misrepresented as being the original software.  Since few users
60  *    ever read sources, credits should appear in the
61  *    documentation.
62  *
63  * 4. This notice may not be removed or altered.
64  *
65  */
66
67 #include "portable.h"
68
69 #include <stdio.h>
70
71 #include <ac/string.h>
72 #include <ac/socket.h>
73
74 #include "slap.h"
75 #include "../back-ldap/back-ldap.h"
76 #include "back-meta.h"
77
78 extern int
79 suffix_massage_config(
80                 struct rewrite_info *info,
81                 int argc,
82                 char **argv
83 );
84
85 static struct metatarget *
86 new_target( void )
87 {
88         struct metatarget *lt;
89         struct ldapmapping *mapping;
90
91         lt = ch_calloc( sizeof( struct metatarget ), 1 );
92         if ( lt == NULL ) {
93                 return NULL;
94         }
95
96         lt->rwinfo = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
97         if ( lt->rwinfo == NULL ) {
98                 free( lt );
99                 return NULL;
100         }
101
102         mapping = ch_calloc( 2, sizeof( struct ldapmapping ) );
103         if ( mapping == NULL ) {
104                 free( lt );
105                 return NULL;
106         }
107         mapping->src = ch_strdup( "objectClass" );
108         mapping->dst = ch_strdup( "objectClass" );
109         mapping[ 1 ].src = mapping->src;
110         mapping[ 1 ].dst = mapping->dst;
111
112         avl_insert( &lt->at_map.map, ( caddr_t )mapping, 
113                         mapping_cmp, mapping_dup );
114         avl_insert( &lt->at_map.remap, ( caddr_t )&mapping[ 1 ],
115                         mapping_cmp, mapping_dup );
116
117         return lt;
118 }
119
120 int
121 meta_back_db_config(
122                 BackendDB       *be,
123                 const char      *fname,
124                 int             lineno,
125                 int             argc,
126                 char            **argv
127 )
128 {
129         struct metainfo *li = ( struct metainfo * )be->be_private;
130
131         if ( li == NULL ) {
132                 fprintf( stderr, 
133         "%s: line %d: meta backend info is null!\n",
134                     fname, lineno );
135                 return 1;
136         }
137
138         /* URI of server to query */
139         if ( strcasecmp( argv[ 0 ], "uri" ) == 0 ) {
140                 int             i = li->ntargets;
141 #if 0
142                 int             j;
143 #endif /* uncomment if uri MUST be a branch of suffix */
144                 LDAPURLDesc     *ludp;
145                 char            *last;
146                 struct berval   dn, *pdn = NULL, *ndn = NULL;
147                 int             rc;
148                 
149                 if ( argc != 2 ) {
150                         fprintf( stderr,
151         "%s: line %d: missing address"
152         " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
153                                 fname, lineno );
154                         return 1;
155                 }
156                 
157                 ++li->ntargets;
158
159                 li->targets = ch_realloc( li->targets, 
160                         sizeof( struct metatarget *)*li->ntargets );
161                 if ( li->targets == NULL ) {
162                         fprintf( stderr,
163         "%s: line %d: out of memory while storing server name"
164         " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
165                                 fname, lineno );
166                         return 1;
167                 }
168
169                 if ( ( li->targets[ i ] = new_target() ) == NULL ) {
170                         fprintf( stderr,
171         "%s: line %d: unable to init server"
172         " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
173                                 fname, lineno );
174                         return 1;
175                 }
176
177                 /*
178                  * uri MUST be legal!
179                  */
180                 if ( ldap_url_parse( argv[ 1 ], &ludp ) != LDAP_SUCCESS ) {
181                         fprintf( stderr,
182         "%s: line %d: unable to parse URI"
183         " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
184                                 fname, lineno );
185                         return 1;
186                 }
187
188                 /*
189                  * uri MUST have the <dn> part!
190                  */
191                 if ( ludp->lud_dn == NULL || ludp->lud_dn[ 0 ] == '\0' ) {
192                         fprintf( stderr,
193         "%s: line %d: missing <naming context> "
194         " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
195                                 fname, lineno );
196                         return 1;
197                 }
198
199                 /*
200                  * copies and stores uri and suffix
201                  */
202                 dn.bv_val = ludp->lud_dn;
203                 dn.bv_len = strlen( ludp->lud_dn );
204
205                 rc = dnPrettyNormal( NULL, &dn, &li->targets[ i ]->psuffix,
206                         &li->targets[ i ]->suffix );
207                 if( rc != LDAP_SUCCESS ) {
208                         fprintf( stderr, "%s: line %d: "
209                                         "target '%s' DN is invalid\n",
210                                         fname, lineno, argv[ 1 ] );
211                         return( 1 );
212                 }
213
214                 li->targets[ i ]->uri = ch_strdup( argv[ 1 ] );
215                 last = strstr( li->targets[ i ]->uri, ludp->lud_dn );
216                 assert( last != NULL );
217                 last[ 0 ] = '\0';
218                 
219                 /*
220                  * uri MUST be a branch of suffix!
221                  */
222 #if 0 /* too strict a constraint */
223                 if ( select_backend( &li->targets[ i ]->suffix, 0, 0 ) != be ) {
224                         fprintf( stderr,
225         "%s: line %d: <naming context> of URI does not refer to current backend"
226         " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
227                                 fname, lineno );
228                         return 1;
229                 }
230 #else
231                 /*
232                  * uri MUST be a branch of a suffix!
233                  */
234                 if ( select_backend( &li->targets[ i ]->suffix, 0, 0 ) == NULL ) {
235                         fprintf( stderr,
236         "%s: line %d: <naming context> of URI does not resolve to a backend"
237         " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
238                                 fname, lineno );
239                         return 1;
240                 }
241 #endif
242
243 #if 0
244                 /*
245                  * uri MUST not be used by other URIs!
246                  *
247                  * FIXME: this limitation may be removed,
248                  * or worked out, at least, in some manner
249                  */
250                 for ( j = 0; j < i-1; j++ ) {
251                         if ( strcmp( li->targets[ i ]->suffix.bv_val,
252                                         li->targets[ j ]->suffix.bv_val ) == 0 ) {
253                                 fprintf( stderr,
254         "%s: line %d: naming context \"%s\" already used"
255         " in \"uri <protocol>://<server>[:port]/<naming context>\" line\n",
256                                         fname, lineno, last+1 );
257                                 return 1;
258                         }
259                 }
260 #endif
261                 
262                 ldap_free_urldesc( ludp );
263
264                 fprintf(stderr, "%s: line %d: URI \"%s\", suffix \"%s\"\n",
265                         fname, lineno, li->targets[ i ]->uri, 
266                         li->targets[ i ]->psuffix.bv_val );
267                 
268         /* default target directive */
269         } else if ( strcasecmp( argv[ 0 ], "default-target" ) == 0 ) {
270                 int             i = li->ntargets-1;
271                 
272                 if ( argc == 1 ) {
273                         if ( i < 0 ) {
274                                 fprintf( stderr,
275         "%s: line %d: \"default-target\" alone need be"
276         " inside a \"uri\" directive\n",
277                                         fname, lineno );
278                                 return 1;
279                         }
280                         li->defaulttarget = i;
281                 } else {
282                         if ( strcasecmp( argv[ 1 ], "none" ) == 0 ) {
283                                 if ( i >= 0 ) {
284                                         fprintf( stderr,
285         "%s: line %d: \"default-target none\""
286         " should go before uri definitions\n",
287                                                 fname, lineno );
288                                 }
289                                 li->defaulttarget = META_DEFAULT_TARGET_NONE;
290                         } else {
291                                 int n = atoi( argv[ 1 ] );
292                                 if ( n < 1 || n >= i ) {
293                                         fprintf( stderr,
294         "%s: line %d: illegal target number %d\n",
295                                                 fname, lineno, n );
296                                         return 1;
297                                 }
298                                 li->defaulttarget = n-1;
299                         }
300                 }
301                 
302         /* ttl of dn cache */
303         } else if ( strcasecmp( argv[ 0 ], "dncache-ttl" ) == 0 ) {
304                 if ( argc != 2 ) {
305                         fprintf( stderr,
306         "%s: line %d: missing ttl in \"dncache-ttl <ttl>\" line\n",
307                                 fname, lineno );
308                         return 1;
309                 }
310                 
311                 if ( strcasecmp( argv[ 1 ], "forever" ) == 0 ) {
312                         li->cache.ttl = META_DNCACHE_FOREVER;
313                 } else if ( strcasecmp( argv[ 1 ], "disabled" ) == 0 ) {
314                         li->cache.ttl = META_DNCACHE_DISABLED;
315                 } else {
316                         li->cache.ttl = atol( argv[ 1 ] );
317                 }
318
319         /* name to use for meta_back_group */
320         } else if ( strcasecmp( argv[ 0 ], "binddn" ) == 0 ) {
321                 int             i = li->ntargets-1;
322                 struct berval   dn, *ndn = NULL;
323
324                 if ( i < 0 ) {
325                         fprintf( stderr,
326         "%s: line %d: need \"uri\" directive first\n",
327                                 fname, lineno );
328                 }
329                 
330                 if ( argc != 2 ) {
331                         fprintf( stderr,
332         "%s: line %d: missing name in \"binddn <name>\" line\n",
333                                 fname, lineno );
334                         return 1;
335                 }
336
337                 dn.bv_val = argv[ 1 ];
338                 dn.bv_len = strlen( argv[ 1 ] );
339                 if ( dnNormalize2( NULL, &dn, &li->targets[ i ]->binddn ) != LDAP_SUCCESS ) {
340                         fprintf( stderr, "%s: line %d: "
341                                         "bind DN '%s' is invalid\n",
342                                         fname, lineno, argv[ 1 ] );
343                         return( 1 );
344                 }
345
346         /* password to use for meta_back_group */
347         } else if ( strcasecmp( argv[ 0 ], "bindpw" ) == 0 ) {
348                 int             i = li->ntargets-1;
349
350                 if ( i < 0 ) {
351                         fprintf( stderr,
352         "%s: line %d: need \"uri\" directive first\n",
353                                 fname, lineno );
354                 }
355                 
356                 if ( argc != 2 ) {
357                         fprintf( stderr,
358         "%s: line %d: missing password in \"bindpw <password>\" line\n",
359                             fname, lineno );
360                         return 1;
361                 }
362                 li->targets[ i ]->bindpw = ber_bvstrdup( argv[ 1 ] );
363                 
364         /* name to use as pseudo-root dn */
365         } else if ( strcasecmp( argv[ 0 ], "pseudorootdn" ) == 0 ) {
366                 int             i = li->ntargets-1;
367                 struct berval   dn, *ndn = NULL;
368
369                 if ( i < 0 ) {
370                         fprintf( stderr,
371         "%s: line %d: need \"uri\" directive first\n",
372                                 fname, lineno );
373                 }
374                 
375                 if ( argc != 2 ) {
376                         fprintf( stderr,
377         "%s: line %d: missing name in \"pseudorootdn <name>\" line\n",
378                                 fname, lineno );
379                         return 1;
380                 }
381
382                 dn.bv_val = argv[ 1 ];
383                 dn.bv_len = strlen( argv[ 1 ] );
384                 if ( dnNormalize2( NULL, &dn, &li->targets[ i ]->pseudorootdn ) != LDAP_SUCCESS ) {
385                         fprintf( stderr, "%s: line %d: "
386                                         "pseudoroot DN '%s' is invalid\n",
387                                         fname, lineno, argv[ 1 ] );
388                         return( 1 );
389                 }
390
391         /* password to use as pseudo-root */
392         } else if ( strcasecmp( argv[ 0 ], "pseudorootpw" ) == 0 ) {
393                 int             i = li->ntargets-1;
394
395                 if ( i < 0 ) {
396                         fprintf( stderr,
397         "%s: line %d: need \"uri\" directive first\n",
398                                 fname, lineno );
399                 }
400                 
401                 if ( argc != 2 ) {
402                         fprintf( stderr,
403         "%s: line %d: missing password in \"pseudorootpw <password>\" line\n",
404                             fname, lineno );
405                         return 1;
406                 }
407                 li->targets[ i ]->pseudorootpw = ber_bvstrdup( argv[ 1 ] );
408         
409         /* dn massaging */
410         } else if ( strcasecmp( argv[ 0 ], "suffixmassage" ) == 0 ) {
411                 BackendDB       *tmp_be;
412                 int             i = li->ntargets-1;
413                 struct berval   dn, ndn;
414
415                 if ( i < 0 ) {
416                         fprintf( stderr,
417         "%s: line %d: need \"uri\" directive first\n",
418                                 fname, lineno );
419                         return 1;
420                 }
421                 
422                 /*
423                  * syntax:
424                  * 
425                  *      suffixmassage <suffix> <massaged suffix>
426                  *
427                  * the <suffix> field must be defined as a valid suffix
428                  * (or suffixAlias?) for the current database;
429                  * the <massaged suffix> shouldn't have already been
430                  * defined as a valid suffix or suffixAlias for the 
431                  * current server
432                  */
433                 if ( argc != 3 ) {
434                         fprintf( stderr,
435         "%s: line %d: syntax is \"suffixMassage <suffix> <massaged suffix>\"\n",
436                                 fname, lineno );
437                         return 1;
438                 }
439
440                 dn.bv_val = argv[ 1 ];
441                 dn.bv_len = strlen( argv[ 1 ] );
442                 if ( dnNormalize2( NULL, &dn, &ndn ) != LDAP_SUCCESS ) {
443                         fprintf( stderr, "%s: line %d: "
444                                         "suffix '%s' is invalid\n",
445                                         fname, lineno, argv[ 1 ] );
446                         return 1;
447                 }
448                 
449                 tmp_be = select_backend( &ndn, 0, 0 );
450                 free( ndn.bv_val );
451                 if ( tmp_be != NULL && tmp_be != be ) {
452                         fprintf( stderr, 
453         "%s: line %d: suffix already in use by another backend in"
454         " \"suffixMassage <suffix> <massaged suffix>\"\n",
455                                 fname, lineno );
456                         return 1;                                               
457                 }
458
459                 dn.bv_val = argv[ 2 ];
460                 dn.bv_len = strlen( argv[ 2 ] );
461                 if ( dnNormalize2( NULL, &dn, &ndn ) != LDAP_SUCCESS ) {
462                         fprintf( stderr, "%s: line %d: "
463                                         "massaged suffix '%s' is invalid\n",
464                                         fname, lineno, argv[ 2 ] );
465                         return 1;
466                 }
467                 
468                 tmp_be = select_backend( &ndn, 0, 0 );
469                 free( ndn.bv_val );
470                 if ( tmp_be != NULL ) {
471                         fprintf( stderr,
472         "%s: line %d: massaged suffix already in use by another backend in" 
473         " \"suffixMassage <suffix> <massaged suffix>\"\n",
474                                 fname, lineno );
475                         return 1;
476                 }
477                 
478                 /*
479                  * The suffix massaging is emulated by means of the
480                  * rewrite capabilities
481                  * FIXME: no extra rewrite capabilities should be added
482                  * to the database
483                  */
484                 return suffix_massage_config( li->targets[ i ]->rwinfo,
485                                 argc, argv );
486                 
487         /* rewrite stuff ... */
488         } else if ( strncasecmp( argv[ 0 ], "rewrite", 7 ) == 0 ) {
489                 int             i = li->ntargets-1;
490
491                 if ( i < 0 ) {
492                         fprintf( stderr,
493         "%s: line %d: need \"uri\" directive first\n",
494                                 fname, lineno );
495                 }
496                 
497                 return rewrite_parse( li->targets[ i ]->rwinfo, fname, lineno,
498                                 argc, argv );
499
500         /* objectclass/attribute mapping */
501         } else if ( strcasecmp( argv[ 0 ], "map" ) == 0 ) {
502                 struct ldapmap *map;
503                 struct ldapmapping *mapping;
504                 char *src, *dst;
505                 int             i = li->ntargets-1;
506
507                 if ( i < 0 ) {
508                         fprintf( stderr,
509         "%s: line %d: need \"uri\" directive first\n",
510                                 fname, lineno );
511                 }
512                 
513
514                 if ( argc < 3 || argc > 4 ) {
515                         fprintf( stderr,
516         "%s: line %d: syntax is \"map {objectclass | attribute} {<source> | *} [<dest> | *]\"\n",
517                                 fname, lineno );
518                         return 1;
519                 }
520
521                 if ( strcasecmp( argv[ 1 ], "objectClass" ) == 0 ) {
522                         map = &li->targets[ i ]->oc_map;
523                 } else if ( strcasecmp( argv[ 1 ], "attribute" ) == 0 ) {
524                         map = &li->targets[ i ]->at_map;
525                 } else {
526                         fprintf( stderr,
527         "%s: line %d: syntax is \"map {objectclass | attribute} {<source> | *} [<dest> | *]\"\n",
528                                 fname, lineno );
529                         return 1;
530                 }
531
532                 if ( strcasecmp( argv[ 2 ], "*" ) != 0 ) {
533                         src = argv[ 2 ];
534                         if ( argc < 4 ) {
535                                 dst = "";
536                         } else if ( strcasecmp( argv[ 3 ], "*" ) == 0 ) {
537                                 dst = src;
538                         } else {
539                                 dst = argv[ 3 ];
540                         }
541                 } else {
542                         if ( argc < 4 ) {
543                                 map->drop_missing = 1;
544                                 return 0;
545                         }
546                         if ( strcasecmp( argv[ 3 ], "*" ) == 0 ) {
547                                 map->drop_missing = 0;
548                                 return 0;
549                         }
550
551                         src = argv[ 3 ];
552                         dst = src;
553                 }
554
555                 if ( ( map == &li->targets[ i ]->at_map )
556                         && ( strcasecmp( src, "objectclass" ) == 0
557                                 || strcasecmp( dst, "objectclass" ) == 0 ) ) {
558                         fprintf( stderr,
559         "%s: line %d: objectclass attribute cannot be mapped\n",
560                                 fname, lineno );
561                 }
562
563                 mapping = ch_calloc( 2, sizeof( struct ldapmapping ) );
564                 if ( mapping == NULL ) {
565                         fprintf( stderr,
566                                 "%s: line %d: out of memory\n",
567                                 fname, lineno );
568                         return 1;
569                 }
570                 mapping->src = ch_strdup( src );
571                 mapping->dst = ch_strdup( dst );
572                 if ( *dst != 0 ) {
573                         mapping[ 1 ].src = mapping->dst;
574                         mapping[ 1 ].dst = mapping->src;
575                 } else {
576                         mapping[ 1 ].src = mapping->src;
577                         mapping[ 1 ].dst = mapping->dst;
578                 }
579
580                 if ( avl_find( map->map, ( caddr_t )mapping,
581                                 mapping_cmp ) != NULL
582                         || avl_find( map->remap, ( caddr_t )&mapping[ 1 ],
583                                 mapping_cmp ) != NULL) {
584                         fprintf( stderr,
585         "%s: line %d: duplicate mapping found (ignored)\n",
586                                 fname, lineno );
587                         return 0;
588                 }
589
590                 avl_insert( &map->map, ( caddr_t )mapping,
591                                         mapping_cmp, mapping_dup );
592                 avl_insert( &map->remap, ( caddr_t )&mapping[ 1 ],
593                                         mapping_cmp, mapping_dup );
594
595         /* anything else */
596         } else {
597                 fprintf( stderr,
598         "%s: line %d: unknown directive \"%s\" in meta database definition"
599         " (ignored)\n",
600                     fname, lineno, argv[0] );
601         }
602         return 0;
603 }
604