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