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