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