]> git.sur5r.net Git - openldap/blob - servers/slapd/dn.c
1d106206a09b0c97a9b998ca7042c5b780480aa1
[openldap] / servers / slapd / dn.c
1 /* dn.c - routines for dealing with distinguished names */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11
12 #include <ac/ctype.h>
13 #include <ac/socket.h>
14 #include <ac/string.h>
15 #include <ac/time.h>
16
17 #include "ldap_pvt.h"
18
19 #include "slap.h"
20
21 #define B4LEADTYPE              0
22 #define B4TYPE                  1
23 #define INOIDTYPE               2
24 #define INKEYTYPE               3
25 #define B4EQUAL                 4
26 #define B4VALUE                 5
27 #define INVALUE                 6
28 #define INQUOTEDVALUE   7
29 #define B4SEPARATOR             8
30
31 /*
32  * dn_validate - validate and compress dn.  the dn is
33  * compressed in place are returned if valid.
34  */
35
36 char *
37 dn_validate( char *dn_in )
38 {
39 #ifdef USE_LDAP_DN_PARSING
40         struct berval   val, *normalized;
41         int             rc;
42
43         fprintf(stderr, ">>> dn_validate: %s\n", dn_in);
44
45         if ( dn_in == NULL || dn_in[ 0 ] == '\0' ) {
46                 return( dn_in );
47         }
48
49         val.bv_val = dn_in;
50         val.bv_len = strlen( dn_in );
51
52         rc = dnPretty( NULL, &val, &normalized );
53         if ( rc != LDAP_SUCCESS ) {
54                 return( NULL );
55         }
56
57         if ( val.bv_len < normalized->bv_len ) {
58                 ber_bvfree( normalized );
59                 return( NULL );
60         }
61
62         AC_MEMCPY( dn_in, normalized->bv_val, normalized->bv_len + 1 );
63         ber_bvfree( normalized );
64
65         fprintf(stderr, "<<< dn_validate: %s\n", dn_in);
66
67         return( dn_in );
68         
69 #else /* !USE_LDAP_DN_PARSING */
70         char    *d, *s;
71         int     state, gotesc;
72         char    *dn = dn_in;
73
74         gotesc = 0;
75         state = B4LEADTYPE;
76         for ( d = s = dn; *s; s++ ) {
77                 switch ( state ) {
78                 case B4LEADTYPE:
79                 case B4TYPE:
80                         if ( OID_LEADCHAR(*s) ) {
81                                 state = INOIDTYPE;
82                                 *d++ = *s;
83                         } else if ( ATTR_LEADCHAR(*s) ) {
84                                 state = INKEYTYPE;
85                                 *d++ = *s;
86                         } else if ( ! ASCII_SPACE( *s ) ) {
87                                 dn = NULL;
88                                 state = INKEYTYPE;
89                                 *d++ = *s;
90                         }
91                         break;
92
93                 case INOIDTYPE:
94                         if ( OID_CHAR(*s) ) {
95                                 *d++ = *s;
96                         } else if ( *s == '=' ) {
97                                 state = B4VALUE;
98                                 *d++ = *s;
99                         } else if ( ASCII_SPACE( *s ) ) {
100                                 state = B4EQUAL;
101                         } else {
102                                 dn = NULL;
103                                 *d++ = *s;
104                         }
105                         break;
106
107                 case INKEYTYPE:
108                         if ( ATTR_CHAR(*s) ) {
109                                 *d++ = *s;
110                         } else if ( *s == '=' ) {
111                                 state = B4VALUE;
112                                 *d++ = *s;
113                         } else if ( ASCII_SPACE( *s ) ) {
114                                 state = B4EQUAL;
115                         } else {
116                                 dn = NULL;
117                                 *d++ = *s;
118                         }
119                         break;
120
121                 case B4EQUAL:
122                         if ( *s == '=' ) {
123                                 state = B4VALUE;
124                                 *d++ = *s;
125                         } else if ( ! ASCII_SPACE( *s ) ) {
126                                 /* not a valid dn - but what can we do here? */
127                                 *d++ = *s;
128                                 dn = NULL;
129                         }
130                         break;
131
132                 case B4VALUE:
133                         if ( *s == '"' ) {
134                                 state = INQUOTEDVALUE;
135                                 *d++ = *s;
136                         } else if ( ! ASCII_SPACE( *s ) ) {
137                                 state = INVALUE;
138                                 *d++ = *s;
139                         }
140                         break;
141
142                 case INVALUE:
143                         if ( !gotesc && RDN_SEPARATOR( *s ) ) {
144                                 while ( ASCII_SPACE( *(d - 1) ) )
145                                         d--;
146                                 state = B4TYPE;
147                                 if ( *s == '+' ) {
148                                         *d++ = *s;
149                                 } else {
150                                         *d++ = ',';
151                                 }
152                         } else if ( gotesc && !RDN_NEEDSESCAPE( *s ) &&
153                                 !RDN_SEPARATOR( *s ) )
154                         {
155                                 *--d = *s;
156                                 d++;
157                         } else if( !ASCII_SPACE( *s ) || !ASCII_SPACE( *(d - 1) ) ) {
158                                 *d++ = *s;
159                         }
160                         break;
161
162                 case INQUOTEDVALUE:
163                         if ( !gotesc && *s == '"' ) {
164                                 state = B4SEPARATOR;
165                                 *d++ = *s;
166                         } else if ( gotesc && !RDN_NEEDSESCAPE( *s ) ) {
167                                 *--d = *s;
168                                 d++;
169                         } else if( !ASCII_SPACE( *s ) || !ASCII_SPACE( *(d - 1) ) ) {
170                                 *d++ = *s;
171                         }
172                         break;
173
174                 case B4SEPARATOR:
175                         if ( RDN_SEPARATOR( *s ) ) {
176                                 state = B4TYPE;
177                                 *d++ = *s;
178                         } else if ( !ASCII_SPACE( *s ) ) {
179                                 dn = NULL;
180                         }
181                         break;
182
183                 default:
184                         dn = NULL;
185 #ifdef NEW_LOGGING
186                         LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
187                                 "dn_validate: unknown state %d for dn \"%s\".\n",
188                                 state, dn_in ));
189 #else
190                         Debug( LDAP_DEBUG_ANY,
191                                 "dn_validate - unknown state %d\n", state, 0, 0 );
192 #endif
193                         break;
194                 }
195
196                 if ( *s == '\\' ) {
197                         gotesc = 1;
198                 } else {
199                         gotesc = 0;
200                 }
201         }
202
203         /* trim trailing spaces */
204         while( d > dn_in && ASCII_SPACE( *(d-1) ) ) {
205                 --d;
206         }
207         *d = '\0';
208
209         if( gotesc ) {
210                 /* shouldn't be left in escape */
211                 dn = NULL;
212         }
213
214         /* check end state */
215         switch( state ) {
216         case B4LEADTYPE:        /* looking for first type */
217         case B4SEPARATOR:       /* looking for separator */
218         case INVALUE:           /* inside value */
219                 break;
220         default:
221                 dn = NULL;
222         }
223
224         return( dn );
225 #endif /* !USE_LDAP_DN_PARSING */
226 }
227
228 /*
229  * dn_normalize - put dn into a canonical form suitable for storing
230  * in a hash database.  this involves normalizing the case as well as
231  * the format.  the dn is normalized in place as well as returned if valid.
232  */
233
234 char *
235 dn_normalize( char *dn )
236 {
237 #ifdef USE_LDAP_DN_PARSING
238         struct berval   val, *normalized;
239         int             rc;
240
241         fprintf(stderr, ">>> dn_normalize: %s\n", dn);
242
243         if ( dn == NULL || dn[ 0 ] == '\0' ) {
244                 return( dn );
245         }
246
247         val.bv_val = dn;
248         val.bv_len = strlen( dn );
249
250         rc = dnNormalize( NULL, &val, &normalized );
251         if ( rc != LDAP_SUCCESS ) {
252                 return( NULL );
253         }
254
255         if ( val.bv_len < normalized->bv_len ) {
256                 ber_bvfree( normalized );
257                 return( NULL );
258         }
259
260         AC_MEMCPY( dn, normalized->bv_val, normalized->bv_len + 1 );
261         ber_bvfree( normalized );
262
263         ( void )ldap_pvt_str2upper( dn );
264
265         fprintf(stderr, "<<< dn_normalize: %s\n", dn);
266
267         return( dn );
268         
269 #else /* !USE_LDAP_DN_PARSING */
270         char *out;
271         struct berval *bvdn, *nbvdn;
272
273         out = NULL;
274         bvdn = ber_bvstr( dn );
275         
276         if ( dnNormalize( NULL, bvdn, &nbvdn ) == LDAP_SUCCESS ) {
277                 if ( nbvdn->bv_len <= bvdn->bv_len ) {
278                         out = dn;
279                         strcpy( out, nbvdn->bv_val );
280                 }
281                 ber_bvfree( nbvdn );
282         }
283         bvdn->bv_val = NULL; /* prevent bvfree from freeing dn */
284         ber_bvfree( bvdn );
285
286         return( out );
287 #endif /* !USE_LDAP_DN_PARSING */
288 }
289
290 int
291 dn_match( const char *val, const char *asserted )
292 {
293         struct berval   bval, basserted;
294
295         if ( val == NULL || asserted == NULL ) {
296                 return 0;
297         }
298
299         bval.bv_val = ( char * )val;
300         bval.bv_len = strlen( val );
301
302         basserted.bv_val = ( char * )asserted;
303         basserted.bv_len = strlen( asserted);
304
305         return dnMatch( NULL, 0, NULL, NULL, &bval, &basserted);
306 }
307
308 /*
309  * dn_parent - return a copy of the dn of dn's parent
310  */
311
312 char *
313 dn_parent(
314         Backend *be,
315         const char      *dn
316 )
317 {
318         const char      *s;
319         int     inquote;
320
321         if( dn == NULL ) {
322                 return NULL;
323         }
324
325         while(*dn != '\0' && ASCII_SPACE(*dn)) {
326                 dn++;
327         }
328
329         if( *dn == '\0' ) {
330                 return NULL;
331         }
332
333         if ( be != NULL && be_issuffix( be, dn ) ) {
334                 return NULL;
335         }
336
337         /*
338          * assume it is an X.500-style name, which looks like
339          * foo=bar,sha=baz,...
340          */
341
342         inquote = 0;
343         for ( s = dn; *s; s++ ) {
344                 if ( *s == '\\' ) {
345                         if ( *(s + 1) ) {
346                                 s++;
347                         }
348                         continue;
349                 }
350                 if ( inquote ) {
351                         if ( *s == '"' ) {
352                                 inquote = 0;
353                         }
354                 } else {
355                         if ( *s == '"' ) {
356                                 inquote = 1;
357                         } else if ( DN_SEPARATOR( *s ) ) {
358                                 return ch_strdup( &s[1] );
359                         }
360                 }
361         }
362
363         return ch_strdup( "" );
364 }
365
366 char * dn_rdn(
367         Backend *be,
368         const char      *dn_in )
369 {
370         char    *dn, *s;
371         int     inquote;
372
373         if( dn_in == NULL ) {
374                 return NULL;
375         }
376
377         while(*dn_in && ASCII_SPACE(*dn_in)) {
378                 dn_in++;
379         }
380
381         if( *dn_in == '\0' ) {
382                 return( NULL );
383         }
384
385         if ( be != NULL && be_issuffix( be, dn_in ) ) {
386                 return( NULL );
387         }
388
389         dn = ch_strdup( dn_in );
390
391         inquote = 0;
392
393         for ( s = dn; *s; s++ ) {
394                 if ( *s == '\\' ) {
395                         if ( *(s + 1) ) {
396                                 s++;
397                         }
398                         continue;
399                 }
400                 if ( inquote ) {
401                         if ( *s == '"' ) {
402                                 inquote = 0;
403                         }
404                 } else {
405                         if ( *s == '"' ) {
406                                 inquote = 1;
407                         } else if ( DN_SEPARATOR( *s ) ) {
408                                 *s = '\0';
409                                 return( dn );
410                         }
411                 }
412         }
413
414         return( dn );
415 }
416
417
418 /*
419  * return a charray of all subtrees to which the DN resides in
420  */
421 char **dn_subtree(
422         Backend *be,
423         const char      *dn )
424 {
425         char *child, *parent;
426         char **subtree = NULL;
427         
428         child = ch_strdup( dn );
429
430         do {
431                 charray_add( &subtree, child );
432
433                 parent = dn_parent( be, child );
434
435                 free( child );
436
437                 child = parent;
438         } while ( child != NULL );
439
440         return subtree;
441 }
442
443
444 /*
445  * dn_issuffix - tells whether suffix is a suffix of dn. Both dn
446  * and suffix must be normalized.
447  */
448
449 int
450 dn_issuffix(
451         const char      *dn,
452         const char      *suffix
453 )
454 {
455         int     dnlen, suffixlen;
456
457         if ( dn == NULL ) {
458                 return( 0 );
459         }
460
461         suffixlen = strlen( suffix );
462         dnlen = strlen( dn );
463
464         if ( suffixlen > dnlen ) {
465                 return( 0 );
466         }
467
468         return( strcmp( dn + dnlen - suffixlen, suffix ) == 0 );
469 }
470
471 /*
472  * get_next_substring(), rdn_attr_type(), rdn_attr_value(), and
473  * build_new_dn().
474  *
475  * Copyright 1999, Juan C. Gomez, All rights reserved.
476  * This software is not subject to any license of Silicon Graphics
477  * Inc. or Purdue University.
478  *
479  * Redistribution and use in source and binary forms are permitted
480  * without restriction or fee of any kind as long as this notice
481  * is preserved.
482  *
483  */
484
485 /* get_next_substring:
486  *
487  * Gets next substring in s, using d (or the end of the string '\0') as a
488  * string delimiter, and places it in a duplicated memory space. Leading
489  * spaces are ignored. String s **must** be null-terminated.
490  */
491
492 static char *
493 get_next_substring( const char * s, char d )
494 {
495
496         char    *str, *r;
497
498         r = str = ch_malloc( strlen(s) + 1 );
499
500         /* Skip leading spaces */
501         
502         while ( *s && ASCII_SPACE(*s) ) {
503                 s++;
504         }
505         
506         /* Copy word */
507
508         while ( *s && (*s != d) ) {
509
510                 /* Don't stop when you see trailing spaces may be a multi-word
511                 * string, i.e. name=John Doe!
512                 */
513
514                 *str++ = *s++;
515         }
516         
517         *str = '\0';
518         
519         return r;
520         
521 }
522
523
524 /* rdn_attr_type:
525  *
526  * Given a string (i.e. an rdn) of the form:
527  *       "attribute_type = attribute_value"
528  * this function returns the type of an attribute, that is the
529  * string "attribute_type" which is placed in newly allocated
530  * memory. The returned string will be null-terminated.
531  */
532
533 char * rdn_attr_type( const char * s )
534 {
535         return get_next_substring( s, '=' );
536 }
537
538
539 /* rdn_attr_value:
540  *
541  * Given a string (i.e. an rdn) of the form:
542  *       "attribute_type = attribute_value"
543  * this function returns "attribute_type" which is placed in newly allocated
544  * memory. The returned string will be null-terminated and may contain
545  * spaces (i.e. "John Doe\0").
546  */
547
548 char *
549 rdn_attr_value( const char * rdn )
550 {
551
552         const char      *str;
553
554         if ( (str = strchr( rdn, '=' )) != NULL ) {
555                 return get_next_substring(++str, '\0');
556         }
557
558         return NULL;
559
560 }
561
562
563 /* rdn_attrs:
564  *
565  * Given a string (i.e. an rdn) of the form:
566  *   "attribute_type=attribute_value[+attribute_type=attribute_value[...]]"
567  * this function stores the types of the attributes in ptypes, that is the
568  * array of strings "attribute_type" which is placed in newly allocated
569  * memory, and the values of the attributes in pvalues, that is the
570  * array of strings "attribute_value" which is placed in newly allocated
571  * memory. Returns 0 on success, -1 on failure.
572  *
573  * note: got part of the code from dn_validate
574  */
575
576 int
577 rdn_attrs( const char * rdn_in, char ***ptypes, char ***pvalues)
578 {
579         char **parts, **p;
580
581         *ptypes = NULL;
582         *pvalues = NULL;
583
584         /*
585          * explode the rdn in parts
586          */
587         parts = ldap_explode_rdn( rdn_in, 0 );
588
589         if ( parts == NULL ) {
590                 return( -1 );
591         }
592
593         for ( p = parts; p[0]; p++ ) {
594                 char *s, *e, *d;
595                 
596                 /* split each rdn part in type value */
597                 s = strchr( p[0], '=' );
598                 if ( s == NULL ) {
599                         charray_free( *ptypes );
600                         charray_free( *pvalues );
601                         charray_free( parts );
602                         return( -1 );
603                 }
604                 
605                 /* type should be fine */
606                 charray_add_n( ptypes, p[0], ( s-p[0] ) );
607
608                 /* value needs to be unescaped
609                  * (maybe this should be moved to ldap_explode_rdn?) */
610                 for ( e = d = s + 1; e[0]; e++ ) {
611                         if ( *e != '\\' ) {
612                                 *d++ = *e;
613                         }
614                 }
615                 d[0] = '\0';
616                 charray_add( pvalues, s + 1 );
617         }
618
619         /* free array */
620         charray_free( parts );
621
622         return( 0 );
623 }
624
625
626 /* rdn_validate:
627  *
628  * 1 if rdn is a legal rdn;
629  * 0 otherwise (including a sequence of rdns)
630  *
631  * note: got it from dn_rdn; it should be rewritten
632  * according to dn_validate
633  */
634 int
635 rdn_validate( const char * rdn )
636 {
637         int     inquote;
638
639         if ( rdn == NULL ) {
640                 return( 0 );
641         }
642
643         if ( strchr( rdn, '=' ) == NULL ) {
644                 return( 0 );
645         }
646
647         while ( *rdn && ASCII_SPACE( *rdn ) ) {
648                 rdn++;
649         }
650
651         if( *rdn == '\0' ) {
652                 return( 0 );
653         }
654
655         inquote = 0;
656
657         for ( ; *rdn; rdn++ ) {
658                 if ( *rdn == '\\' ) {
659                         if ( *(rdn + 1) ) {
660                                 rdn++;
661                         }
662                         continue;
663                 }
664                 if ( inquote ) {
665                         if ( *rdn == '"' ) {
666                                 inquote = 0;
667                         }
668                 } else {
669                         if ( *rdn == '"' ) {
670                                 inquote = 1;
671                         } else if ( DN_SEPARATOR( *rdn ) ) {
672                                 return( 0 );
673                         }
674                 }
675         }
676
677         return( 1 );
678 }
679
680
681 /* build_new_dn:
682  *
683  * Used by ldbm/bdb2 back_modrdn to create the new dn of entries being
684  * renamed.
685  *
686  * new_dn = parent (p_dn) + separator(s) + rdn (newrdn) + null.
687  */
688
689 void
690 build_new_dn( char ** new_dn,
691         const char *e_dn,
692         const char * p_dn,
693         const char * newrdn )
694 {
695
696         if ( p_dn == NULL ) {
697                 *new_dn = ch_strdup( newrdn );
698                 return;
699         }
700
701         *new_dn = (char *) ch_malloc( strlen( p_dn ) + strlen( newrdn ) + 3 );
702
703         strcpy( *new_dn, newrdn );
704         strcat( *new_dn, "," );
705         strcat( *new_dn, p_dn );
706 }