]> git.sur5r.net Git - openldap/blob - servers/slapd/dn.c
Made add_values(), delete_values(), replace_values() so they can be used
[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         char    *s;
135
136         /* normalize format */
137         dn_normalize( dn );
138
139         /* normalize case */
140         for ( s = dn; *s; s++ ) {
141                 *s = TOUPPER( (unsigned char) *s );
142         }
143
144         return( dn );
145 }
146
147 /*
148  * dn_parent - return a copy of the dn of dn's parent
149  */
150
151 char *
152 dn_parent(
153     Backend     *be,
154     char        *dn
155 )
156 {
157         char    *s;
158         int     inquote, gotesc;
159
160         if( dn == NULL ) {
161                 return NULL;
162         }
163
164         while(*dn && SPACE(*dn)) {
165                 dn++;
166         }
167
168         if( *dn == '\0' ) {
169                 return( NULL );
170         }
171
172         if ( be_issuffix( be, dn ) ) {
173                 return( NULL );
174         }
175
176         /*
177          * no =, assume it is a dns name, like blah@some.domain.name
178          * if the blah@ part is there, return some.domain.name.  if
179          * it's just some.domain.name, return domain.name.
180          */
181         if ( strchr( dn, '=' ) == NULL ) {
182                 if ( (s = strchr( dn, '@' )) == NULL ) {
183                         if ( (s = strchr( dn, '.' )) == NULL ) {
184                                 return( NULL );
185                         }
186                 }
187                 if ( *(s + 1) == '\0' ) {
188                         return( NULL );
189                 } else {
190                         return( ch_strdup( &s[1] ) );
191                 }
192         }
193
194         /*
195          * else assume it is an X.500-style name, which looks like
196          * foo=bar,sha=baz,...
197          */
198
199         inquote = 0;
200         for ( s = dn; *s; s++ ) {
201                 if ( *s == '\\' ) {
202                         if ( *(s + 1) ) {
203                                 s++;
204                         }
205                         continue;
206                 }
207                 if ( inquote ) {
208                         if ( *s == '"' ) {
209                                 inquote = 0;
210                         }
211                 } else {
212                         if ( *s == '"' ) {
213                                 inquote = 1;
214                         } else if ( DNSEPARATOR( *s ) ) {
215                                 return( ch_strdup( &s[1] ) );
216                         }
217                 }
218         }
219
220         return( ch_strdup( "" ) );
221 }
222
223 char * dn_rdn( 
224     Backend     *be,
225     char        *dn )
226 {
227         char    *s;
228         int     inquote, gotesc;
229
230         if( dn == NULL ) {
231                 return NULL;
232         }
233
234         while(*dn && SPACE(*dn)) {
235                 dn++;
236         }
237
238         if( *dn == '\0' ) {
239                 return( NULL );
240         }
241
242         if ( be_issuffix( be, dn ) ) {
243                 return( NULL );
244         }
245
246         dn = ch_strdup( dn );
247
248         /*
249          * no =, assume it is a dns name, like blah@some.domain.name
250          * if the blah@ part is there, return some.domain.name.  if
251          * it's just some.domain.name, return domain.name.
252          */
253         if ( strchr( dn, '=' ) == NULL ) {
254                 if ( (s = strchr( dn, '@' )) == NULL ) {
255                         if ( (s = strchr( dn, '.' )) == NULL ) {
256                                 return( dn );
257                         }
258                 }
259                 *s = '\0';
260                 return( dn );
261         }
262
263         /*
264          * else assume it is an X.500-style name, which looks like
265          * foo=bar,sha=baz,...
266          */
267
268         inquote = 0;
269
270         for ( s = dn; *s; s++ ) {
271                 if ( *s == '\\' ) {
272                         if ( *(s + 1) ) {
273                                 s++;
274                         }
275                         continue;
276                 }
277                 if ( inquote ) {
278                         if ( *s == '"' ) {
279                                 inquote = 0;
280                         }
281                 } else {
282                         if ( *s == '"' ) {
283                                 inquote = 1;
284                         } else if ( DNSEPARATOR( *s ) ) {
285                                 *s = '\0';
286                                 return( dn );
287                         }
288                 }
289         }
290
291         return( dn );
292 }
293
294 /*
295  * dn_issuffix - tells whether suffix is a suffix of dn.  both dn
296  * and suffix must be normalized.
297  */
298
299 int
300 dn_issuffix(
301     char        *dn,
302     char        *suffix
303 )
304 {
305         int     dnlen, suffixlen;
306
307         if ( dn == NULL ) {
308                 return( 0 );
309         }
310
311         suffixlen = strlen( suffix );
312         dnlen = strlen( dn );
313
314         if ( suffixlen > dnlen ) {
315                 return( 0 );
316         }
317
318         return( strcmp( dn + dnlen - suffixlen, suffix ) == 0 );
319 }
320
321 /*
322  * dn_type - tells whether the given dn is an X.500 thing or DNS thing
323  * returns (defined in slap.h): DN_DNS          dns-style thing
324  *                              DN_X500         x500-style thing
325  */
326
327 int
328 dn_type( char *dn )
329 {
330         return( strchr( dn, '=' ) == NULL ? DN_DNS : DN_X500 );
331 }
332
333 char *
334 dn_upcase( char *dn )
335 {
336         char    *s;
337
338         /* normalize case */
339         for ( s = dn; *s; s++ ) {
340                 *s = TOUPPER( (unsigned char) *s );
341         }
342
343         return( dn );
344 }