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