]>
Commit | Line | Data |
---|---|---|
5b95b903 | 1 | /* |
4ac4a490 | 2 | * Copyright (C) 1996-2017 The Squid Software Foundation and contributors |
5b95b903 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 | ||
d80aac12 | 9 | /* |
10 | * RADIUS | |
11 | * Remote Authentication Dial In User Service | |
12 | * | |
13 | * | |
14 | * Livingston Enterprises, Inc. | |
15 | * 6920 Koll Center Parkway | |
16 | * Pleasanton, CA 94566 | |
17 | * | |
18 | * Copyright 1992 Livingston Enterprises, Inc. | |
19 | * | |
20 | * Permission to use, copy, modify, and distribute this software for any | |
21 | * purpose and without fee is hereby granted, provided that this | |
22 | * copyright and permission notice appear on all copies and supporting | |
23 | * documentation, the name of Livingston Enterprises, Inc. not be used | |
24 | * in advertising or publicity pertaining to distribution of the | |
25 | * program without specific prior permission, and notice be given | |
26 | * in supporting documentation that copying and distribution is by | |
26ac0430 | 27 | * permission of Livingston Enterprises, Inc. |
d80aac12 | 28 | * |
29 | * Livingston Enterprises, Inc. makes no representations about | |
30 | * the suitability of this software for any purpose. It is | |
31 | * provided "as is" without express or implied warranty. | |
32 | * | |
33 | * The new parts of the code is Copyright (C) 1998 R.M. van Selm <selm@cistron.nl> | |
34 | * with modifications | |
35 | * Copyright (C) 2004 Henrik Nordstrom <hno@squid-cache.org> | |
36 | * Copyright (C) 2006 Henrik Nordstrom <hno@squid-cache.org> | |
37 | */ | |
38 | ||
5a48ed18 | 39 | /* basic_radius_auth is a RADIUS authenticator for Squid-2.5 and later. |
d80aac12 | 40 | * The authenticator reads a line with a user and password combination. |
41 | * If access is granted OK is returned. Else ERR. | |
42 | * | |
5a48ed18 | 43 | * basic_radius_auth-1.0 is based on modules from the Cistron-radiusd-1.5.4. |
d80aac12 | 44 | * |
45 | * Currently you should only start 1 authentificator at a time because the | |
46 | * the ID's of the different programs can start to conflict. I'm not sure it | |
47 | * would help anyway. I think the RADIUS server is close by and I don't think | |
48 | * it will handle requests in parallel anyway (correct me if I'm wrong here) | |
49 | * | |
50 | * Marc van Selm <selm@cistron.nl> | |
51 | * with contributions from | |
52 | * Henrik Nordstrom <hno@squid-cache.org> | |
53 | * and many others | |
54 | */ | |
55 | ||
f7f3304a | 56 | #include "squid.h" |
03901cf8 AJ |
57 | #include "auth/basic/RADIUS/radius-util.h" |
58 | #include "auth/basic/RADIUS/radius.h" | |
079b1d0f | 59 | #include "helper/protocol_defines.h" |
43fed740 | 60 | #include "md5.h" |
a8b30ac9 | 61 | |
074d6a40 AJ |
62 | #include <cctype> |
63 | #include <cerrno> | |
64 | #include <cstring> | |
65 | #include <ctime> | |
fce06581 | 66 | #include <random> |
a8b30ac9 | 67 | #if HAVE_SYS_SOCKET_H |
5a48ed18 | 68 | #include <sys/socket.h> |
a8b30ac9 | 69 | #endif |
70 | #if HAVE_NETINET_IN_H | |
5a48ed18 | 71 | #include <netinet/in.h> |
a8b30ac9 | 72 | #endif |
a8b30ac9 | 73 | #if HAVE_UNISTD_H |
5a48ed18 | 74 | #include <unistd.h> |
a8b30ac9 | 75 | #endif |
76 | #if HAVE_FCNTL_H | |
5a48ed18 | 77 | #include <fcntl.h> |
a8b30ac9 | 78 | #endif |
be266cb2 | 79 | #if _SQUID_WINDOWS_ |
757bcd6b GS |
80 | #include <io.h> |
81 | #endif | |
a8b30ac9 | 82 | #if HAVE_UNISTD_H |
5a48ed18 | 83 | #include <unistd.h> |
a8b30ac9 | 84 | #endif |
85 | #if HAVE_NETDB_H | |
5a48ed18 | 86 | #include <netdb.h> |
a8b30ac9 | 87 | #endif |
88 | #if HAVE_PWD_H | |
5a48ed18 | 89 | #include <pwd.h> |
a8b30ac9 | 90 | #endif |
757bcd6b GS |
91 | #if HAVE_GETOPT_H |
92 | #include <getopt.h> | |
93 | #endif | |
d80aac12 | 94 | |
43fed740 | 95 | /* AYJ: helper input buffer may be a lot larger than this used to expect... */ |
f53969cc SM |
96 | #define MAXPWNAM 254 |
97 | #define MAXPASS 254 | |
98 | #define MAXLINE 254 | |
d80aac12 | 99 | |
2e7c8541 | 100 | static void md5_calc(uint8_t out[16], void *in, size_t len); |
d80aac12 | 101 | |
102 | static int i_send_buffer[2048]; | |
103 | static int i_recv_buffer[2048]; | |
104 | static char *send_buffer = (char *) i_send_buffer; | |
105 | static char *recv_buffer = (char *) i_recv_buffer; | |
106 | static int sockfd; | |
0afdb165 | 107 | static u_char request_id; |
d80aac12 | 108 | static char vector[AUTH_VECTOR_LEN]; |
109 | static char secretkey[MAXPASS + 1] = ""; | |
110 | static char server[MAXLINE] = ""; | |
111 | static char identifier[MAXLINE] = ""; | |
112 | static char svc_name[MAXLINE] = "radius"; | |
113 | static int nasport = 111; | |
114 | static int nasporttype = 0; | |
09aabd84 FC |
115 | static uint32_t nas_ipaddr; |
116 | static uint32_t auth_ipaddr; | |
6ec3c3f6 | 117 | static int retries = 10; |
d80aac12 | 118 | |
5a48ed18 | 119 | char progname[] = "basic_radius_auth"; |
d80aac12 | 120 | |
7aa9bb3e | 121 | #if _SQUID_WINDOWS_ |
ec556193 GS |
122 | void |
123 | Win32SockCleanup(void) | |
124 | { | |
125 | WSACleanup(); | |
126 | return; | |
127 | } | |
1191b93b | 128 | #endif |
ec556193 | 129 | |
d80aac12 | 130 | /* |
131 | * Diff two timeval, b - a | |
132 | */ | |
133 | static int | |
134 | timeval_diff(const struct timeval *a, const struct timeval *b) | |
135 | { | |
136 | return (b->tv_sec - a->tv_sec) * 1000000 + (b->tv_usec - a->tv_usec); | |
137 | } | |
138 | ||
139 | /* | |
140 | * Time since a timeval | |
141 | */ | |
142 | static int | |
143 | time_since(const struct timeval *when) | |
144 | { | |
145 | struct timeval now; | |
146 | gettimeofday(&now, NULL); | |
147 | return timeval_diff(when, &now); | |
148 | } | |
149 | ||
a8b30ac9 | 150 | /* |
151 | * MD5 digest | |
152 | */ | |
153 | static void | |
154 | md5_calc(uint8_t out[16], void *in, size_t len) | |
155 | { | |
628ac45c | 156 | SquidMD5_CTX ctx; |
157 | SquidMD5Init(&ctx); | |
158 | SquidMD5Update(&ctx, in, len); | |
159 | SquidMD5Final(out, &ctx); | |
a8b30ac9 | 160 | } |
161 | ||
d80aac12 | 162 | /* |
163 | * Receive and verify the result. | |
164 | */ | |
165 | static int | |
ced8def3 | 166 | result_recv(char *buffer, int length) |
d80aac12 | 167 | { |
168 | AUTH_HDR *auth; | |
169 | int totallen; | |
170 | unsigned char reply_digest[AUTH_VECTOR_LEN]; | |
171 | unsigned char calc_digest[AUTH_VECTOR_LEN]; | |
172 | int secretlen; | |
173 | /* VALUE_PAIR *req; */ | |
174 | ||
175 | auth = (AUTH_HDR *) buffer; | |
176 | totallen = ntohs(auth->length); | |
177 | ||
178 | if (totallen != length) { | |
43fed740 | 179 | debug("Received invalid reply length from server (want %d/ got %d)\n", totallen, length); |
26ac0430 | 180 | return -1; |
d80aac12 | 181 | } |
d80aac12 | 182 | if (auth->id != request_id) { |
26ac0430 AJ |
183 | /* Duplicate response of an earlier query, ignore */ |
184 | return -1; | |
d80aac12 | 185 | } |
d80aac12 | 186 | /* Verify the reply digest */ |
187 | memcpy(reply_digest, auth->vector, AUTH_VECTOR_LEN); | |
188 | memcpy(auth->vector, vector, AUTH_VECTOR_LEN); | |
189 | secretlen = strlen(secretkey); | |
190 | memcpy(buffer + length, secretkey, secretlen); | |
191 | md5_calc(calc_digest, (unsigned char *) auth, length + secretlen); | |
192 | ||
193 | if (memcmp(reply_digest, calc_digest, AUTH_VECTOR_LEN) != 0) { | |
43fed740 | 194 | debug("WARNING: Received invalid reply digest from server\n"); |
26ac0430 | 195 | return -1; |
d80aac12 | 196 | } |
d80aac12 | 197 | if (auth->code != PW_AUTHENTICATION_ACK) |
26ac0430 | 198 | return 1; |
d80aac12 | 199 | |
200 | return 0; | |
201 | } | |
202 | ||
d80aac12 | 203 | /* |
204 | * Generate a random vector. | |
205 | */ | |
206 | static void | |
d5f8d05f | 207 | random_vector(char *aVector) |
d80aac12 | 208 | { |
fce06581 | 209 | static std::mt19937 mt(time(0)); |
8ed8fa40 | 210 | static xuniform_int_distribution<uint8_t> dist; |
fce06581 AJ |
211 | |
212 | for (int i = 0; i < AUTH_VECTOR_LEN; ++i) | |
213 | aVector[i] = static_cast<char>(dist(mt) & 0xFF); | |
d80aac12 | 214 | } |
215 | ||
216 | /* read the config file | |
217 | * The format should be something like: | |
5a48ed18 | 218 | * # basic_radius_auth configuration file |
d80aac12 | 219 | * # MvS: 28-10-1998 |
220 | * server suncone.cistron.nl | |
221 | * secret testje | |
222 | */ | |
223 | static int | |
224 | rad_auth_config(const char *cfname) | |
225 | { | |
226 | FILE *cf; | |
227 | char line[MAXLINE]; | |
228 | int srv = 0, crt = 0; | |
229 | ||
230 | if ((cf = fopen(cfname, "r")) == NULL) { | |
26ac0430 AJ |
231 | perror(cfname); |
232 | return -1; | |
d80aac12 | 233 | } |
234 | while (fgets(line, MAXLINE, cf) != NULL) { | |
26ac0430 AJ |
235 | if (!memcmp(line, "server", 6)) |
236 | srv = sscanf(line, "server %s", server); | |
237 | if (!memcmp(line, "secret", 6)) | |
238 | crt = sscanf(line, "secret %s", secretkey); | |
239 | if (!memcmp(line, "identifier", 10)) | |
240 | sscanf(line, "identifier %s", identifier); | |
241 | if (!memcmp(line, "service", 7)) | |
242 | sscanf(line, "service %s", svc_name); | |
243 | if (!memcmp(line, "port", 4)) | |
244 | sscanf(line, "port %s", svc_name); | |
6ec3c3f6 AM |
245 | if (!memcmp(line, "timeout", 7)) |
246 | sscanf(line, "timeout %d", &retries); | |
d80aac12 | 247 | } |
32ae6cde | 248 | fclose(cf); |
d80aac12 | 249 | if (srv && crt) |
26ac0430 | 250 | return 0; |
d80aac12 | 251 | return -1; |
252 | } | |
253 | ||
254 | static void | |
255 | urldecode(char *dst, const char *src, int size) | |
256 | { | |
257 | char tmp[3]; | |
258 | tmp[2] = '\0'; | |
259 | while (*src && size > 1) { | |
26ac0430 | 260 | if (*src == '%' && src[1] != '\0' && src[2] != '\0') { |
eb62585f | 261 | ++src; |
14942edd FC |
262 | tmp[0] = *src; |
263 | ++src; | |
264 | tmp[1] = *src; | |
265 | ++src; | |
f207fe64 FC |
266 | *dst = strtol(tmp, NULL, 16); |
267 | ++dst; | |
26ac0430 | 268 | } else { |
14942edd FC |
269 | *dst = *src; |
270 | ++dst; | |
271 | ++src; | |
26ac0430 | 272 | } |
eb62585f | 273 | --size; |
d80aac12 | 274 | } |
eb62585f | 275 | *dst = '\0'; |
d80aac12 | 276 | } |
277 | ||
6ec3c3f6 | 278 | static void |
e053c141 | 279 | authenticate(int socket_fd, const char *username, const char *passwd) |
d80aac12 | 280 | { |
281 | AUTH_HDR *auth; | |
f45dd259 | 282 | unsigned short total_length; |
d80aac12 | 283 | u_char *ptr; |
284 | int length; | |
285 | char passbuf[MAXPASS]; | |
286 | u_char md5buf[256]; | |
287 | int secretlen; | |
288 | u_char cbc[AUTH_VECTOR_LEN]; | |
289 | int i, j; | |
09aabd84 | 290 | uint32_t ui; |
d80aac12 | 291 | struct sockaddr_in saremote; |
292 | fd_set readfds; | |
293 | socklen_t salen; | |
294 | int retry = retries; | |
295 | ||
296 | /* | |
297 | * Build an authentication request | |
298 | */ | |
299 | auth = (AUTH_HDR *) send_buffer; | |
300 | auth->code = PW_AUTHENTICATION_REQUEST; | |
301 | auth->id = ++request_id; | |
302 | random_vector(vector); | |
303 | memcpy(auth->vector, vector, AUTH_VECTOR_LEN); | |
304 | total_length = AUTH_HDR_LEN; | |
305 | ptr = auth->data; | |
306 | ||
307 | /* | |
308 | * User Name | |
309 | */ | |
f207fe64 FC |
310 | *ptr = PW_USER_NAME; |
311 | ++ptr; | |
d80aac12 | 312 | length = strlen(username); |
313 | if (length > MAXPWNAM) { | |
26ac0430 | 314 | length = MAXPWNAM; |
d80aac12 | 315 | } |
f207fe64 | 316 | *ptr = length + 2; |
69c954eb | 317 | ptr = (unsigned char*)send_buffer + sizeof(AUTH_HDR); |
d80aac12 | 318 | memcpy(ptr, username, length); |
319 | ptr += length; | |
320 | total_length += length + 2; | |
321 | ||
322 | /* | |
323 | * Password | |
324 | */ | |
325 | length = strlen(passwd); | |
326 | if (length > MAXPASS) { | |
26ac0430 | 327 | length = MAXPASS; |
d80aac12 | 328 | } |
329 | memset(passbuf, 0, MAXPASS); | |
330 | memcpy(passbuf, passwd, length); | |
331 | ||
26ac0430 | 332 | /* |
d80aac12 | 333 | * Length is rounded up to multiple of 16, |
26ac0430 | 334 | * and the password is encoded in blocks of 16 |
d80aac12 | 335 | * with cipher block chaining |
336 | */ | |
337 | length = ((length / AUTH_VECTOR_LEN) + 1) * AUTH_VECTOR_LEN; | |
338 | ||
f207fe64 FC |
339 | *ptr = PW_PASSWORD; |
340 | ++ptr; | |
341 | *ptr = length + 2; | |
342 | ++ptr; | |
d80aac12 | 343 | |
344 | secretlen = strlen(secretkey); | |
345 | /* Set up the Cipher block chain */ | |
346 | memcpy(cbc, auth->vector, AUTH_VECTOR_LEN); | |
347 | for (j = 0; j < length; j += AUTH_VECTOR_LEN) { | |
26ac0430 AJ |
348 | /* Calculate the MD5 Digest */ |
349 | strcpy((char *) md5buf, secretkey); | |
350 | memcpy(md5buf + secretlen, cbc, AUTH_VECTOR_LEN); | |
351 | md5_calc(cbc, md5buf, secretlen + AUTH_VECTOR_LEN); | |
352 | ||
353 | /* Xor the password into the MD5 digest */ | |
eb62585f | 354 | for (i = 0; i < AUTH_VECTOR_LEN; ++i) { |
f207fe64 FC |
355 | *ptr = (cbc[i] ^= passbuf[j + i]); |
356 | ++ptr; | |
26ac0430 | 357 | } |
d80aac12 | 358 | } |
359 | total_length += length + 2; | |
360 | ||
f207fe64 FC |
361 | *ptr = PW_NAS_PORT_ID; |
362 | ++ptr; | |
363 | *ptr = 6; | |
364 | ++ptr; | |
d80aac12 | 365 | |
366 | ui = htonl(nasport); | |
367 | memcpy(ptr, &ui, 4); | |
368 | ptr += 4; | |
369 | total_length += 6; | |
370 | ||
f207fe64 FC |
371 | *ptr = PW_NAS_PORT_TYPE; |
372 | ++ptr; | |
373 | *ptr = 6; | |
374 | ++ptr; | |
d80aac12 | 375 | |
376 | ui = htonl(nasporttype); | |
377 | memcpy(ptr, &ui, 4); | |
378 | ptr += 4; | |
379 | total_length += 6; | |
380 | ||
381 | if (*identifier) { | |
26ac0430 | 382 | int len = strlen(identifier); |
f207fe64 FC |
383 | *ptr = PW_NAS_ID; |
384 | ++ptr; | |
385 | *ptr = len + 2; | |
386 | ++ptr; | |
26ac0430 AJ |
387 | memcpy(ptr, identifier, len); |
388 | ptr += len; | |
f9acc802 | 389 | total_length += len + 2; |
d80aac12 | 390 | } else { |
f207fe64 FC |
391 | *ptr = PW_NAS_IP_ADDRESS; |
392 | ++ptr; | |
393 | *ptr = 6; | |
394 | ++ptr; | |
d80aac12 | 395 | |
26ac0430 AJ |
396 | ui = htonl(nas_ipaddr); |
397 | memcpy(ptr, &ui, 4); | |
398 | ptr += 4; | |
399 | total_length += 6; | |
d80aac12 | 400 | } |
401 | ||
402 | /* Klaus Weidner <kw@w-m-p.com> changed this | |
403 | * from htonl to htons. It might have caused | |
404 | * you trouble or not. That depends on the byte | |
405 | * order of your system. | |
406 | * The symptom was that the radius server | |
26ac0430 | 407 | * ignored the requests, because they had zero |
d80aac12 | 408 | * length according to the data header. |
409 | */ | |
410 | auth->length = htons(total_length); | |
411 | ||
eb62585f FC |
412 | while (retry) { |
413 | --retry; | |
26ac0430 AJ |
414 | int time_spent; |
415 | struct timeval sent; | |
416 | /* | |
417 | * Send the request we've built. | |
418 | */ | |
419 | gettimeofday(&sent, NULL); | |
69c954eb | 420 | if (send(socket_fd, (char *) auth, total_length, 0) < 0) { |
b69e9ffa | 421 | int xerrno = errno; |
69c954eb AJ |
422 | // EAGAIN is expected at high traffic, just retry |
423 | // TODO: block/sleep a few ms to let the apparently full buffer drain ? | |
b69e9ffa AJ |
424 | if (xerrno != EAGAIN && xerrno != EWOULDBLOCK) |
425 | fprintf(stderr,"ERROR: RADIUS send() failure: %s\n", xstrerr(xerrno)); | |
69c954eb AJ |
426 | continue; |
427 | } | |
26ac0430 AJ |
428 | while ((time_spent = time_since(&sent)) < 1000000) { |
429 | struct timeval tv; | |
430 | int rc, len; | |
431 | if (!time_spent) { | |
432 | tv.tv_sec = 1; | |
433 | tv.tv_usec = 0; | |
434 | } else { | |
435 | tv.tv_sec = 0; | |
436 | tv.tv_usec = 1000000 - time_spent; | |
437 | } | |
438 | FD_ZERO(&readfds); | |
e053c141 | 439 | FD_SET(socket_fd, &readfds); |
f53969cc | 440 | if (select(socket_fd + 1, &readfds, NULL, NULL, &tv) == 0) /* Select timeout */ |
26ac0430 AJ |
441 | break; |
442 | salen = sizeof(saremote); | |
e053c141 | 443 | len = recvfrom(socket_fd, recv_buffer, sizeof(i_recv_buffer), |
26ac0430 AJ |
444 | 0, (struct sockaddr *) &saremote, &salen); |
445 | ||
446 | if (len < 0) | |
447 | continue; | |
448 | ||
ced8def3 | 449 | rc = result_recv(recv_buffer, len); |
6ec3c3f6 AM |
450 | if (rc == 0) { |
451 | SEND_OK(""); | |
452 | return; | |
453 | } | |
454 | if (rc == 1) { | |
455 | SEND_ERR(""); | |
456 | return; | |
457 | } | |
26ac0430 | 458 | } |
d80aac12 | 459 | } |
460 | ||
461 | fprintf(stderr, "%s: No response from RADIUS server\n", progname); | |
6ec3c3f6 AM |
462 | SEND_ERR("No response from RADIUS server"); |
463 | return; | |
d80aac12 | 464 | } |
465 | ||
466 | int | |
467 | main(int argc, char **argv) | |
468 | { | |
469 | struct sockaddr_in salocal; | |
470 | struct sockaddr_in saremote; | |
471 | struct servent *svp; | |
f45dd259 | 472 | unsigned short svc_port; |
d80aac12 | 473 | char username[MAXPWNAM]; |
474 | char passwd[MAXPASS]; | |
475 | char *ptr; | |
43fed740 | 476 | char buf[HELPER_INPUT_BUFFER]; |
d80aac12 | 477 | const char *cfname = NULL; |
478 | int err = 0; | |
479 | socklen_t salen; | |
480 | int c; | |
481 | ||
482 | while ((c = getopt(argc, argv, "h:p:f:w:i:t:")) != -1) { | |
26ac0430 | 483 | switch (c) { |
e673ba3a AJ |
484 | case 'd': |
485 | debug_enabled = 1; | |
486 | break; | |
26ac0430 AJ |
487 | case 'f': |
488 | cfname = optarg; | |
489 | break; | |
490 | case 'h': | |
53cb2c80 AJ |
491 | strncpy(server, optarg, sizeof(server)-1); |
492 | server[sizeof(server)-1] = '\0'; | |
26ac0430 AJ |
493 | break; |
494 | case 'p': | |
53cb2c80 AJ |
495 | strncpy(svc_name, optarg, sizeof(svc_name)-1); |
496 | svc_name[sizeof(svc_name)-1] = '\0'; | |
26ac0430 AJ |
497 | break; |
498 | case 'w': | |
53cb2c80 AJ |
499 | strncpy(secretkey, optarg, sizeof(secretkey)-1); |
500 | secretkey[sizeof(secretkey)-1] = '\0'; | |
26ac0430 AJ |
501 | break; |
502 | case 'i': | |
53cb2c80 AJ |
503 | strncpy(identifier, optarg, sizeof(identifier)-1); |
504 | identifier[sizeof(identifier)-1] = '\0'; | |
26ac0430 AJ |
505 | break; |
506 | case 't': | |
507 | retries = atoi(optarg); | |
508 | break; | |
509 | } | |
d80aac12 | 510 | } |
511 | /* make standard output line buffered */ | |
512 | if (setvbuf(stdout, NULL, _IOLBF, 0) != 0) | |
26ac0430 | 513 | return 1; |
d80aac12 | 514 | |
515 | if (cfname) { | |
26ac0430 | 516 | if (rad_auth_config(cfname) < 0) { |
43fed740 | 517 | fprintf(stderr, "FATAL: %s: can't open configuration file '%s'.\n", argv[0], cfname); |
26ac0430 AJ |
518 | exit(1); |
519 | } | |
d80aac12 | 520 | } |
d80aac12 | 521 | if (!*server) { |
43fed740 | 522 | fprintf(stderr, "FATAL: %s: Server not specified\n", argv[0]); |
26ac0430 | 523 | exit(1); |
d80aac12 | 524 | } |
d80aac12 | 525 | if (!*secretkey) { |
43fed740 | 526 | fprintf(stderr, "FATAL: %s: Shared secret not specified\n", argv[0]); |
26ac0430 | 527 | exit(1); |
d80aac12 | 528 | } |
7aa9bb3e | 529 | #if _SQUID_WINDOWS_ |
757bcd6b | 530 | { |
26ac0430 AJ |
531 | WSADATA wsaData; |
532 | WSAStartup(2, &wsaData); | |
533 | atexit(Win32SockCleanup); | |
757bcd6b GS |
534 | } |
535 | #endif | |
d80aac12 | 536 | /* |
537 | * Open a connection to the server. | |
538 | */ | |
539 | svp = getservbyname(svc_name, "udp"); | |
540 | if (svp != NULL) | |
f45dd259 | 541 | svc_port = ntohs((unsigned short) svp->s_port); |
d80aac12 | 542 | else |
26ac0430 | 543 | svc_port = atoi(svc_name); |
d80aac12 | 544 | if (svc_port == 0) |
26ac0430 | 545 | svc_port = PW_AUTH_UDP_PORT; |
d80aac12 | 546 | |
547 | /* Get the IP address of the authentication server */ | |
548 | if ((auth_ipaddr = get_ipaddr(server)) == 0) { | |
43fed740 | 549 | fprintf(stderr, "FATAL: %s: Couldn't find host %s\n", argv[0], server); |
26ac0430 | 550 | exit(1); |
d80aac12 | 551 | } |
552 | sockfd = socket(AF_INET, SOCK_DGRAM, 0); | |
553 | if (sockfd < 0) { | |
26ac0430 AJ |
554 | perror("socket"); |
555 | exit(1); | |
d80aac12 | 556 | } |
557 | memset(&saremote, 0, sizeof(saremote)); | |
558 | saremote.sin_family = AF_INET; | |
559 | saremote.sin_addr.s_addr = htonl(auth_ipaddr); | |
560 | saremote.sin_port = htons(svc_port); | |
561 | ||
562 | if (connect(sockfd, (struct sockaddr *) &saremote, sizeof(saremote)) < 0) { | |
26ac0430 AJ |
563 | perror("connect"); |
564 | exit(1); | |
d80aac12 | 565 | } |
566 | salen = sizeof(salocal); | |
567 | if (getsockname(sockfd, (struct sockaddr *) &salocal, &salen) < 0) { | |
26ac0430 AJ |
568 | perror("getsockname"); |
569 | exit(1); | |
d80aac12 | 570 | } |
571 | #ifdef O_NONBLOCK | |
69c954eb | 572 | if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL, 0) | O_NONBLOCK) < 0) { |
b69e9ffa AJ |
573 | int xerrno = errno; |
574 | fprintf(stderr,"%s| ERROR: fcntl() failure: %s\n", argv[0], xstrerr(xerrno)); | |
69c954eb AJ |
575 | exit(1); |
576 | } | |
d80aac12 | 577 | #endif |
578 | nas_ipaddr = ntohl(salocal.sin_addr.s_addr); | |
43fed740 | 579 | while (fgets(buf, HELPER_INPUT_BUFFER, stdin) != NULL) { |
26ac0430 AJ |
580 | char *end; |
581 | /* protect me form to long lines */ | |
43fed740 | 582 | if ((end = strchr(buf, '\n')) == NULL) { |
26ac0430 AJ |
583 | err = 1; |
584 | continue; | |
585 | } | |
586 | if (err) { | |
43fed740 | 587 | SEND_ERR(""); |
26ac0430 AJ |
588 | err = 0; |
589 | continue; | |
590 | } | |
43fed740 AJ |
591 | if (strlen(buf) > HELPER_INPUT_BUFFER) { |
592 | SEND_ERR(""); | |
26ac0430 AJ |
593 | continue; |
594 | } | |
595 | /* Strip off the trailing newline */ | |
596 | *end = '\0'; | |
597 | ||
598 | /* Parse out the username and password */ | |
43fed740 | 599 | ptr = buf; |
26ac0430 | 600 | while (isspace(*ptr)) |
eb62585f | 601 | ++ptr; |
26ac0430 | 602 | if ((end = strchr(ptr, ' ')) == NULL) { |
43fed740 | 603 | SEND_ERR("No password"); |
26ac0430 AJ |
604 | continue; |
605 | } | |
606 | *end = '\0'; | |
607 | urldecode(username, ptr, MAXPWNAM); | |
608 | ptr = end + 1; | |
609 | while (isspace(*ptr)) | |
eb62585f | 610 | ++ptr; |
26ac0430 AJ |
611 | urldecode(passwd, ptr, MAXPASS); |
612 | ||
6ec3c3f6 | 613 | authenticate(sockfd, username, passwd); |
d80aac12 | 614 | } |
615 | close(sockfd); | |
616 | exit(1); | |
617 | } | |
f53969cc | 618 |