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