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