1 /*
2 * Copyright 2004 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 #ifdef LDAP_DNS
9 /*
10 * Copyright (c) 1995 Regents of the University of Michigan.
11 * All rights reserved.
12 *
13 * getdxbyname - retrieve DX records from the DNS (from TXT records for now)
14 */
15 #include <stdio.h>
16 #include <string.h>
17 #include <ctype.h>
18
19 #ifdef MACOS
20 #include <stdlib.h>
21 #include "macos.h"
22 #endif /* MACOS */
23
24 #if !defined(MACOS) && !defined(DOS) && !defined( _WIN32 )
25 #include <sys/types.h>
26 #include <netinet/in.h>
27 #include <arpa/nameser.h>
28 #include <sys/time.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <netdb.h>
32 #include <resolv.h>
33 #endif
34 #include "lber.h"
35 #include "ldap.h"
36 #include "ldap-private.h"
37 #include "ldap-int.h"
38
39 #if defined( DOS ) || defined( _WIN32 )
40 #include "msdos.h"
41 #endif /* DOS */
42
43
44 #ifdef NEEDPROTOS
45 static char ** decode_answer( unsigned char *answer, int len );
46 #else /* NEEDPROTOS */
47 static char **decode_answer();
48 #endif /* NEEDPROTOS */
49
50 extern int h_errno;
51 extern char *h_errlist[];
52
53
54 #define MAX_TO_SORT 32
55
56
57 /*
58 * getdxbyname - lookup DNS DX records for domain and return an ordered
59 * array.
60 */
61 char **
getdxbyname(char * domain)62 getdxbyname( char *domain )
63 {
64 unsigned char buf[ PACKETSZ ];
65 char **dxs;
66 int rc;
67
68 Debug( LDAP_DEBUG_TRACE, "getdxbyname( %s )\n", domain, 0, 0 );
69
70 memset( buf, 0, sizeof( buf ));
71
72 if (( rc = res_search( domain, C_IN, T_TXT, buf, sizeof( buf ))) < 0
73 || ( dxs = decode_answer( buf, rc )) == NULL ) {
74 /*
75 * punt: return list conisting of the original domain name only
76 */
77 if (( dxs = (char **)malloc( 2 * sizeof( char * ))) == NULL ||
78 ( dxs[ 0 ] = strdup( domain )) == NULL ) {
79 if ( dxs != NULL ) {
80 free( dxs );
81 }
82 dxs = NULL;
83 } else {
84 dxs[ 1 ] = NULL;
85 }
86 }
87
88 return( dxs );
89 }
90
91
92 static char **
decode_answer(unsigned char * answer,int len)93 decode_answer( unsigned char *answer, int len )
94 {
95 HEADER *hp;
96 char buf[ 256 ], **dxs;
97 unsigned char *eom, *p;
98 int ancount, err, rc, type, class, dx_count, rr_len;
99 int dx_pref[ MAX_TO_SORT ];
100
101 int _getshort( unsigned char * );
102 #ifdef LDAP_DEBUG
103 if ( ldap_debug & LDAP_DEBUG_PACKETS ) {
104 /* __p_query( answer ); */
105 }
106 #endif /* LDAP_DEBUG */
107
108 dxs = NULL;
109 hp = (HEADER *)answer;
110 eom = answer + len;
111
112 if ( ntohs( hp->qdcount ) != 1 ) {
113 h_errno = NO_RECOVERY;
114 return( NULL );
115 }
116
117 ancount = ntohs( hp->ancount );
118 if ( ancount < 1 ) {
119 h_errno = NO_DATA;
120 return( NULL );
121 }
122
123 /*
124 * skip over the query
125 */
126 p = answer + HFIXEDSZ;
127 if (( rc = dn_expand( answer, eom, p, buf, sizeof( buf ))) < 0 ) {
128 h_errno = NO_RECOVERY;
129 return( NULL );
130 }
131 p += ( rc + QFIXEDSZ );
132
133 /*
134 * pull out the answers we are interested in
135 */
136 err = dx_count = 0;
137 while ( ancount > 0 && err == 0 && p < eom ) {
138 if (( rc = dn_expand( answer, eom, p, buf, sizeof( buf ))) < 0 ) {
139 err = NO_RECOVERY;
140 continue;
141 }
142 p += rc; /* skip over name */
143 type = _getshort( p );
144 p += INT16SZ;
145 class = _getshort( p );
146 p += INT16SZ;
147 p += INT32SZ; /* skip over TTL */
148 rr_len = _getshort( p );
149 p += INT16SZ;
150 if ( class == C_IN && type == T_TXT ) {
151 int i, n, pref, txt_len;
152 char *q, *r;
153
154 q = (char *)p;
155 while ( q < (char *)p + rr_len && err == 0 ) {
156 if ( *q >= 3 && strncasecmp( q + 1, "dx:", 3 ) == 0 ) {
157 txt_len = *q - 3;
158 r = q + 4;
159 while ( isspace( *r )) {
160 ++r;
161 --txt_len;
162 }
163 pref = 0;
164 while ( isdigit( *r )) {
165 pref *= 10;
166 pref += ( *r - '0' );
167 ++r;
168 --txt_len;
169 }
170 if ( dx_count < MAX_TO_SORT - 1 ) {
171 dx_pref[ dx_count ] = pref;
172 }
173 while ( isspace( *r )) {
174 ++r;
175 --txt_len;
176 }
177 if ( dx_count == 0 ) {
178 dxs = (char **)malloc( 2 * sizeof( char * ));
179 } else {
180 dxs = (char **)realloc( dxs,
181 ( dx_count + 2 ) * sizeof( char * ));
182 }
183 if ( dxs == NULL || ( dxs[ dx_count ] =
184 (char *)calloc( 1, txt_len + 1 )) == NULL ) {
185 err = NO_RECOVERY;
186 continue;
187 }
188 memcpy( dxs[ dx_count ], r, txt_len );
189 dxs[ ++dx_count ] = NULL;
190 }
191 q += ( *q + 1 ); /* move past last TXT record */
192 }
193 }
194 p += rr_len;
195 }
196
197 if ( err == 0 ) {
198 if ( dx_count == 0 ) {
199 err = NO_DATA;
200 } else {
201 /*
202 * sort records based on associated preference value
203 */
204 int i, j, sort_count, tmp_pref;
205 char *tmp_dx;
206
207 sort_count = ( dx_count < MAX_TO_SORT ) ? dx_count : MAX_TO_SORT;
208 for ( i = 0; i < sort_count; ++i ) {
209 for ( j = i + 1; j < sort_count; ++j ) {
210 if ( dx_pref[ i ] > dx_pref[ j ] ) {
211 tmp_pref = dx_pref[ i ];
212 dx_pref[ i ] = dx_pref[ j ];
213 dx_pref[ j ] = tmp_pref;
214 tmp_dx = dxs[ i ];
215 dxs[ i ] = dxs[ j ];
216 dxs[ j ] = tmp_dx;
217 }
218 }
219 }
220 }
221 }
222
223 h_errno = err;
224 return( dxs );
225 }
226
227 #endif /* LDAP_DNS */
228