1 /*
2 * Copyright (c) 2001 by Sun Microsystems, Inc.
3 * All rights reserved.
4 */
5
6 #pragma ident "%Z%%M% %I% %E% SMI"
7
8 /*
9 * The contents of this file are subject to the Netscape Public
10 * License Version 1.1 (the "License"); you may not use this file
11 * except in compliance with the License. You may obtain a copy of
12 * the License at http://www.mozilla.org/NPL/
13 *
14 * Software distributed under the License is distributed on an "AS
15 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
16 * implied. See the License for the specific language governing
17 * rights and limitations under the License.
18 *
19 * The Original Code is Mozilla Communicator client code, released
20 * March 31, 1998.
21 *
22 * The Initial Developer of the Original Code is Netscape
23 * Communications Corporation. Portions created by Netscape are
24 * Copyright (C) 1998-1999 Netscape Communications Corporation. All
25 * Rights Reserved.
26 *
27 * Contributor(s):
28 */
29 /*
30 * Copyright (c) 1994 Regents of the University of Michigan.
31 * All rights reserved.
32 */
33 /*
34 * getdn.c
35 */
36
37 #if 0
38 #ifndef lint
39 static char copyright[] = "@(#) Copyright (c) 1990 Regents of the University of Michigan.\nAll rights reserved.\n";
40 #endif
41 #endif
42
43 #include "ldap-int.h"
44
45 char *
46 LDAP_CALL
ldap_get_dn(LDAP * ld,LDAPMessage * entry)47 ldap_get_dn( LDAP *ld, LDAPMessage *entry )
48 {
49 char *dn;
50 struct berelement tmp;
51
52 LDAPDebug( LDAP_DEBUG_TRACE, "ldap_get_dn\n", 0, 0, 0 );
53
54 if ( !NSLDAPI_VALID_LDAP_POINTER( ld )) {
55 return( NULL ); /* punt */
56 }
57
58 if ( !NSLDAPI_VALID_LDAPMESSAGE_ENTRY_POINTER( entry )) {
59 LDAP_SET_LDERRNO( ld, LDAP_PARAM_ERROR, NULL, NULL );
60 return( NULL );
61 }
62
63 tmp = *entry->lm_ber; /* struct copy */
64 if ( ber_scanf( &tmp, "{a", &dn ) == LBER_ERROR ) {
65 LDAP_SET_LDERRNO( ld, LDAP_DECODING_ERROR, NULL, NULL );
66 return( NULL );
67 }
68
69 return( dn );
70 }
71
72 char *
73 LDAP_CALL
ldap_dn2ufn(const char * dn)74 ldap_dn2ufn( const char *dn )
75 {
76 char *p, *ufn, *r;
77 size_t plen;
78 int state;
79
80 LDAPDebug( LDAP_DEBUG_TRACE, "ldap_dn2ufn\n", 0, 0, 0 );
81
82 if ( dn == NULL ) {
83 dn = "";
84 }
85
86 if ( ldap_is_dns_dn( dn ) || ( p = strchr( dn, '=' )) == NULL )
87 return( nsldapi_strdup( (char *)dn ));
88
89 ufn = nsldapi_strdup( ++p );
90
91 #define INQUOTE 1
92 #define OUTQUOTE 2
93 state = OUTQUOTE;
94 for ( p = ufn, r = ufn; *p; p += plen ) {
95 plen = 1;
96 switch ( *p ) {
97 case '\\':
98 if ( *++p == '\0' )
99 plen=0;
100 else {
101 *r++ = '\\';
102 r += (plen = LDAP_UTF8COPY(r,p));
103 }
104 break;
105 case '"':
106 if ( state == INQUOTE )
107 state = OUTQUOTE;
108 else
109 state = INQUOTE;
110 *r++ = *p;
111 break;
112 case ';':
113 case ',':
114 if ( state == OUTQUOTE )
115 *r++ = ',';
116 else
117 *r++ = *p;
118 break;
119 case '=':
120 if ( state == INQUOTE )
121 *r++ = *p;
122 else {
123 char *rsave = r;
124 LDAP_UTF8DEC(r);
125 *rsave = '\0';
126 while ( !ldap_utf8isspace( r ) && *r != ';'
127 && *r != ',' && r > ufn )
128 LDAP_UTF8DEC(r);
129 LDAP_UTF8INC(r);
130
131 if ( strcasecmp( r, "c" )
132 && strcasecmp( r, "o" )
133 && strcasecmp( r, "ou" )
134 && strcasecmp( r, "st" )
135 && strcasecmp( r, "l" )
136 && strcasecmp( r, "dc" )
137 && strcasecmp( r, "uid" )
138 && strcasecmp( r, "cn" ) ) {
139 r = rsave;
140 *r++ = '=';
141 }
142 }
143 break;
144 default:
145 r += (plen = LDAP_UTF8COPY(r,p));
146 break;
147 }
148 }
149 *r = '\0';
150
151 return( ufn );
152 }
153
154 char **
155 LDAP_CALL
ldap_explode_dns(const char * dn)156 ldap_explode_dns( const char *dn )
157 {
158 int ncomps, maxcomps;
159 char *s, *cpydn;
160 char **rdns;
161 #ifdef HAVE_STRTOK_R /* defined in portable.h */
162 char *lasts;
163 #endif
164
165 if ( dn == NULL ) {
166 dn = "";
167 }
168
169 if ( (rdns = (char **)NSLDAPI_MALLOC( 8 * sizeof(char *) )) == NULL ) {
170 return( NULL );
171 }
172
173 maxcomps = 8;
174 ncomps = 0;
175 cpydn = nsldapi_strdup( (char *)dn );
176 for ( s = STRTOK( cpydn, "@.", &lasts ); s != NULL;
177 s = STRTOK( NULL, "@.", &lasts ) ) {
178 if ( ncomps == maxcomps ) {
179 maxcomps *= 2;
180 if ( (rdns = (char **)NSLDAPI_REALLOC( rdns, maxcomps *
181 sizeof(char *) )) == NULL ) {
182 NSLDAPI_FREE( cpydn );
183 return( NULL );
184 }
185 }
186 rdns[ncomps++] = nsldapi_strdup( s );
187 }
188 rdns[ncomps] = NULL;
189 NSLDAPI_FREE( cpydn );
190
191 return( rdns );
192 }
193
194 #define LDAP_DN 1
195 #define LDAP_RDN 2
196
197 static char **
ldap_explode(const char * dn,const int notypes,const int nametype)198 ldap_explode( const char *dn, const int notypes, const int nametype )
199 {
200 char *p, *q, *rdnstart, **rdns = NULL;
201 size_t plen = 0;
202 int state, count = 0, endquote, len, goteq;
203
204 LDAPDebug( LDAP_DEBUG_TRACE, "ldap_explode\n", 0, 0, 0 );
205
206 if ( dn == NULL ) {
207 dn = "";
208 }
209
210 #if 0
211 if ( ldap_is_dns_dn( dn ) ) {
212 return( ldap_explode_dns( dn ) );
213 }
214 #endif
215
216 while ( ldap_utf8isspace( (char *)dn )) { /* ignore leading spaces */
217 ++dn;
218 }
219
220 p = rdnstart = (char *) dn;
221 state = OUTQUOTE;
222 goteq = 0;
223
224 do {
225 p += plen;
226 plen = 1;
227 switch ( *p ) {
228 case '\\':
229 if ( *++p == '\0' )
230 p--;
231 else
232 plen = LDAP_UTF8LEN(p);
233 break;
234 case '"':
235 if ( state == INQUOTE )
236 state = OUTQUOTE;
237 else
238 state = INQUOTE;
239 break;
240 case '+': if ( nametype != LDAP_RDN ) break;
241 case ';':
242 case ',':
243 case '\0':
244 if ( state == OUTQUOTE ) {
245 /*
246 * semicolon and comma are not valid RDN
247 * separators.
248 */
249 if ( nametype == LDAP_RDN &&
250 ( *p == ';' || *p == ',' || !goteq)) {
251 ldap_charray_free( rdns );
252 return NULL;
253 }
254 if ( (*p == ',' || *p == ';') && !goteq ) {
255 /* If we get here, we have a case similar
256 * to <attr>=<value>,<string>,<attr>=<value>
257 * This is not a valid dn */
258 ldap_charray_free( rdns );
259 return NULL;
260 }
261 goteq = 0;
262 ++count;
263 if ( rdns == NULL ) {
264 if (( rdns = (char **)NSLDAPI_MALLOC( 8
265 * sizeof( char *))) == NULL )
266 return( NULL );
267 } else if ( count >= 8 ) {
268 if (( rdns = (char **)NSLDAPI_REALLOC(
269 rdns, (count+1) *
270 sizeof( char *))) == NULL )
271 return( NULL );
272 }
273 rdns[ count ] = NULL;
274 endquote = 0;
275 if ( notypes ) {
276 for ( q = rdnstart;
277 q < p && *q != '='; ++q ) {
278 ;
279 }
280 if ( q < p ) { /* *q == '=' */
281 rdnstart = ++q;
282 }
283 if ( *rdnstart == '"' ) {
284 ++rdnstart;
285 }
286
287 if ( *(p-1) == '"' ) {
288 endquote = 1;
289 --p;
290 }
291 }
292
293 len = p - rdnstart;
294 if (( rdns[ count-1 ] = (char *)NSLDAPI_CALLOC(
295 1, len + 1 )) != NULL ) {
296 SAFEMEMCPY( rdns[ count-1 ], rdnstart,
297 len );
298 if ( !endquote ) {
299 /* trim trailing spaces */
300 while ( len > 0 &&
301 ldap_utf8isspace(
302 &rdns[count-1][len-1] )) {
303 --len;
304 }
305 }
306 rdns[ count-1 ][ len ] = '\0';
307 }
308
309 /*
310 * Don't forget to increment 'p' back to where
311 * it should be. If we don't, then we will
312 * never get past an "end quote."
313 */
314 if ( endquote == 1 )
315 p++;
316
317 rdnstart = *p ? p + 1 : p;
318 while ( ldap_utf8isspace( rdnstart ))
319 ++rdnstart;
320 }
321 break;
322 case '=':
323 if ( state == OUTQUOTE ) {
324 goteq = 1;
325 }
326 /* FALL */
327 default:
328 plen = LDAP_UTF8LEN(p);
329 break;
330 }
331 } while ( *p );
332
333 return( rdns );
334 }
335
336 char **
337 LDAP_CALL
ldap_explode_dn(const char * dn,const int notypes)338 ldap_explode_dn( const char *dn, const int notypes )
339 {
340 return( ldap_explode( dn, notypes, LDAP_DN ) );
341 }
342
343 char **
344 LDAP_CALL
ldap_explode_rdn(const char * rdn,const int notypes)345 ldap_explode_rdn( const char *rdn, const int notypes )
346 {
347 return( ldap_explode( rdn, notypes, LDAP_RDN ) );
348 }
349
350 int
351 LDAP_CALL
ldap_is_dns_dn(const char * dn)352 ldap_is_dns_dn( const char *dn )
353 {
354 return( dn != NULL && dn[ 0 ] != '\0' && strchr( dn, '=' ) == NULL &&
355 strchr( dn, ',' ) == NULL );
356 }
357
358 #ifdef _SOLARIS_SDK
359
360 /*
361 * Convert a DNS domain name into an X.500 distinguished name.
362 * For example, "sales.wiz.com" -> "dc=sales,dc=wiz,dc=com"
363 *
364 * If an error is encountered zero is returned, otherwise a string
365 * distinguished name and the number of nameparts is returned.
366 * The caller should free the returned string if it is non-zero.
367 */
368
369 char *
ldap_dns_to_dn(char * dns_name,int * nameparts)370 ldap_dns_to_dn(
371 char *dns_name,
372 int *nameparts
373 )
374 {
375 size_t dns_len;
376 char *dn = 0;
377 char *cp;
378
379 /* check for NULL string, empty name and name ending in '.' */
380 if (dns_name && (dns_len = strlen(dns_name)) &&
381 (dns_name[dns_len - 1] != '.')) {
382 if (dn = (char *)malloc(dns_len * 3 + 1)) {
383 *nameparts = 0;
384 cp = dn;
385 while (*dns_name) {
386 *cp++ = 'd';
387 *cp++ = 'c';
388 *cp++ = '=';
389
390 while (*dns_name && (*dns_name != '.')) {
391 *cp++ = *dns_name++;
392 }
393 if (*dns_name == '.') {
394 dns_name++;
395 *cp++ = ',';
396 }
397 (*nameparts)++;
398 }
399 *cp = '\0';
400 }
401 }
402 return (dn);
403 }
404
405 #endif
406
407