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