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 **
nsldapi_getdxbyname(char * domain)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 **
decode_answer(unsigned char * answer,int len)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