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