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