]> git.sur5r.net Git - openldap/blob - servers/slapd/dn.c
include portable.h
[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 #include <ctype.h>
7 #include <string.h>
8 #include <sys/time.h>
9 #include <sys/types.h>
10 #include <sys/socket.h>
11 #include "slap.h"
12
13 static char     **dn_explode();
14
15 #define DNSEPARATOR(c)  (c == ',' || c == ';')
16 #define SEPARATOR(c)    (c == ',' || c == ';' || c == '+')
17 #define SPACE(c)        (c == ' ' || c == '\n')
18 #define NEEDSESCAPE(c)  (c == '\\' || c == '"')
19 #define B4TYPE          0
20 #define INTYPE          1
21 #define B4EQUAL         2
22 #define B4VALUE         3
23 #define INVALUE         4
24 #define INQUOTEDVALUE   5
25 #define B4SEPARATOR     6
26
27 /*
28  * dn_normalize - put dn into a canonical format.  the dn is
29  * normalized in place, as well as returned.
30  */
31
32 char *
33 dn_normalize( char *dn )
34 {
35         char    *d, *s;
36         int     state, gotesc;
37
38         /* Debug( LDAP_DEBUG_TRACE, "=> dn_normalize \"%s\"\n", dn, 0, 0 ); */
39
40         gotesc = 0;
41         state = B4TYPE;
42         for ( d = s = dn; *s; s++ ) {
43                 switch ( state ) {
44                 case B4TYPE:
45                         if ( ! SPACE( *s ) ) {
46                                 state = INTYPE;
47                                 *d++ = *s;
48                         }
49                         break;
50                 case INTYPE:
51                         if ( *s == '=' ) {
52                                 state = B4VALUE;
53                                 *d++ = *s;
54                         } else if ( SPACE( *s ) ) {
55                                 state = B4EQUAL;
56                         } else {
57                                 *d++ = *s;
58                         }
59                         break;
60                 case B4EQUAL:
61                         if ( *s == '=' ) {
62                                 state = B4VALUE;
63                                 *d++ = *s;
64                         } else if ( ! SPACE( *s ) ) {
65                                 /* not a valid dn - but what can we do here? */
66                                 *d++ = *s;
67                         }
68                         break;
69                 case B4VALUE:
70                         if ( *s == '"' ) {
71                                 state = INQUOTEDVALUE;
72                                 *d++ = *s;
73                         } else if ( ! SPACE( *s ) ) { 
74                                 state = INVALUE;
75                                 *d++ = *s;
76                         }
77                         break;
78                 case INVALUE:
79                         if ( !gotesc && SEPARATOR( *s ) ) {
80                                 while ( SPACE( *(d - 1) ) )
81                                         d--;
82                                 state = B4TYPE;
83                                 if ( *s == '+' ) {
84                                         *d++ = *s;
85                                 } else {
86                                         *d++ = ',';
87                                 }
88                         } else if ( gotesc && !NEEDSESCAPE( *s ) &&
89                             !SEPARATOR( *s ) ) {
90                                 *--d = *s;
91                                 d++;
92                         } else {
93                                 *d++ = *s;
94                         }
95                         break;
96                 case INQUOTEDVALUE:
97                         if ( !gotesc && *s == '"' ) {
98                                 state = B4SEPARATOR;
99                                 *d++ = *s;
100                         } else if ( gotesc && !NEEDSESCAPE( *s ) ) {
101                                 *--d = *s;
102                                 d++;
103                         } else {
104                                 *d++ = *s;
105                         }
106                         break;
107                 case B4SEPARATOR:
108                         if ( SEPARATOR( *s ) ) {
109                                 state = B4TYPE;
110                                 *d++ = *s;
111                         }
112                         break;
113                 default:
114                         Debug( LDAP_DEBUG_ANY,
115                             "dn_normalize - unknown state %d\n", state, 0, 0 );
116                         break;
117                 }
118                 if ( *s == '\\' ) {
119                         gotesc = 1;
120                 } else {
121                         gotesc = 0;
122                 }
123         }
124         *d = '\0';
125
126         /* Debug( LDAP_DEBUG_TRACE, "<= dn_normalize \"%s\"\n", dn, 0, 0 ); */
127         return( dn );
128 }
129
130 /*
131  * dn_normalize_case - put dn into a canonical form suitable for storing
132  * in a hash database.  this involves normalizing the case as well as
133  * the format.  the dn is normalized in place as well as returned.
134  */
135
136 char *
137 dn_normalize_case( char *dn )
138 {
139         char    *s;
140
141         /* normalize format */
142         dn_normalize( dn );
143
144         /* normalize case */
145         for ( s = dn; *s; s++ ) {
146                 *s = TOUPPER( *s );
147         }
148
149         return( dn );
150 }
151
152 /*
153  * dn_parent - return a copy of the dn of dn's parent
154  */
155
156 char *
157 dn_parent(
158     Backend     *be,
159     char        *dn
160 )
161 {
162         char    *s;
163         int     inquote, gotesc;
164
165         if ( dn == NULL || *dn == '\0' || be_issuffix( be, dn ) ) {
166                 return( NULL );
167         }
168
169         /*
170          * no =, assume it is a dns name, like blah@some.domain.name
171          * if the blah@ part is there, return some.domain.name.  if
172          * it's just some.domain.name, return domain.name.
173          */
174         if ( strchr( dn, '=' ) == NULL ) {
175                 if ( (s = strchr( dn, '@' )) == NULL ) {
176                         if ( (s = strchr( dn, '.' )) == NULL ) {
177                                 return( NULL );
178                         }
179                 }
180                 if ( *(s + 1) == '\0' ) {
181                         return( NULL );
182                 } else {
183                         return( strdup( s + 1 ) );
184                 }
185         }
186
187         /*
188          * else assume it is an X.500-style name, which looks like
189          * foo=bar,sha=baz,...
190          */
191
192         inquote = 0;
193         for ( s = dn; *s; s++ ) {
194                 if ( *s == '\\' ) {
195                         if ( *(s + 1) )
196                                 s++;
197                         continue;
198                 }
199                 if ( inquote ) {
200                         if ( *s == '"' )
201                                 inquote = 0;
202                 } else {
203                         if ( *s == '"' )
204                                 inquote = 1;
205                         else if ( DNSEPARATOR( *s ) )
206                                 return( strdup( s + 1 ) );
207                 }
208         }
209
210         return( strdup("") );
211 }
212
213 /*
214  * dn_issuffix - tells whether suffix is a suffix of dn.  both dn
215  * and suffix must be normalized.
216  */
217
218 int
219 dn_issuffix(
220     char        *dn,
221     char        *suffix
222 )
223 {
224         int     dnlen, suffixlen;
225
226         if ( dn == NULL ) {
227                 return( 0 );
228         }
229
230         suffixlen = strlen( suffix );
231         dnlen = strlen( dn );
232
233         if ( suffixlen > dnlen ) {
234                 return( 0 );
235         }
236
237         return( strcasecmp( dn + dnlen - suffixlen, suffix ) == 0 );
238 }
239
240 /*
241  * dn_type - tells whether the given dn is an X.500 thing or DNS thing
242  * returns (defined in slap.h): DN_DNS          dns-style thing
243  *                              DN_X500         x500-style thing
244  */
245
246 int
247 dn_type( char *dn )
248 {
249         return( strchr( dn, '=' ) == NULL ? DN_DNS : DN_X500 );
250 }
251
252 char *
253 dn_upcase( char *dn )
254 {
255         char    *s;
256
257         /* normalize case */
258         for ( s = dn; *s; s++ ) {
259                 *s = TOUPPER( *s );
260         }
261
262         return( dn );
263 }