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