]> git.sur5r.net Git - openldap/blob - libraries/libldap/dn.c
7e77493806aa96dfc30391942dbc44260bb55955
[openldap] / libraries / libldap / 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-int.h"
17
18 #define B4LEADTYPE              0
19 #define B4TYPE                  1
20 #define INOIDTYPE               2
21 #define INKEYTYPE               3
22 #define B4EQUAL                 4
23 #define B4VALUE                 5
24 #define INVALUE                 6
25 #define INQUOTEDVALUE   7
26 #define B4SEPARATOR             8
27
28 /*
29  * ldap_dn_normalize - put dn into a canonical format
30  * and return it.
31  */
32
33 char *
34 ldap_dn_normalize( const char *dn )
35 {
36         char    *d, *s;
37         int     state, gotesc;
38         char *ndn;
39
40         if( dn == NULL ) {
41                 return NULL;
42         }
43
44         ndn = LDAP_STRDUP( dn );
45
46         if( ndn == NULL ) {
47                 return NULL;
48         }
49
50         gotesc = 0;
51         state = B4LEADTYPE;
52         for ( d = s = ndn; *s; s++ ) {
53                 switch ( state ) {
54                 case B4LEADTYPE:
55                 case B4TYPE:
56                         if ( LDAP_LEADOIDCHAR(*s) ) {
57                                 state = INOIDTYPE;
58                                 *d++ = *s;
59                         } else if ( LDAP_LEADKEYCHAR(*s) ) {
60                                 state = INKEYTYPE;
61                                 *d++ = *s;
62                         } else if ( ! LDAP_SPACE( *s ) ) {
63                                 dn = NULL;
64                                 state = INKEYTYPE;
65                                 *d++ = *s;
66                         }
67                         break;
68
69                 case INOIDTYPE:
70                         if ( LDAP_OIDCHAR(*s) ) {
71                                 *d++ = *s;
72                         } else if ( *s == '=' ) {
73                                 state = B4VALUE;
74                                 *d++ = *s;
75                         } else if ( LDAP_SPACE( *s ) ) {
76                                 state = B4EQUAL;
77                         } else {
78                                 dn = NULL;
79                                 *d++ = *s;
80                         }
81                         break;
82
83                 case INKEYTYPE:
84                         if ( LDAP_KEYCHAR(*s) ) {
85                                 *d++ = *s;
86                         } else if ( *s == '=' ) {
87                                 state = B4VALUE;
88                                 *d++ = *s;
89                         } else if ( LDAP_SPACE( *s ) ) {
90                                 state = B4EQUAL;
91                         } else {
92                                 dn = NULL;
93                                 *d++ = *s;
94                         }
95                         break;
96
97                 case B4EQUAL:
98                         if ( *s == '=' ) {
99                                 state = B4VALUE;
100                                 *d++ = *s;
101                         } else if ( ! LDAP_SPACE( *s ) ) {
102                                 /* not a valid dn - but what can we do here? */
103                                 *d++ = *s;
104                                 dn = NULL;
105                         }
106                         break;
107
108                 case B4VALUE:
109                         if ( *s == '"' ) {
110                                 state = INQUOTEDVALUE;
111                                 *d++ = *s;
112                         } else if ( ! LDAP_SPACE( *s ) ) { 
113                                 state = INVALUE;
114                                 *d++ = *s;
115                         }
116                         break;
117
118                 case INVALUE:
119                         if ( !gotesc && LDAP_SEPARATOR( *s ) ) {
120                                 while ( LDAP_SPACE( *(d - 1) ) )
121                                         d--;
122                                 state = B4TYPE;
123                                 if ( *s == '+' ) {
124                                         *d++ = *s;
125                                 } else {
126                                         *d++ = ',';
127                                 }
128                         } else if ( gotesc && !LDAP_NEEDSESCAPE( *s ) &&
129                             !LDAP_SEPARATOR( *s ) ) {
130                                 *--d = *s;
131                                 d++;
132                         } else {
133                                 *d++ = *s;
134                         }
135                         break;
136
137                 case INQUOTEDVALUE:
138                         if ( !gotesc && *s == '"' ) {
139                                 state = B4SEPARATOR;
140                                 *d++ = *s;
141                         } else if ( gotesc && !LDAP_NEEDSESCAPE( *s ) ) {
142                                 *--d = *s;
143                                 d++;
144                         } else {
145                                 *d++ = *s;
146                         }
147                         break;
148                 case B4SEPARATOR:
149                         if ( LDAP_SEPARATOR( *s ) ) {
150                                 state = B4TYPE;
151                                 *d++ = *s;
152                         }
153                         break;
154                 default:
155                         dn = NULL;
156                         Debug( LDAP_DEBUG_ANY,
157                             "dn_normalize - unknown state %d\n", state, 0, 0 );
158                         break;
159                 }
160                 if ( *s == '\\' ) {
161                         gotesc = 1;
162                 } else {
163                         gotesc = 0;
164                 }
165         }
166         *d = '\0';
167
168         if( gotesc ) {
169                 /* shouldn't be left in escape */
170                 dn = NULL;
171         }
172
173         /* check end state */
174         switch( state ) {
175         case B4LEADTYPE:        /* looking for first type */
176         case B4SEPARATOR:       /* looking for separator */
177         case INVALUE:           /* inside value */
178                 break;
179         default:
180                 dn = NULL;
181         }
182
183         if( dn == NULL ) {
184                 return( ndn );
185                 ndn = NULL;
186         }
187
188         return( ndn );
189 }
190
191 /*
192  * ldap_dn_parent - return a copy of the dn of dn's parent
193  */
194
195 char *
196 ldap_dn_parent(
197     const char *dn
198 )
199 {
200         const char      *s;
201         int     inquote;
202
203         if( dn == NULL ) {
204                 return NULL;
205         }
206
207         while(*dn && LDAP_SPACE(*dn)) {
208                 dn++;
209         }
210
211         if( *dn == '\0' ) {
212                 return( NULL );
213         }
214
215         /*
216          * no =, assume it is a dns name, like blah@some.domain.name
217          * if the blah@ part is there, return some.domain.name.  if
218          * it's just some.domain.name, return domain.name.
219          */
220         if ( strchr( dn, '=' ) == NULL ) {
221                 if ( (s = strchr( dn, '@' )) == NULL ) {
222                         if ( (s = strchr( dn, '.' )) == NULL ) {
223                                 return( NULL );
224                         }
225                 }
226                 if ( *(s + 1) == '\0' ) {
227                         return( NULL );
228                 } else {
229                         return( LDAP_STRDUP( &s[1] ) );
230                 }
231         }
232
233         /*
234          * else assume it is an X.500-style name, which looks like
235          * foo=bar,sha=baz,...
236          */
237
238         inquote = 0;
239         for ( s = dn; *s; s++ ) {
240                 if ( *s == '\\' ) {
241                         if ( *(s + 1) ) {
242                                 s++;
243                         }
244                         continue;
245                 }
246                 if ( inquote ) {
247                         if ( *s == '"' ) {
248                                 inquote = 0;
249                         }
250                 } else {
251                         if ( *s == '"' ) {
252                                 inquote = 1;
253                         } else if ( LDAP_DNSEPARATOR( *s ) ) {
254                                 return( LDAP_STRDUP( &s[1] ) );
255                         }
256                 }
257         }
258
259         return( LDAP_STRDUP( "" ) );
260 }
261
262 char * ldap_dn_rdn( 
263     const char  *dn )
264 {
265         char    *s;
266         char    *rdn;
267         int     inquote;
268
269         if( dn == NULL ) {
270                 return NULL;
271         }
272
273         while(*dn && LDAP_SPACE(*dn)) {
274                 dn++;
275         }
276
277         if( *dn == '\0' ) {
278                 return( NULL );
279         }
280
281         rdn = LDAP_STRDUP( dn );
282
283         if( rdn == NULL ) {
284                 return NULL;
285         }
286
287 #ifdef DNS_DN
288         /*
289          * no =, assume it is a dns name, like blah@some.domain.name
290          * if the blah@ part is there, return some.domain.name.  if
291          * it's just some.domain.name, return domain.name.
292          */
293         if ( strchr( rdn, '=' ) == NULL ) {
294                 if ( (s = strchr( rdn, '@' )) == NULL ) {
295                         if ( (s = strchr( rdn, '.' )) == NULL ) {
296                                 return( rdn );
297                         }
298                 }
299                 *s = '\0';
300                 return( rdn );
301         }
302 #endif
303
304         /*
305          * else assume it is an X.500-style name, which looks like
306          * foo=bar,sha=baz,...
307          */
308
309         inquote = 0;
310
311         for ( s = rdn; *s; s++ ) {
312                 if ( *s == '\\' ) {
313                         if ( *(s + 1) ) {
314                                 s++;
315                         }
316                         continue;
317                 }
318                 if ( inquote ) {
319                         if ( *s == '"' ) {
320                                 inquote = 0;
321                         }
322                 } else {
323                         if ( *s == '"' ) {
324                                 inquote = 1;
325                         } else if ( LDAP_DNSEPARATOR( *s ) ) {
326                                 *s = '\0';
327                                 return( rdn );
328                         }
329                 }
330         }
331
332         return( rdn );
333 }