]> git.ipfire.org Git - thirdparty/squid.git/blob - helpers/external_acl/kerberos_ldap_group/support_resolv.cc
Typo on 64-bit builds
[thirdparty/squid.git] / helpers / external_acl / kerberos_ldap_group / support_resolv.cc
1 /*
2 * -----------------------------------------------------------------------------
3 *
4 * Author: Markus Moeller (markus_moeller at compuserve.com)
5 *
6 * Copyright (C) 2007 Markus Moeller. All rights reserved.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
21 *
22 * -----------------------------------------------------------------------------
23 */
24
25 #include "config.h"
26 #include "util.h"
27
28 #ifdef HAVE_LDAP
29
30 #include "support.h"
31 #ifdef HAVE_ERRNO_H
32 #include <errno.h>
33 #endif
34 #ifdef HAVE_NETDB_H
35 #include <netdb.h>
36 #endif
37 #ifdef HAVE_NETINET_IN_H
38 #include <netinet/in.h>
39 #endif
40 #ifdef HAVE_RESOLV_H
41 #include <resolv.h>
42 #endif
43 #ifdef HAVE_ARPA_NAMESER_H
44 #include <arpa/nameser.h>
45 #endif
46
47 void nsError(int nserror, char *server);
48 static int compare_hosts(struct hstruct *h1, struct hstruct *h2);
49 static void swap(struct hstruct *a, struct hstruct *b);
50 static void sort(struct hstruct *array, int nitems, int (*cmp) (struct hstruct *, struct hstruct *), int begin, int end);
51 static void msort(struct hstruct *array, size_t nitems, int (*cmp) (struct hstruct *, struct hstruct *));
52
53 /*
54 * See http://www.ietf.org/rfc/rfc1035.txt
55 */
56 /*
57 * See http://www.ietf.org/rfc/rfc2782.txt
58 *
59 */
60 void
61 nsError(int nserror, char *service)
62 {
63 switch (nserror) {
64 case HOST_NOT_FOUND:
65 error((char *) "%s| %s: ERROR: res_search: Unknown service record: %s\n", LogTime(), PROGRAM, service);
66 break;
67 case NO_DATA:
68 error((char *) "%s| %s: ERROR: res_search: No SRV record for %s\n", LogTime(), PROGRAM, service);
69 break;
70 case TRY_AGAIN:
71 error((char *) "%s| %s: ERROR: res_search: No response for SRV query\n", LogTime(), PROGRAM);
72 break;
73 default:
74 error((char *) "%s| %s: ERROR: res_search: Unexpected error: %s\n", LogTime(), PROGRAM, strerror(nserror));
75 }
76 }
77
78 static void
79 swap(struct hstruct *a, struct hstruct *b)
80 {
81 struct hstruct c;
82
83 c.host = a->host;
84 c.priority = a->priority;
85 c.weight = a->weight;
86 a->priority = b->priority;
87 a->weight = b->weight;
88 b->host = c.host;
89 b->priority = c.priority;
90 b->weight = c.weight;
91 }
92
93 static void
94 sort(struct hstruct *array, int nitems, int (*cmp) (struct hstruct *, struct hstruct *), int begin, int end)
95 {
96 if (end > begin) {
97 int pivot = begin;
98 int l = begin + 1;
99 int r = end;
100 while (l < r) {
101 if (cmp(&array[l], &array[pivot]) <= 0) {
102 l += 1;
103 } else {
104 r -= 1;
105 swap(&array[l], &array[r]);
106 }
107 }
108 l -= 1;
109 swap(&array[begin], &array[l]);
110 sort(array, nitems, cmp, begin, l);
111 sort(array, nitems, cmp, r, end);
112 }
113 }
114
115 static void
116 msort(struct hstruct *array, size_t nitems, int (*cmp) (struct hstruct *, struct hstruct *))
117 {
118 sort(array, nitems, cmp, 0, nitems - 1);
119 }
120
121 static int
122 compare_hosts(struct hstruct *host1, struct hstruct *host2)
123 {
124 /*
125 *
126 * The comparison function must return an integer less than, equal to,
127 * or greater than zero if the first argument is considered to be
128 * respectively less than, equal to, or greater than the second.
129 */
130 if ((host1->priority < host2->priority) && (host1->priority != -1))
131 return -1;
132 if ((host1->priority < host2->priority) && (host1->priority == -1))
133 return 1;
134 if ((host1->priority > host2->priority) && (host2->priority != -1))
135 return 1;
136 if ((host1->priority > host2->priority) && (host2->priority == -1))
137 return -1;
138 if (host1->priority == host2->priority) {
139 if (host1->weight > host2->weight)
140 return -1;
141 if (host1->weight < host2->weight)
142 return 1;
143 }
144 return 0;
145 }
146
147 int
148 free_hostname_list(struct hstruct **hlist, int nhosts)
149 {
150 struct hstruct *hp = NULL;
151 int i;
152
153 hp = *hlist;
154 for (i = 0; i < nhosts; i++) {
155 if (hp[i].host)
156 xfree(hp[i].host);
157 hp[i].host = NULL;
158 }
159
160
161 if (hp)
162 xfree(hp);
163 hp = NULL;
164 *hlist = hp;
165 return 0;
166 }
167
168 int
169 get_hostname_list(struct main_args *margs, struct hstruct **hlist, int nhosts, char *name)
170 {
171 /*
172 * char host[sysconf(_SC_HOST_NAME_MAX)];
173 */
174 char host[1024];
175 struct addrinfo *hres = NULL, *hres_list;
176 int rc, count;
177 struct hstruct *hp = NULL;
178
179 if (!name)
180 return (nhosts);
181
182 hp = *hlist;
183 rc = getaddrinfo((const char *) name, NULL, NULL, &hres);
184 if (rc != 0) {
185 error((char *) "%s| %s: ERROR: Error while resolving hostname with getaddrinfo: %s\n", LogTime(), PROGRAM, gai_strerror(rc));
186 return (nhosts);
187 }
188 hres_list = hres;
189 count = 0;
190 while (hres_list) {
191 count++;
192 hres_list = hres_list->ai_next;
193 }
194 hres_list = hres;
195 count = 0;
196 while (hres_list) {
197 rc = getnameinfo(hres_list->ai_addr, hres_list->ai_addrlen, host, sizeof(host), NULL, 0, 0);
198 if (rc != 0) {
199 error((char *) "%s| %s: ERROR: Error while resolving ip address with getnameinfo: %s\n", LogTime(), PROGRAM, gai_strerror(rc));
200 freeaddrinfo(hres);
201 *hlist = hp;
202 return (nhosts);
203 }
204 count++;
205 debug((char *) "%s| %s: DEBUG: Resolved address %d of %s to %s\n", LogTime(), PROGRAM, count, name, host);
206
207 hp = (struct hstruct *) xrealloc(hp, sizeof(struct hstruct) * (nhosts + 1));
208 hp[nhosts].host = xstrdup(host);
209 hp[nhosts].port = -1;
210 hp[nhosts].priority = -1;
211 hp[nhosts].weight = -1;
212 nhosts++;
213
214 hres_list = hres_list->ai_next;
215 }
216
217 freeaddrinfo(hres);
218 *hlist = hp;
219 return (nhosts);
220 }
221
222 int
223 get_ldap_hostname_list(struct main_args *margs, struct hstruct **hlist, int nh, char *domain)
224 {
225
226 /*
227 * char name[sysconf(_SC_HOST_NAME_MAX)];
228 */
229 char name[1024];
230 char host[NS_MAXDNAME];
231 char *service;
232 struct hstruct *hp = NULL;
233 int nhosts = 0;
234 int size;
235 int type, rdlength;
236 int priority, weight, port;
237 int len, olen;
238 int i, j, k;
239 u_char *buffer;
240 u_char *p;
241
242 if (margs->ssl) {
243 service = (char *) xmalloc(strlen("_ldaps._tcp.") + strlen(domain) + 1);
244 strcpy(service, "_ldaps._tcp.");
245 } else {
246 service = (char *) xmalloc(strlen("_ldap._tcp.") + strlen(domain) + 1);
247 strcpy(service, "_ldap._tcp.");
248 }
249 strcat(service, domain);
250
251 #ifndef PACKETSZ_MULT
252 /*
253 * It seems Solaris doesn't give back the real length back when res_search uses a to small buffer
254 * Set a bigger one here
255 */
256 #define PACKETSZ_MULT 10
257 #endif
258
259 hp = *hlist;
260 buffer = (u_char *) xmalloc(PACKETSZ_MULT * NS_PACKETSZ);
261 if ((len = res_search(service, ns_c_in, ns_t_srv, (u_char *) buffer, PACKETSZ_MULT * NS_PACKETSZ)) < 0) {
262 error((char *) "%s| %s: ERROR: Error while resolving service record %s with res_search\n", LogTime(), PROGRAM, service);
263 nsError(h_errno, service);
264 if (margs->ssl) {
265 xfree(service);
266 service = (char *) xmalloc(strlen("_ldap._tcp.") + strlen(domain) + 1);
267 strcpy(service, "_ldap._tcp.");
268 strcat(service, domain);
269 if ((len = res_search(service, ns_c_in, ns_t_srv, (u_char *) buffer, PACKETSZ_MULT * NS_PACKETSZ)) < 0) {
270 error((char *) "%s| %s: ERROR: Error while resolving service record %s with res_search\n", LogTime(), PROGRAM, service);
271 nsError(h_errno, service);
272 goto cleanup;
273 }
274 } else {
275 goto cleanup;
276 }
277 }
278 if (len > PACKETSZ_MULT * NS_PACKETSZ) {
279 olen = len;
280 buffer = (u_char *) xrealloc(buffer, len);
281 if ((len = res_search(service, ns_c_in, ns_t_srv, (u_char *) buffer, len)) < 0) {
282 error((char *) "%s| %s: ERROR: Error while resolving service record %s with res_search\n", LogTime(), PROGRAM, service);
283 nsError(h_errno, service);
284 goto cleanup;
285 }
286 if (len > olen) {
287 error((char *) "%s| %s: ERROR: Reply to big: buffer: %d reply length: %d\n", LogTime(), PROGRAM, olen, len);
288 goto cleanup;
289 }
290 }
291 p = buffer;
292 p += 6 * NS_INT16SZ; /* Header(6*16bit) = id + flags + 4*section count */
293 if (p > buffer + len) {
294 error((char *) "%s| %s: ERROR: Message to small: %d < header size\n", LogTime(), PROGRAM, len);
295 goto cleanup;
296 }
297 if ((size = dn_expand(buffer, buffer + len, p, name, sysconf(_SC_HOST_NAME_MAX))) < 0) {
298 error((char *) "%s| %s: ERROR: Error while expanding query name with dn_expand: %s\n", LogTime(), PROGRAM, strerror(errno));
299 goto cleanup;
300 }
301 p += size; /* Query name */
302 p += 2 * NS_INT16SZ; /* Query type + class (2*16bit) */
303 if (p > buffer + len) {
304 error((char *) "%s| %s: ERROR: Message to small: %d < header + query name,type,class \n", LogTime(), PROGRAM, len);
305 goto cleanup;
306 }
307 while (p < buffer + len) {
308 if ((size = dn_expand(buffer, buffer + len, p, name, sysconf(_SC_HOST_NAME_MAX))) < 0) {
309 error((char *) "%s| %s: ERROR: Error while expanding answer name with dn_expand: %s\n", LogTime(), PROGRAM, strerror(errno));
310 goto cleanup;
311 }
312 p += size; /* Resource Record name */
313 if (p > buffer + len) {
314 error((char *) "%s| %s: ERROR: Message to small: %d < header + query name,type,class + answer name\n", LogTime(), PROGRAM, len);
315 goto cleanup;
316 }
317 NS_GET16(type, p); /* RR type (16bit) */
318 p += NS_INT16SZ + NS_INT32SZ; /* RR class + ttl (16bit+32bit) */
319 if (p > buffer + len) {
320 error((char *) "%s| %s: ERROR: Message to small: %d < header + query name,type,class + answer name + RR type,class,ttl\n", LogTime(), PROGRAM, len);
321 goto cleanup;
322 }
323 NS_GET16(rdlength, p); /* RR data length (16bit) */
324
325 if (type == ns_t_srv) { /* SRV record */
326 if (p > buffer + len) {
327 error((char *) "%s| %s: ERROR: Message to small: %d < header + query name,type,class + answer name + RR type,class,ttl + RR data length\n", LogTime(), PROGRAM, len);
328 goto cleanup;
329 }
330 NS_GET16(priority, p); /* Priority (16bit) */
331 if (p > buffer + len) {
332 error((char *) "%s| %s: ERROR: Message to small: %d < SRV RR + priority\n", LogTime(), PROGRAM, len);
333 goto cleanup;
334 }
335 NS_GET16(weight, p); /* Weight (16bit) */
336 if (p > buffer + len) {
337 error((char *) "%s| %s: ERROR: Message to small: %d < SRV RR + priority + weight\n", LogTime(), PROGRAM, len);
338 goto cleanup;
339 }
340 NS_GET16(port, p); /* Port (16bit) */
341 if (p > buffer + len) {
342 error((char *) "%s| %s: ERROR: Message to small: %d < SRV RR + priority + weight + port\n", LogTime(), PROGRAM, len);
343 goto cleanup;
344 }
345 if ((size = dn_expand(buffer, buffer + len, p, host, NS_MAXDNAME)) < 0) {
346 error((char *) "%s| %s: ERROR: Error while expanding SRV RR name with dn_expand: %s\n", LogTime(), PROGRAM, strerror(errno));
347 goto cleanup;
348 }
349 debug((char *) "%s| %s: DEBUG: Resolved SRV %s record to %s\n", LogTime(), PROGRAM, service, host);
350 hp = (struct hstruct *) xrealloc(hp, sizeof(struct hstruct) * (nh + 1));
351 hp[nh].host = xstrdup(host);
352 hp[nh].port = port;
353 hp[nh].priority = priority;
354 hp[nh].weight = weight;
355 nh++;
356 p += size;
357 } else {
358 p += rdlength;
359 }
360 if (p > buffer + len) {
361 error((char *) "%s| %s: ERROR: Message to small: %d < SRV RR + priority + weight + port + name\n", LogTime(), PROGRAM, len);
362 goto cleanup;
363 }
364 }
365 if (p != buffer + len) {
366 #if (SIZEOF_LONG == 8)
367 error("%s| %s: ERROR: Inconsistence message length: %ld!=0\n", LogTime(), PROGRAM, buffer + len - p);
368 #else
369 error((char *) "%s| %s: ERROR: Inconsistence message length: %d!=0\n", LogTime(), PROGRAM, buffer + len - p);
370 #endif
371 goto cleanup;
372 }
373 nhosts = get_hostname_list(margs, &hp, nh, domain);
374
375 /* Remove duplicates */
376 for (i = 0; i < nhosts; i++) {
377 for (j = i + 1; j < nhosts; j++) {
378 if (!strcasecmp(hp[i].host, hp[j].host)) {
379 if (hp[i].port == hp[j].port ||
380 (hp[i].port == -1 && hp[j].port == 389) ||
381 (hp[i].port == 389 && hp[j].port == -1)) {
382 xfree(hp[j].host);
383 for (k = j + 1; k < nhosts; k++) {
384 hp[k - 1].host = hp[k].host;
385 hp[k - 1].port = hp[k].port;
386 hp[k - 1].priority = hp[k].priority;
387 hp[k - 1].weight = hp[k].weight;
388 }
389 j--;
390 nhosts--;
391 hp = (struct hstruct *) xrealloc(hp, sizeof(struct hstruct) * (nhosts + 1));
392 }
393 }
394 }
395 }
396
397 /* Sort by Priority / Weight */
398 msort(hp, nhosts, compare_hosts);
399
400 if (debug_enabled) {
401 debug((char *) "%s| %s: DEBUG: Sorted ldap server names for domain %s:\n", LogTime(), PROGRAM, domain);
402 for (i = 0; i < nhosts; i++) {
403 debug((char *) "%s| %s: DEBUG: Host: %s Port: %d Priority: %d Weight: %d\n", LogTime(), PROGRAM, hp[i].host, hp[i].port, hp[i].priority, hp[i].weight);
404 }
405 }
406 if (buffer)
407 xfree(buffer);
408 if (service)
409 xfree(service);
410 *hlist = hp;
411 return (nhosts);
412
413 cleanup:
414 if (buffer)
415 xfree(buffer);
416 if (service)
417 xfree(service);
418 *hlist = hp;
419 return (nhosts);
420 }
421 #endif