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