xref: /onnv-gate/usr/src/lib/libldap4/common/getdn.c (revision 3857:21b9b714e4ab)
1 /*
2  * Portions Copyright 1998 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
7 
8 /*
9  *  Copyright (c) 1994 Regents of the University of Michigan.
10  *  All rights reserved.
11  *
12  *  getdn.c
13  */
14 
15 #ifndef lint
16 static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
17 #endif
18 
19 #include <stdio.h>
20 #include <ctype.h>
21 #include <string.h>
22 #include <stdlib.h> /* malloc(), realloc(), calloc() for Solaris */
23 #ifdef MACOS
24 #include <stdlib.h>
25 #include "macos.h"
26 #else /* MACOS */
27 #if defined( DOS ) || defined( _WIN32 )
28 #include <malloc.h>
29 #include "msdos.h"
30 #else /* DOS */
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #endif /* DOS */
34 #endif /* MACOS */
35 
36 #include "lber.h"
37 #include "ldap.h"
38 #include "ldap-private.h"
39 #include "ldap-int.h"
40 
41 char *
ldap_get_dn(LDAP * ld,LDAPMessage * entry)42 ldap_get_dn( LDAP *ld, LDAPMessage *entry )
43 {
44 	char		*dn;
45 	BerElement	tmp;
46 
47 	Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 181, "ldap_get_dn\n"), 0, 0, 0 );
48 
49 	if ( entry == NULL ) {
50 		ld->ld_errno = LDAP_PARAM_ERROR;
51 		return( NULL );
52 	}
53 
54 	tmp = *entry->lm_ber;	/* struct copy */
55 	if ( ber_scanf( &tmp, "{a", &dn ) == LBER_ERROR ) {
56 		ld->ld_errno = LDAP_DECODING_ERROR;
57 		return( NULL );
58 	}
59 
60 	return( dn );
61 }
62 
63 char *
ldap_dn2ufn(char * dn)64 ldap_dn2ufn( char *dn )
65 {
66 	char	*p, *ufn, *r;
67 	int	state;
68 
69 	Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 182, "ldap_dn2ufn\n"), 0, 0, 0 );
70 
71 	if ( ldap_is_dns_dn( dn ) || ( p = strchr( dn, '=' )) == NULL )
72 		return( strdup( dn ));
73 
74 	ufn = strdup( ++p );
75 
76 #define INQUOTE		1
77 #define OUTQUOTE	2
78 	state = OUTQUOTE;
79 	for ( p = ufn, r = ufn; *p; p++ ) {
80 		switch ( *p ) {
81 		case '\\':
82 			if ( *++p == '\0' )
83 				p--;
84 			else {
85 				*r++ = '\\';
86 				*r++ = *p;
87 			}
88 			break;
89 		case '"':
90 			if ( state == INQUOTE )
91 				state = OUTQUOTE;
92 			else
93 				state = INQUOTE;
94 			*r++ = *p;
95 			break;
96 		case ';':
97 		case ',':
98 			if ( state == OUTQUOTE )
99 				*r++ = ',';
100 			else
101 				*r++ = *p;
102 			break;
103 		case '=':
104 			if ( state == INQUOTE )
105 				*r++ = *p;
106 			else {
107 				char	*rsave = r;
108 
109 				*r-- = '\0';
110 				while ( !isspace( *r ) && *r != ';'
111 				    && *r != ',' && r > ufn )
112 					r--;
113 				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 		default:
127 			*r++ = *p;
128 			break;
129 		}
130 	}
131 	*r = '\0';
132 
133 	return( ufn );
134 }
135 
136 char **
ldap_explode_dns(char * dn)137 ldap_explode_dns( char *dn )
138 {
139 	int	ncomps, maxcomps;
140 	char	*s;
141 	char	**rdns;
142 
143 	if ( (rdns = (char **) malloc( 8 * sizeof(char *) )) == NULL ) {
144 		return( NULL );
145 	}
146 
147 	maxcomps = 8;
148 	ncomps = 0;
149 	for ( s = strtok( dn, "@." ); s != NULL; s = strtok( NULL, "@." ) ) {
150 		if ( ncomps == maxcomps ) {
151 			maxcomps *= 2;
152 			if ( (rdns = (char **) realloc( rdns, maxcomps *
153 			    sizeof(char *) )) == NULL ) {
154 				return( NULL );
155 			}
156 		}
157 		rdns[ncomps++] = strdup( s );
158 	}
159 	rdns[ncomps] = NULL;
160 
161 	return( rdns );
162 }
163 
164 char **
ldap_explode_dn(char * dn,int notypes)165 ldap_explode_dn( char *dn, int notypes )
166 {
167 	char	*p, *q, *rdnstart, **rdns = NULL;
168 	int	state, count = 0, endquote;
169 	ssize_t  len;
170 
171 	Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 183, "ldap_explode_dn\n"), 0, 0, 0 );
172 
173 	if ( ldap_is_dns_dn( dn ) ) {
174 		return( ldap_explode_dns( dn ) );
175 	}
176 
177 	rdnstart = dn;
178 	p = dn-1;
179 	state = OUTQUOTE;
180 
181 	do {
182 
183 		++p;
184 		switch ( *p ) {
185 		case '\\':
186 			if ( *++p == '\0' )
187 				p--;
188 			break;
189 		case '"':
190 			if ( state == INQUOTE )
191 				state = OUTQUOTE;
192 			else
193 				state = INQUOTE;
194 			break;
195 		case ';':
196 		case ',':
197 		case '\0':
198 			if ( state == OUTQUOTE ) {
199 				++count;
200 				if ( rdns == NULL ) {
201 					if (( rdns = (char **)malloc( 8
202 						 * sizeof( char *))) == NULL )
203 						return( NULL );
204 				} else if ( count >= 8 ) {
205 					if (( rdns = (char **)realloc( rdns,
206 						(count+1) * sizeof( char *)))
207 						== NULL )
208 						return( NULL );
209 				}
210 				rdns[ count ] = NULL;
211 				endquote = 0;
212 				if ( notypes ) {
213 					for ( q = rdnstart;
214 					    q < p && *q != '='; ++q ) {
215 						;
216 					}
217 					if ( q < p ) {
218 						rdnstart = ++q;
219 					}
220 					if ( *rdnstart == '"' ) {
221 						++rdnstart;
222 					}
223 
224 					if ( *(p-1) == '"' ) {
225 						endquote = 1;
226 						--p;
227 					}
228 				}
229 
230 				len = p - rdnstart;
231 				if (( rdns[ count-1 ] = (char *)calloc( 1,
232 				    len + 1 )) != NULL ) {
233 				    	(void) SAFEMEMCPY( rdns[ count-1 ], rdnstart,
234 					    len );
235 					rdns[ count-1 ][ len ] = '\0';
236 				}
237 
238 				/*
239 				 *  Don't forget to increment 'p' back to where
240 				 *  it should be.  If we don't, then we will
241 				 *  never get past an "end quote."
242 				 */
243 				if ( endquote == 1 )
244 					p++;
245 
246 				rdnstart = *p ? p + 1 : p;
247 				while ( isspace( *rdnstart ))
248 					++rdnstart;
249 			}
250 			break;
251 		}
252 	} while ( *p );
253 
254 	return( rdns );
255 }
256 
257 
258 int
ldap_is_dns_dn(char * dn)259 ldap_is_dns_dn( char *dn )
260 {
261 	return( dn[ 0 ] != '\0' && strchr( dn, '=' ) == NULL &&
262 	    strchr( dn, ',' ) == NULL );
263 }
264 
265 
266 #if defined( ultrix ) || defined( NeXT )
267 
strdup(char * s)268 char *strdup( char *s )
269 {
270 	char	*p;
271 
272 	if ( (p = (char *) malloc( strlen( s ) + 1 )) == NULL )
273 		return( NULL );
274 
275 	strcpy( p, s );
276 
277 	return( p );
278 }
279 
280 #endif /* ultrix */
281 
282 
283 /*
284  * Convert a DNS domain name into an X.500 distinguished name.
285  * For example, "sales.wiz.com" -> "dc=sales,dc=wiz,dc=com"
286  *
287  * If an error is encountered zero is returned, otherwise a string
288  * distinguished name and the number of nameparts is returned.
289  * The caller should free the returned string if it is non-zero.
290  */
291 
292 char *
ldap_dns_to_dn(char * dns_name,int * nameparts)293 ldap_dns_to_dn(
294 	char	*dns_name,
295 	int	*nameparts
296 )
297 {
298 	size_t	dns_len;
299 	char	*dn = 0;
300 	char	*cp;
301 
302 	/* check for NULL string, empty name and name ending in '.' */
303 	if (dns_name && (dns_len = strlen(dns_name)) &&
304 	    (dns_name[dns_len - 1] != '.')) {
305 		if (dn = (char *)malloc(dns_len * 3 + 1)) {
306 			*nameparts = 0;
307 			cp = dn;
308 			while (*dns_name) {
309 				*cp++ = 'd';
310 				*cp++ = 'c';
311 				*cp++ = '=';
312 
313 				while (*dns_name && (*dns_name != '.')) {
314 					*cp++ = *dns_name++;
315 				}
316 				if (*dns_name == '.') {
317 					dns_name++;
318 					*cp++ = ',';
319 				}
320 				(*nameparts)++;
321 			}
322 			*cp = '\0';
323 		}
324 	}
325 	return (dn);
326 }
327 
328 char **
ldap_explode_rdn(char * rdn,int notypes)329 ldap_explode_rdn( char *rdn, int notypes )
330 {
331 	char	*p, *q, *rdnstart, **rdncomps = NULL;
332 	int	state, count = 0, endquote;
333 	size_t  len;
334 
335 	Debug( LDAP_DEBUG_TRACE, catgets(slapdcat, 1, 183, "ldap_explode_rdn\n"), 0, 0, 0 );
336 
337 	rdnstart = rdn;
338 	p = rdn-1;
339 	state = OUTQUOTE;
340 
341 	do {
342 
343 		++p;
344 		switch ( *p ) {
345 		case '\\':
346 			if ( *++p == '\0' )
347 				p--;
348 			break;
349 		case '"':
350 			if ( state == INQUOTE )
351 				state = OUTQUOTE;
352 			else
353 				state = INQUOTE;
354 			break;
355 		case '+':
356 		case '\0':
357 			if ( state == OUTQUOTE ) {
358 				++count;
359 				if ( rdncomps == NULL ) {
360 					if (( rdncomps = (char **)malloc( 8 * sizeof( char *))) == NULL )
361 						return( NULL );
362 				} else if ( count >= 8 ) {
363 					if (( rdncomps = (char **)realloc( rdncomps,
364 						(count+1) * sizeof( char *)))
365 						== NULL )
366 						return( NULL );
367 				}
368 				rdncomps[ count ] = NULL;
369 				endquote = 0;
370 				if ( notypes ) {
371 					for ( q = rdnstart;
372 					    q < p && *q != '='; ++q ) {
373 						;
374 					}
375 					if ( q < p ) {
376 						rdnstart = ++q;
377 					}
378 					if ( *rdnstart == '"' ) {
379 						++rdnstart;
380 					}
381 
382 					if ( *(p-1) == '"' ) {
383 						endquote = 1;
384 						--p;
385 					}
386 				}
387 
388 				len = p - rdnstart;
389 				if (( rdncomps[ count-1 ] = (char *)calloc( 1, len + 1 )) != NULL ) {
390 				    	SAFEMEMCPY( rdncomps[ count-1 ], rdnstart,
391 					    len );
392 					rdncomps[ count-1 ][ len ] = '\0';
393 				}
394 
395 				/*
396 				 *  Don't forget to increment 'p' back to where
397 				 *  it should be.  If we don't, then we will
398 				 *  never get past an "end quote."
399 				 */
400 				if ( endquote == 1 )
401 					p++;
402 
403 				rdnstart = *p ? p + 1 : p;
404 				while ( isspace( *rdnstart ))
405 					++rdnstart;
406 			}
407 			break;
408 		}
409 	} while ( *p );
410 
411 	return( rdncomps );
412 }
413