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