xref: /illumos-gate/usr/src/lib/libldap5/sources/ldap/common/getdxbyname.c (revision 7257d1b4d25bfac0c802847390e98a464fd787ac)
1 #pragma ident	"%Z%%M%	%I%	%E% SMI"
2 
3 /*
4  * The contents of this file are subject to the Netscape Public
5  * License Version 1.1 (the "License"); you may not use this file
6  * except in compliance with the License. You may obtain a copy of
7  * the License at http://www.mozilla.org/NPL/
8  *
9  * Software distributed under the License is distributed on an "AS
10  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11  * implied. See the License for the specific language governing
12  * rights and limitations under the License.
13  *
14  * The Original Code is Mozilla Communicator client code, released
15  * March 31, 1998.
16  *
17  * The Initial Developer of the Original Code is Netscape
18  * Communications Corporation. Portions created by Netscape are
19  * Copyright (C) 1998-1999 Netscape Communications Corporation. All
20  * Rights Reserved.
21  *
22  * Contributor(s):
23  */
24 /*
25  *  Copyright (c) 1995 Regents of the University of Michigan.
26  *  All rights reserved.
27  */
28 /*
29  * nsldapi_getdxbyname - retrieve DX records from the DNS (from
30  * TXT records for now)
31  */
32 
33 #include <stdio.h>
34 
35 #ifdef LDAP_DNS
36 
37 XXX not MT-safe XXX
38 
39 #include <string.h>
40 #include <ctype.h>
41 
42 #ifdef macintosh
43 #include <stdlib.h>
44 #include "macos.h"
45 #endif /* macintosh */
46 
47 #ifdef _WINDOWS
48 #include <windows.h>
49 #endif
50 
51 #if !defined(macintosh) && !defined(DOS) && !defined( _WINDOWS )
52 #include <sys/types.h>
53 #include <netinet/in.h>
54 #include <arpa/nameser.h>
55 #include <sys/time.h>
56 #include <sys/types.h>
57 #include <sys/socket.h>
58 #include <netdb.h>
59 #include <resolv.h>
60 #endif
61 #include "ldap-int.h"
62 
63 #if defined( DOS )
64 #include "msdos.h"
65 #endif /* DOS */
66 
67 
68 #ifdef NEEDPROTOS
69 static char ** decode_answer( unsigned char *answer, int len );
70 #else /* NEEDPROTOS */
71 static char **decode_answer();
72 #endif /* NEEDPROTOS */
73 
74 extern int h_errno;
75 extern char *h_errlist[];
76 
77 
78 #define MAX_TO_SORT	32
79 
80 
81 /*
82  * nsldapi_getdxbyname - lookup DNS DX records for domain and return an ordered
83  *	array.
84  */
85 char **
86 nsldapi_getdxbyname( char *domain )
87 {
88     unsigned char	buf[ PACKETSZ ];
89     char		**dxs;
90     int			rc;
91 
92     LDAPDebug( LDAP_DEBUG_TRACE, "nsldapi_getdxbyname( %s )\n", domain, 0, 0 );
93 
94     memset( buf, 0, sizeof( buf ));
95 
96     /* XXX not MT safe XXX */
97     if (( rc = res_search( domain, C_IN, T_TXT, buf, sizeof( buf ))) < 0
98 		|| ( dxs = decode_answer( buf, rc )) == NULL ) {
99 	/*
100 	 * punt:  return list conisting of the original domain name only
101 	 */
102 	if (( dxs = (char **)NSLDAPI_MALLOC( 2 * sizeof( char * ))) == NULL ||
103 		( dxs[ 0 ] = nsldapi_strdup( domain )) == NULL ) {
104 	    if ( dxs != NULL ) {
105 		NSLDAPI_FREE( dxs );
106 	    }
107 	    dxs = NULL;
108 	} else {
109 	    dxs[ 1 ] = NULL;
110 	}
111     }
112 
113     return( dxs );
114 }
115 
116 
117 static char **
118 decode_answer( unsigned char *answer, int len )
119 {
120     HEADER		*hp;
121     char		buf[ 256 ], **dxs;
122     unsigned char	*eom, *p;
123     int			ancount, err, rc, type, class, dx_count, rr_len;
124     int			dx_pref[ MAX_TO_SORT ];
125 
126 #ifdef LDAP_DEBUG
127     if ( ldap_debug & LDAP_DEBUG_PACKETS ) {
128 /*	__p_query( answer );	*/
129     }
130 #endif /* LDAP_DEBUG */
131 
132     dxs = NULL;
133     hp = (HEADER *)answer;
134     eom = answer + len;
135 
136     if ( ntohs( hp->qdcount ) != 1 ) {
137 	h_errno = NO_RECOVERY;
138 	return( NULL );
139     }
140 
141     ancount = ntohs( hp->ancount );
142     if ( ancount < 1 ) {
143 	h_errno = NO_DATA;
144 	return( NULL );
145     }
146 
147     /*
148      * skip over the query
149      */
150     p = answer + HFIXEDSZ;
151     if (( rc = dn_expand( answer, eom, p, buf, sizeof( buf ))) < 0 ) {
152 	h_errno = NO_RECOVERY;
153 	return( NULL );
154     }
155     p += ( rc + QFIXEDSZ );
156 
157     /*
158      * pull out the answers we are interested in
159      */
160     err = dx_count = 0;
161     while ( ancount > 0 && err == 0 && p < eom ) {
162 	if (( rc = dn_expand( answer, eom, p, buf, sizeof( buf ))) < 0 ) {
163 	    err = NO_RECOVERY;
164 	    continue;
165 	}
166 	p += rc;	/* skip over name */
167 	type = _getshort( p );
168 	p += INT16SZ;
169 	class = _getshort( p );
170 	p += INT16SZ;
171 	p += INT32SZ;		/* skip over TTL */
172 	rr_len = _getshort( p );
173 	p += INT16SZ;
174 	if ( class == C_IN && type == T_TXT ) {
175 	    int 	i, n, pref, txt_len;
176 	    char	*q, *r;
177 
178 	    q = (char *)p;
179 	    while ( q < (char *)p + rr_len && err == 0 ) {
180 		if ( *q >= 3 && strncasecmp( q + 1, "dx:", 3 ) == 0 ) {
181 		    txt_len = *q - 3;
182 		    r = q + 4;
183 		    while ( isspace( *r )) {
184 			++r;
185 			--txt_len;
186 		    }
187 		    pref = 0;
188 		    while ( isdigit( *r )) {
189 			pref *= 10;
190 			pref += ( *r - '0' );
191 			++r;
192 			--txt_len;
193 		    }
194 		    if ( dx_count < MAX_TO_SORT - 1 ) {
195 			dx_pref[ dx_count ] = pref;
196 		    }
197 		    while ( isspace( *r )) {
198 			++r;
199 			--txt_len;
200 		    }
201 		    if ( dx_count == 0 ) {
202 			dxs = (char **)NSLDAPI_MALLOC( 2 * sizeof( char * ));
203 		    } else {
204 			dxs = (char **)NSLDAPI_REALLOC( dxs,
205 				( dx_count + 2 ) * sizeof( char * ));
206 		    }
207 		    if ( dxs == NULL || ( dxs[ dx_count ] =
208 			    (char *)NSLDAPI_CALLOC( 1, txt_len + 1 ))
209 			    == NULL ) {
210 			err = NO_RECOVERY;
211 			continue;
212 		    }
213 		    SAFEMEMCPY( dxs[ dx_count ], r, txt_len );
214 		    dxs[ ++dx_count ] = NULL;
215 		}
216 		q += ( *q + 1 );	/* move past last TXT record */
217 	    }
218 	}
219 	p += rr_len;
220     }
221 
222     if ( err == 0 ) {
223 	if ( dx_count == 0 ) {
224 	    err = NO_DATA;
225 	} else {
226 	    /*
227 	     * sort records based on associated preference value
228 	     */
229 	    int		i, j, sort_count, tmp_pref;
230 	    char	*tmp_dx;
231 
232 	    sort_count = ( dx_count < MAX_TO_SORT ) ? dx_count : MAX_TO_SORT;
233 	    for ( i = 0; i < sort_count; ++i ) {
234 		for ( j = i + 1; j < sort_count; ++j ) {
235 		    if ( dx_pref[ i ] > dx_pref[ j ] ) {
236 			tmp_pref = dx_pref[ i ];
237 			dx_pref[ i ] = dx_pref[ j ];
238 			dx_pref[ j ] = tmp_pref;
239 			tmp_dx = dxs[ i ];
240 			dxs[ i ] = dxs[ j ];
241 			dxs[ j ] = tmp_dx;
242 		    }
243 		}
244 	    }
245 	}
246     }
247 
248     h_errno = err;
249     return( dxs );
250 }
251 
252 #endif /* LDAP_DNS */
253