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