]> git.sur5r.net Git - openldap/blob - libraries/libldap/getdn.c
Merge latest devel codes into releng 2 branch.
[openldap] / libraries / libldap / getdn.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 /*  Portions
7  *  Copyright (c) 1994 Regents of the University of Michigan.
8  *  All rights reserved.
9  *
10  *  getdn.c
11  */
12
13 #include "portable.h"
14
15 #include <stdio.h>
16
17 #include <ac/stdlib.h>
18
19 #include <ac/ctype.h>
20 #include <ac/socket.h>
21 #include <ac/string.h>
22 #include <ac/time.h>
23
24 #include "ldap-int.h"
25
26 #define NAME_TYPE_LDAP_RDN      0
27 #define NAME_TYPE_LDAP_DN       1
28 #define NAME_TYPE_DCE_DN        2
29
30 static char **explode_name( const char *name, int notypes, int is_type );
31
32 char *
33 ldap_get_dn( LDAP *ld, LDAPMessage *entry )
34 {
35         char            *dn;
36         BerElement      tmp;
37
38         Debug( LDAP_DEBUG_TRACE, "ldap_get_dn\n", 0, 0, 0 );
39
40         if ( entry == NULL ) {
41                 ld->ld_errno = LDAP_PARAM_ERROR;
42                 return( NULL );
43         }
44
45         tmp = *entry->lm_ber;   /* struct copy */
46         if ( ber_scanf( &tmp, "{a" /*}*/, &dn ) == LBER_ERROR ) {
47                 ld->ld_errno = LDAP_DECODING_ERROR;
48                 return( NULL );
49         }
50
51         return( dn );
52 }
53
54 char *
55 ldap_dn2ufn( LDAP_CONST char *dn )
56 {
57         char    *p, *ufn, *r;
58         int     state;
59
60         Debug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 );
61
62         if( dn == NULL ) {
63                 return NULL;
64         }
65
66         if ( ( p = ldap_utf8_strpbrk( dn, "=" ) ) == NULL ) {
67                 return( LDAP_STRDUP( dn ) );
68         }
69         ufn = LDAP_STRDUP( ++p );
70
71         if( ufn == NULL ) return NULL;
72
73 #define INQUOTE         1
74 #define OUTQUOTE        2
75         state = OUTQUOTE;
76         for ( p = ufn, r = ufn; *p; LDAP_UTF8_INCR(p) ) {
77                 switch ( *p ) {
78                 case '\\':
79                         if ( p[1] != '\0' ) {
80                                 *r++ = '\\';
81                                 LDAP_UTF8_COPY(r,++p);
82                                 LDAP_UTF8_INCR(r);
83                         }
84                         break;
85
86                 case '"':
87                         if ( state == INQUOTE )
88                                 state = OUTQUOTE;
89                         else
90                                 state = INQUOTE;
91                         *r++ = *p;
92                         break;
93
94                 case ';':
95                 case ',':
96                         if ( state == OUTQUOTE )
97                                 *r++ = ',';
98                         else
99                                 *r++ = *p;
100                         break;
101
102                 case '=':
103                         if ( state == INQUOTE ) {
104                                 *r++ = *p;
105                         } else {
106                                 char    *rsave = r;
107
108                                 *r = '\0';
109                                 LDAP_UTF8_DECR( r );
110
111                                 while ( !ldap_utf8_isspace( r )
112                                         && *r != ';' && *r != ',' && r > ufn )
113                                 {
114                                         LDAP_UTF8_DECR( r );
115                                 }
116                                 LDAP_UTF8_INCR( r );
117
118                                 if ( strcasecmp( r, "c" )
119                                     && strcasecmp( r, "o" )
120                                     && strcasecmp( r, "ou" )
121                                     && strcasecmp( r, "st" )
122                                     && strcasecmp( r, "l" )
123                                     && strcasecmp( r, "cn" ) ) {
124                                         r = rsave;
125                                         *r++ = '=';
126                                 }
127                         }
128                         break;
129
130                 default:
131                         LDAP_UTF8_COPY(r, p);
132                         LDAP_UTF8_INCR(r);
133                         break;
134                 }
135         }
136         *r = '\0';
137
138         return( ufn );
139 }
140
141 char **
142 ldap_explode_dn( LDAP_CONST char *dn, int notypes )
143 {
144         Debug( LDAP_DEBUG_TRACE, "ldap_explode_dn\n", 0, 0, 0 );
145
146         return explode_name( dn, notypes, NAME_TYPE_LDAP_DN );
147 }
148
149 char **
150 ldap_explode_rdn( LDAP_CONST char *rdn, int notypes )
151 {
152         Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 );
153         return explode_name( rdn, notypes, NAME_TYPE_LDAP_RDN );
154 }
155
156 char *
157 ldap_dn2dcedn( LDAP_CONST char *dn )
158 {
159         char *dce, *q, **rdns, **p;
160         int len = 0;
161
162         Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 );
163
164         rdns = explode_name( dn, 0, NAME_TYPE_LDAP_DN );
165         if ( rdns == NULL ) {
166                 return NULL;
167         }
168         
169         for ( p = rdns; *p != NULL; p++ ) {
170                 len += strlen( *p ) + 1;
171         }
172
173         q = dce = LDAP_MALLOC( len + 1 );
174         if ( dce == NULL ) {
175                 return NULL;
176         }
177
178         p--; /* get back past NULL */
179
180         for ( ; p != rdns; p-- ) {
181                 strcpy( q, "/" );
182                 q++;
183                 strcpy( q, *p );
184                 q += strlen( *p );
185         }
186
187         strcpy( q, "/" );
188         q++;
189         strcpy( q, *p );
190         
191         return dce;
192 }
193
194 char *
195 ldap_dcedn2dn( LDAP_CONST char *dce )
196 {
197         char *dn, *q, **rdns, **p;
198         int len;
199
200         Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 );
201
202         rdns = explode_name( dce, 0, NAME_TYPE_DCE_DN );
203         if ( rdns == NULL ) {
204                 return NULL;
205         }
206
207         len = 0;
208
209         for ( p = rdns; *p != NULL; p++ ) {
210                 len += strlen( *p ) + 1;
211         }
212
213         q = dn = LDAP_MALLOC( len );
214         if ( dn == NULL ) {
215                 return NULL;
216         }
217
218         p--;
219
220         for ( ; p != rdns; p-- ) {
221                 strcpy( q, *p );
222                 q += strlen( *p );
223                 strcpy( q, "," );
224                 q++;
225         }
226
227         if ( *dce == '/' ) {
228                 /* the name was fully qualified, thus the most-significant
229                  * RDN was empty. trash the last comma */
230                 q--;
231                 *q = '\0';
232         } else {
233                 /* the name was relative. copy the most significant RDN */
234                 strcpy( q, *p );
235         }
236
237         return dn;
238 }
239
240 static char **
241 explode_name( const char *name, int notypes, int is_type )
242 {
243         const char *p, *q, *rdn;
244         char **parts = NULL;
245         int     offset, state, have_equals, count = 0, endquote, len;
246
247         /* safe guard */
248         if(name == NULL) name = "";
249
250         /* skip leading whitespace */
251         while( ldap_utf8_isspace( name )) {
252                 LDAP_UTF8_INCR( name );
253         }
254
255         p = rdn = name;
256         offset = 0;
257         state = OUTQUOTE;
258         have_equals=0;
259
260         do {
261                 /* step forward */
262                 p += offset;
263                 offset = 1;
264
265                 switch ( *p ) {
266                 case '\\':
267                         if ( p[1] != '\0' ) {
268                                 offset = LDAP_UTF8_OFFSET(++p);
269                         }
270                         break;
271                 case '"':
272                         if ( state == INQUOTE )
273                                 state = OUTQUOTE;
274                         else
275                                 state = INQUOTE;
276                         break;
277                 case '=':
278                         if( state == OUTQUOTE ) have_equals++;
279                         break;
280                 case '+':
281                         if (is_type == NAME_TYPE_LDAP_RDN)
282                                 goto end_part;
283                         break;
284                 case '/':
285                         if (is_type == NAME_TYPE_DCE_DN)
286                                 goto end_part;
287                         break;
288                 case ';':
289                 case ',':
290                         if (is_type == NAME_TYPE_LDAP_DN)
291                                 goto end_part;
292                         break;
293                 case '\0':
294                 end_part:
295                         if ( state == OUTQUOTE ) {
296                                 ++count;
297                                 have_equals=0;
298
299                                 if ( parts == NULL ) {
300                                         if (( parts = (char **)LDAP_MALLOC( 8
301                                                  * sizeof( char *))) == NULL )
302                                                 return( NULL );
303                                 } else if ( count >= 8 ) {
304                                         if (( parts = (char **)LDAP_REALLOC( parts,
305                                                 (count+1) * sizeof( char *)))
306                                                 == NULL )
307                                                 return( NULL );
308                                 }
309
310                                 parts[ count ] = NULL;
311                                 endquote = 0;
312
313                                 if ( notypes ) {
314                                         for ( q = rdn; q < p && *q != '='; ++q ) {
315                                                 /* EMPTY */;
316                                         }
317
318                                         if ( q < p ) {
319                                                 rdn = ++q;
320                                         }
321
322                                         if ( *rdn == '"' ) {
323                                                 ++rdn;
324                                         }
325                                         
326                                         if ( p[-1] == '"' ) {
327                                                 endquote = 1;
328                                                 --p;
329                                         }
330                                 }
331
332                                 len = p - rdn;
333
334                                 if (( parts[ count-1 ] = (char *)LDAP_CALLOC( 1,
335                                     len + 1 )) != NULL )
336                                 {
337                                         SAFEMEMCPY( parts[ count-1 ], rdn, len );
338
339                                         if( !endquote ) {
340                                                 /* skip trailing spaces */
341                                                 while( len > 0 && ldap_utf8_isspace(
342                                                         &parts[count-1][len-1] ) )
343                                                 {
344                                                         --len;
345                                                 }
346                                         }
347
348                                         parts[ count-1 ][ len ] = '\0';
349                                 }
350
351                                 /*
352                                  *  Don't forget to increment 'p' back to where
353                                  *  it should be.  If we don't, then we will
354                                  *  never get past an "end quote."
355                                  */
356                                 if ( endquote == 1 )
357                                         p++;
358
359                                 rdn = *p ? &p[1] : p;
360                                 while ( ldap_utf8_isspace( rdn ) )
361                                         ++rdn;
362                         } break;
363                 }
364         } while ( *p );
365
366         return( parts );
367 }