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