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