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