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