xref: /onnv-gate/usr/src/lib/libldap4/common/getdxbyname.c (revision 0:68f95e015346)
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