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