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