]>
Commit | Line | Data |
---|---|---|
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 | ||
53 | void nsError(int nserror, char *server); | |
54 | static int compare_hosts(struct hstruct *h1, struct hstruct *h2); | |
55 | static void swap(struct hstruct *a, struct hstruct *b); | |
56 | static void sort(struct hstruct *array, int nitems, int (*cmp) (struct hstruct *, struct hstruct *), int begin, int end); | |
57 | static 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 | */ |
66 | void | |
67 | nsError(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 | ||
84 | static void | |
85 | swap(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 | ||
100 | static void | |
101 | sort(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 | ||
122 | static void | |
123 | msort(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 | ||
128 | static int | |
129 | compare_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 |
154 | size_t |
155 | free_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 |
170 | size_t |
171 | get_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 |
224 | size_t |
225 | get_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 | 404 | finalise: |
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 | 416 | cleanup: |
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 |