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