]> git.sur5r.net Git - openldap/blob - libraries/libldap/getdn.c
20f1882cf5f09ce83cec07a1b125ba5db72ce32e
[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         ufn = LDAP_STRDUP( ++p );
67
68         if( ufn == NULL ) return NULL;
69
70 #define INQUOTE         1
71 #define OUTQUOTE        2
72         state = OUTQUOTE;
73         for ( p = ufn, r = ufn; *p; LDAP_UTF8_INCR(p) ) {
74                 switch ( *p ) {
75                 case '\\':
76                         if ( p[1] != '\0' ) {
77                                 *r++ = '\\';
78                                 LDAP_UTF8_COPY(r,++p);
79                                 LDAP_UTF8_INCR(r);
80                         }
81                         break;
82
83                 case '"':
84                         if ( state == INQUOTE )
85                                 state = OUTQUOTE;
86                         else
87                                 state = INQUOTE;
88                         *r++ = *p;
89                         break;
90
91                 case ';':
92                 case ',':
93                         if ( state == OUTQUOTE )
94                                 *r++ = ',';
95                         else
96                                 *r++ = *p;
97                         break;
98
99                 case '=':
100                         if ( state == INQUOTE ) {
101                                 *r++ = *p;
102                         } else {
103                                 char    *rsave = r;
104
105                                 *r = '\0';
106                                 LDAP_UTF8_DECR( r );
107
108                                 while ( !ldap_utf8_isspace( r )
109                                         && *r != ';' && *r != ',' && r > ufn )
110                                 {
111                                         LDAP_UTF8_DECR( r );
112                                 }
113                                 LDAP_UTF8_INCR( r );
114
115                                 if ( strcasecmp( r, "c" )
116                                     && strcasecmp( r, "o" )
117                                     && strcasecmp( r, "ou" )
118                                     && strcasecmp( r, "st" )
119                                     && strcasecmp( r, "l" )
120                                     && strcasecmp( r, "cn" ) ) {
121                                         r = rsave;
122                                         *r++ = '=';
123                                 }
124                         }
125                         break;
126
127                 default:
128                         LDAP_UTF8_COPY(r, p);
129                         LDAP_UTF8_INCR(r);
130                         break;
131                 }
132         }
133         *r = '\0';
134
135         return( ufn );
136 }
137
138 char **
139 ldap_explode_dn( LDAP_CONST char *dn, int notypes )
140 {
141         Debug( LDAP_DEBUG_TRACE, "ldap_explode_dn\n", 0, 0, 0 );
142
143         return explode_name( dn, notypes, NAME_TYPE_LDAP_DN );
144 }
145
146 char **
147 ldap_explode_rdn( LDAP_CONST char *rdn, int notypes )
148 {
149         Debug( LDAP_DEBUG_TRACE, "ldap_explode_rdn\n", 0, 0, 0 );
150         return explode_name( rdn, notypes, NAME_TYPE_LDAP_RDN );
151 }
152
153 char *
154 ldap_dn2dcedn( LDAP_CONST char *dn )
155 {
156         char *dce, *q, **rdns, **p;
157         int len = 0;
158
159         Debug( LDAP_DEBUG_TRACE, "ldap_dn2dcedn\n", 0, 0, 0 );
160
161         rdns = explode_name( dn, 0, NAME_TYPE_LDAP_DN );
162         if ( rdns == NULL ) {
163                 return NULL;
164         }
165         
166         for ( p = rdns; *p != NULL; p++ ) {
167                 len += strlen( *p ) + 1;
168         }
169
170         q = dce = LDAP_MALLOC( len + 1 );
171         if ( dce == NULL ) {
172                 return NULL;
173         }
174
175         p--; /* get back past NULL */
176
177         for ( ; p != rdns; p-- ) {
178                 strcpy( q, "/" );
179                 q++;
180                 strcpy( q, *p );
181                 q += strlen( *p );
182         }
183
184         strcpy( q, "/" );
185         q++;
186         strcpy( q, *p );
187         
188         return dce;
189 }
190
191 char *
192 ldap_dcedn2dn( LDAP_CONST char *dce )
193 {
194         char *dn, *q, **rdns, **p;
195         int len;
196
197         Debug( LDAP_DEBUG_TRACE, "ldap_dcedn2dn\n", 0, 0, 0 );
198
199         rdns = explode_name( dce, 0, NAME_TYPE_DCE_DN );
200         if ( rdns == NULL ) {
201                 return NULL;
202         }
203
204         len = 0;
205
206         for ( p = rdns; *p != NULL; p++ ) {
207                 len += strlen( *p ) + 1;
208         }
209
210         q = dn = LDAP_MALLOC( len );
211         if ( dn == NULL ) {
212                 return NULL;
213         }
214
215         p--;
216
217         for ( ; p != rdns; p-- ) {
218                 strcpy( q, *p );
219                 q += strlen( *p );
220                 strcpy( q, "," );
221                 q++;
222         }
223
224         if ( *dce == '/' ) {
225                 /* the name was fully qualified, thus the most-significant
226                  * RDN was empty. trash the last comma */
227                 q--;
228                 *q = '\0';
229         } else {
230                 /* the name was relative. copy the most significant RDN */
231                 strcpy( q, *p );
232         }
233
234         return dn;
235 }
236
237 static char **
238 explode_name( const char *name, int notypes, int is_type )
239 {
240         const char *p, *q, *rdn;
241         char **parts = NULL;
242         int     offset, state, have_equals, count = 0, endquote, len;
243
244         /* safe guard */
245         if(name == NULL) name = "";
246
247         /* skip leading whitespace */
248         while( ldap_utf8_isspace( name )) {
249                 LDAP_UTF8_INCR( name );
250         }
251
252         p = rdn = name;
253         offset = 0;
254         state = OUTQUOTE;
255         have_equals=0;
256
257         do {
258                 /* step forward */
259                 p += offset;
260                 offset = 1;
261
262                 switch ( *p ) {
263                 case '\\':
264                         if ( p[1] != '\0' ) {
265                                 offset = LDAP_UTF8_OFFSET(++p);
266                         }
267                         break;
268                 case '"':
269                         if ( state == INQUOTE )
270                                 state = OUTQUOTE;
271                         else
272                                 state = INQUOTE;
273                         break;
274                 case '=':
275                         if( state == OUTQUOTE ) have_equals++;
276                         break;
277                 case '+':
278                         if (is_type == NAME_TYPE_LDAP_RDN)
279                                 goto end_part;
280                         break;
281                 case '/':
282                         if (is_type == NAME_TYPE_DCE_DN)
283                                 goto end_part;
284                         break;
285                 case ';':
286                 case ',':
287                         if (is_type == NAME_TYPE_LDAP_DN)
288                                 goto end_part;
289                         break;
290                 case '\0':
291                 end_part:
292                         if ( state == OUTQUOTE ) {
293                                 ++count;
294                                 have_equals=0;
295
296                                 if ( parts == NULL ) {
297                                         if (( parts = (char **)LDAP_MALLOC( 8
298                                                  * sizeof( char *))) == NULL )
299                                                 return( NULL );
300                                 } else if ( count >= 8 ) {
301                                         if (( parts = (char **)LDAP_REALLOC( parts,
302                                                 (count+1) * sizeof( char *)))
303                                                 == NULL )
304                                                 return( NULL );
305                                 }
306
307                                 parts[ count ] = NULL;
308                                 endquote = 0;
309
310                                 if ( notypes ) {
311                                         for ( q = rdn; q < p && *q != '='; ++q ) {
312                                                 /* EMPTY */;
313                                         }
314
315                                         if ( q < p ) {
316                                                 rdn = ++q;
317                                         }
318
319                                         if ( *rdn == '"' ) {
320                                                 ++rdn;
321                                         }
322                                         
323                                         if ( p[-1] == '"' ) {
324                                                 endquote = 1;
325                                                 --p;
326                                         }
327                                 }
328
329                                 len = p - rdn;
330
331                                 if (( parts[ count-1 ] = (char *)LDAP_CALLOC( 1,
332                                     len + 1 )) != NULL )
333                                 {
334                                         SAFEMEMCPY( parts[ count-1 ], rdn, len );
335
336                                         if( !endquote ) {
337                                                 /* skip trailing spaces */
338                                                 while( len > 0 && ldap_utf8_isspace(
339                                                         &parts[count-1][len-1] ) )
340                                                 {
341                                                         --len;
342                                                 }
343                                         }
344
345                                         parts[ count-1 ][ len ] = '\0';
346                                 }
347
348                                 /*
349                                  *  Don't forget to increment 'p' back to where
350                                  *  it should be.  If we don't, then we will
351                                  *  never get past an "end quote."
352                                  */
353                                 if ( endquote == 1 )
354                                         p++;
355
356                                 rdn = *p ? &p[1] : p;
357                                 while ( ldap_utf8_isspace( rdn ) )
358                                         ++rdn;
359                         } break;
360                 }
361         } while ( *p );
362
363         return( parts );
364 }