]> jfr.im git - solanum.git/blame - authd/providers/opm.c
ircd: wsproc: cleanups
[solanum.git] / authd / providers / opm.c
CommitLineData
4e85459a
EM
1/* authd/providers/opm.c - small open proxy monitor
2 * Copyright (c) 2016 Elizabeth Myers <elizabeth@interlinked.me>
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice is present in all copies.
7 *
8 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
9 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
11 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
12 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
13 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
14 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
15 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
16 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
17 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
18 * POSSIBILITY OF SUCH DAMAGE.
19 */
20
468ef960 21#include "rb_lib.h"
4e85459a
EM
22#include "stdinc.h"
23#include "setup.h"
24#include "authd.h"
25#include "notice.h"
26#include "provider.h"
27
28#define OPM_READSIZE 128
29
30typedef enum protocol_t
31{
32 PROTO_NONE,
33 PROTO_SOCKS4,
34 PROTO_SOCKS5,
35} protocol_t;
36
37struct opm_lookup
38{
39 rb_dlink_list scans; /* List of scans */
40};
41
42struct opm_proxy
43{
1de169a2 44 char note[16];
4e85459a
EM
45 protocol_t proto;
46 uint16_t port;
1de169a2
EM
47
48 rb_dlink_node node;
4e85459a
EM
49};
50
51struct opm_scan
52{
53 struct auth_client *auth;
54
55 struct opm_proxy *proxy;
56 rb_fde_t *F; /* fd for scan */
57
58 rb_dlink_node node;
59};
60
61struct opm_listener
62{
63 char ip[HOSTIPLEN];
64 uint16_t port;
766d4ffc 65 struct rb_sockaddr_storage addr;
4e85459a
EM
66 rb_fde_t *F;
67};
68
69/* Proxies that we scan for */
1de169a2 70static rb_dlink_list proxy_scanners;
4e85459a
EM
71
72static ACCB accept_opm;
73static PF read_opm_reply;
74
75static CNCB socks4_connected;
76static CNCB socks5_connected;
77
78static void opm_cancel(struct auth_client *auth);
4deb334f 79static bool create_listener(const char *ip, uint16_t port);
4e85459a 80
8275e270 81static int opm_timeout = 10;
4e85459a
EM
82static bool opm_enable = false;
83
84#define LISTEN_IPV4 0
85#define LISTEN_IPV6 1
86
87/* IPv4 and IPv6 */
88static struct opm_listener listeners[2];
89
1de169a2
EM
90static inline protocol_t
91get_protocol_from_string(const char *string)
92{
93 if(strcasecmp(string, "socks4") == 0)
94 return PROTO_SOCKS4;
95 else if(strcasecmp(string, "socks5") == 0)
96 return PROTO_SOCKS5;
97 else
98 return PROTO_NONE;
99}
100
101static inline struct opm_proxy *
102find_proxy_scanner(protocol_t proto, uint16_t port)
103{
104 rb_dlink_node *ptr;
105
106 RB_DLINK_FOREACH(ptr, proxy_scanners.head)
107 {
108 struct opm_proxy *proxy = ptr->data;
109
110 if(proxy->proto == proto && proxy->port == port)
111 return proxy;
112 }
113
114 return NULL;
115}
4e85459a
EM
116
117static void
118read_opm_reply(rb_fde_t *F, void *data)
119{
1de169a2 120 rb_dlink_node *ptr;
4e85459a
EM
121 struct auth_client *auth = data;
122 struct opm_lookup *lookup;
123 char readbuf[OPM_READSIZE];
124 ssize_t len;
125
126 if(auth == NULL || (lookup = auth->data[PROVIDER_OPM]) == NULL)
127 {
128 rb_close(F);
129 return;
130 }
131
132 if((len = rb_read(F, readbuf, sizeof(readbuf))) < 0 && rb_ignore_errno(errno))
133 {
134 rb_setselect(F, RB_SELECT_READ, read_opm_reply, auth);
135 return;
136 }
137 else if(len <= 0)
138 {
139 /* Dead */
140 rb_close(F);
141 return;
142 }
143
1de169a2 144 RB_DLINK_FOREACH(ptr, proxy_scanners.head)
4e85459a 145 {
1de169a2
EM
146 struct opm_proxy *proxy = ptr->data;
147
8860e46a
EM
148 if(strncmp(proxy->note, readbuf, sizeof(readbuf)) == 0)
149 {
150 rb_dlink_node *ptr, *nptr;
151
152 /* Cancel outstanding lookups */
153 RB_DLINK_FOREACH_SAFE(ptr, nptr, lookup->scans.head)
154 {
155 struct opm_scan *scan = ptr->data;
156
157 rb_close(scan->F);
158 rb_free(scan);
159 }
160
161 /* No longer needed, client is going away */
162 rb_free(lookup);
163
164 reject_client(auth, PROVIDER_OPM, readbuf, "Open proxy detected");
165 break;
166 }
4e85459a
EM
167 }
168
169 rb_close(F);
170}
171
172static void
173accept_opm(rb_fde_t *F, int status, struct sockaddr *addr, rb_socklen_t len, void *data)
174{
175 struct auth_client *auth = NULL;
176 struct opm_listener *listener = data;
272af6a5 177 struct rb_sockaddr_storage localaddr;
4e85459a
EM
178 unsigned int llen = sizeof(struct rb_sockaddr_storage);
179 rb_dictionary_iter iter;
180
181 if(status != 0 || listener == NULL)
182 {
183 rb_close(F);
184 return;
185 }
186
272af6a5 187 if(getsockname(rb_get_fd(F), (struct sockaddr *)&localaddr, &llen))
4e85459a
EM
188 {
189 /* This can happen if the client goes away after accept */
190 rb_close(F);
191 return;
192 }
193
194 /* Correlate connection with client(s) */
195 RB_DICTIONARY_FOREACH(auth, &iter, auth_clients)
196 {
272af6a5 197 if(GET_SS_FAMILY(&auth->c_addr) != GET_SS_FAMILY(&localaddr))
4e85459a
EM
198 continue;
199
200 /* Compare the addresses */
272af6a5 201 switch(GET_SS_FAMILY(&localaddr))
4e85459a
EM
202 {
203 case AF_INET:
204 {
272af6a5 205 struct sockaddr_in *s = (struct sockaddr_in *)&localaddr, *c = (struct sockaddr_in *)&auth->c_addr;
4e85459a
EM
206
207 if(s->sin_addr.s_addr == c->sin_addr.s_addr)
208 {
209 /* Match... check if it's real */
210 rb_setselect(F, RB_SELECT_READ, read_opm_reply, auth);
211 return;
212 }
213 break;
214 }
215#ifdef RB_IPV6
216 case AF_INET6:
217 {
272af6a5 218 struct sockaddr_in6 *s = (struct sockaddr_in6 *)&localaddr, *c = (struct sockaddr_in6 *)&auth->c_addr;
4e85459a 219
d86692fa 220 if(IN6_ARE_ADDR_EQUAL(&s->sin6_addr, &c->sin6_addr))
4e85459a
EM
221 {
222 rb_setselect(F, RB_SELECT_READ, read_opm_reply, auth);
223 return;
224 }
225 break;
226 }
227#endif
228 default:
229 warn_opers(L_CRIT, "OPM: unknown address type in listen function");
230 exit(EX_PROVIDER_ERROR);
231 }
232 }
233
234 /* We don't care about the socket if we get here */
235 rb_close(F);
236}
237
238/* Scanners */
239
240static void
241socks4_connected(rb_fde_t *F, int error, void *data)
242{
243 struct opm_scan *scan = data;
244 struct opm_lookup *lookup;
245 struct auth_client *auth;
246 uint8_t sendbuf[9]; /* Size we're building */
247 uint8_t *c = sendbuf;
248 ssize_t ret;
249
250 if(scan == NULL || (auth = scan->auth) == NULL || (lookup = auth->data[PROVIDER_OPM]) == NULL)
251 return;
252
253 if(error || !opm_enable)
254 goto end;
255
256 memcpy(c, "\x04\x01", 2); c += 2; /* Socks version 4, connect command */
257
258 switch(GET_SS_FAMILY(&auth->c_addr))
259 {
260 case AF_INET:
261 if(listeners[LISTEN_IPV4].F == NULL)
262 /* They cannot respond to us */
263 goto end;
264
265 memcpy(c, &(((struct sockaddr_in *)&listeners[LISTEN_IPV4].addr)->sin_port), 2); c += 2; /* Port */
266 memcpy(c, &(((struct sockaddr_in *)&listeners[LISTEN_IPV4].addr)->sin_addr.s_addr), 4); c += 4; /* Address */
267 break;
268#ifdef RB_IPV6
269 case AF_INET6:
270 /* socks4 doesn't support IPv6 */
271#endif
272 default:
273 goto end;
274 }
275
276 *c = '\x00'; /* No userid */
277
278 /* Send header */
279 if(rb_write(scan->F, sendbuf, sizeof(sendbuf)) < 0)
280 goto end;
281
282 /* Send note */
283 if(rb_write(scan->F, scan->proxy->note, strlen(scan->proxy->note) + 1) < 0)
284 goto end;
285
286end:
287 rb_close(scan->F);
288 rb_dlinkDelete(&scan->node, &lookup->scans);
289 rb_free(scan);
290}
291
292static void
293socks5_connected(rb_fde_t *F, int error, void *data)
294{
295 struct opm_scan *scan = data;
296 struct opm_lookup *lookup;
297 struct opm_listener *listener;
298 struct auth_client *auth;
299 uint8_t sendbuf[25]; /* Size we're building */
300 uint8_t *c = sendbuf;
301 ssize_t ret;
302
303 if(scan == NULL || (auth = scan->auth) == NULL || (lookup = auth->data[PROVIDER_OPM]) == NULL)
304 return;
305
306 if(error || !opm_enable)
307 goto end;
308
309 /* Build the version header and socks request
310 * version header (3 bytes): version, number of auth methods, auth type (0 for none)
311 * connect req (3 bytes): version, command (1 = connect), reserved (0)
312 */
313 memcpy(c, "\x05\x01\x00\x05\x01\x00", 6); c += 6;
314
315 switch(GET_SS_FAMILY(&auth->c_addr))
316 {
317 case AF_INET:
318 listener = &listeners[LISTEN_IPV4];
319 if(!listener->F)
320 goto end;
321
322 *(c++) = '\x01'; /* Address type (1 = IPv4) */
323 memcpy(c, &(((struct sockaddr_in *)&listener->addr)->sin_addr.s_addr), 4); c += 4;/* Address */
324 memcpy(c, &(((struct sockaddr_in *)&listener->addr)->sin_port), 2); c += 2; /* Port */
325 break;
326#ifdef RB_IPV6
327 case AF_INET6:
328 listener = &listeners[LISTEN_IPV6];
329 if(!listener->F)
330 goto end;
331
332 *(c++) = '\x04'; /* Address type (4 = IPv6) */
333 memcpy(c, ((struct sockaddr_in6 *)&listener->addr)->sin6_addr.s6_addr, 16); c += 16; /* Address */
334 memcpy(c, &(((struct sockaddr_in6 *)&listener->addr)->sin6_port), 2); c += 2; /* Port */
335 break;
336#endif
337 default:
338 goto end;
339 }
340
341 /* Send header */
342 if(rb_write(scan->F, sendbuf, (size_t)(sendbuf - c)) <= 0)
343 goto end;
344
345 /* Now the note in a separate write */
346 if(rb_write(scan->F, scan->proxy->note, strlen(scan->proxy->note) + 1) <= 0)
347 goto end;
348
349end:
350 rb_close(scan->F);
351 rb_dlinkDelete(&scan->node, &lookup->scans);
352 rb_free(scan);
353}
354
355/* Establish connections */
356static inline void
357establish_connection(struct auth_client *auth, struct opm_proxy *proxy)
358{
359 struct opm_lookup *lookup = auth->data[PROVIDER_OPM];
360 struct opm_listener *listener;
361 struct opm_scan *scan = rb_malloc(sizeof(struct opm_scan));
766d4ffc 362 struct rb_sockaddr_storage c_a, l_a;
4e85459a
EM
363 int opt = 1;
364 CNCB *callback;
365
366 switch(proxy->proto)
367 {
368 case PROTO_SOCKS4:
8aacefa3
EM
369#ifdef RB_IPV6
370 if(GET_SS_FAMILY(&auth->c_addr) == AF_INET6)
371 {
372 rb_free(scan);
373 return;
374 }
375#endif
4e85459a
EM
376 callback = socks4_connected;
377 break;
378 case PROTO_SOCKS5:
379 callback = socks5_connected;
380 break;
381 default:
382 return;
383 }
384
385#ifdef RB_IPV6
386 if(GET_SS_FAMILY(&auth->c_addr) == AF_INET6)
387 listener = &listeners[LISTEN_IPV6];
388 else
389#endif
390 listener = &listeners[LISTEN_IPV4];
391
392 c_a = auth->c_addr; /* Client */
393 l_a = listener->addr; /* Listener */
394
395 scan->auth = auth;
396 scan->proxy = proxy;
397 if((scan->F = rb_socket(GET_SS_FAMILY(&auth->c_addr), SOCK_STREAM, 0, proxy->note)) == NULL)
398 {
399 warn_opers(L_CRIT, "OPM: could not create OPM socket (proto %s): %s", proxy->note, strerror(errno));
400 rb_free(scan);
401 return;
402 }
403
404 /* Disable Nagle's algorithim - buffering could affect scans */
405 (void)setsockopt(rb_get_fd(scan->F), IPPROTO_TCP, TCP_NODELAY, (char *)&opt, sizeof(opt));
406
d86692fa 407 SET_SS_PORT(&l_a, 0);
8aacefa3 408 SET_SS_PORT(&c_a, htons(proxy->port));
4e85459a
EM
409
410 rb_dlinkAdd(scan, &scan->node, &lookup->scans);
411 rb_connect_tcp(scan->F,
412 (struct sockaddr *)&c_a,
413 (struct sockaddr *)&l_a,
414 GET_SS_LEN(&l_a),
415 callback, scan, opm_timeout);
416}
417
1de169a2
EM
418static bool
419create_listener(const char *ip, uint16_t port)
420{
421 struct auth_client *auth;
422 struct opm_listener *listener;
423 struct rb_sockaddr_storage addr;
424 rb_dictionary_iter iter;
425 rb_fde_t *F;
426 int opt = 1;
427
428 if(!rb_inet_pton_sock(ip, (struct sockaddr *)&addr))
429 {
430 warn_opers(L_CRIT, "OPM: got a bad listener: %s:%hu", ip, port);
431 exit(EX_PROVIDER_ERROR);
432 }
433
434#ifdef RB_IPV6
435 if(GET_SS_FAMILY(&addr) == AF_INET6)
436 {
437 struct sockaddr_in6 *a1, *a2;
438
439 listener = &listeners[LISTEN_IPV6];
440
441 a1 = (struct sockaddr_in6 *)&addr;
442 a2 = (struct sockaddr_in6 *)&listener->addr;
443
444 if(IN6_ARE_ADDR_EQUAL(&a1->sin6_addr, &a2->sin6_addr) &&
445 GET_SS_PORT(&addr) == GET_SS_PORT(&listener->addr) &&
446 listener->F != NULL)
447 {
448 /* Listener already exists */
449 return false;
450 }
451 }
452 else
453#endif
454 {
455 struct sockaddr_in *a1, *a2;
456
457 listener = &listeners[LISTEN_IPV4];
458
459 a1 = (struct sockaddr_in *)&addr;
460 a2 = (struct sockaddr_in *)&listener->addr;
461
462 if(a1->sin_addr.s_addr == a2->sin_addr.s_addr &&
463 GET_SS_PORT(&addr) == GET_SS_PORT(&listener->addr) &&
464 listener->F != NULL)
465 {
466 /* Listener already exists */
467 return false;
468 }
469 }
470
471 if((F = rb_socket(GET_SS_FAMILY(&addr), SOCK_STREAM, 0, "OPM listener socket")) == NULL)
472 {
473 /* This shouldn't fail, or we have big problems... */
474 warn_opers(L_CRIT, "OPM: cannot create socket: %s", strerror(errno));
475 exit(EX_PROVIDER_ERROR);
476 }
477
478 if(setsockopt(rb_get_fd(F), SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)))
479 {
480 /* This shouldn't fail either... */
481 warn_opers(L_CRIT, "OPM: cannot set options on socket: %s", strerror(errno));
482 exit(EX_PROVIDER_ERROR);
483 }
484
485 /* Set up ports for binding */
486#ifdef RB_IPV6
487 if(GET_SS_FAMILY(&addr) == AF_INET6)
488 ((struct sockaddr_in6 *)&addr)->sin6_port = htons(port);
489 else
490#endif
491 ((struct sockaddr_in *)&addr)->sin_port = htons(port);
492
493 if(bind(rb_get_fd(F), (struct sockaddr *)&addr, GET_SS_LEN(&addr)))
494 {
495 /* Shit happens, let's not cripple authd over /this/ since it could be user error */
496 warn_opers(L_WARN, "OPM: cannot bind on socket: %s", strerror(errno));
497 rb_close(F);
498 return false;
499 }
500
501 if(rb_listen(F, SOMAXCONN, false)) /* deferred accept could interfere with detection */
502 {
503 /* Again, could be user error */
504 warn_opers(L_WARN, "OPM: cannot listen on socket: %s", strerror(errno));
505 rb_close(F);
506 return false;
507 }
508
509 /* From this point forward we assume we have a listener */
510
511 if(listener->F != NULL)
512 /* Close old listener */
513 rb_close(listener->F);
514
515 listener->F = F;
516
517 /* Cancel clients that may be on old listener
518 * XXX - should rescan clients that need it
519 */
520 RB_DICTIONARY_FOREACH(auth, &iter, auth_clients)
521 {
522 opm_cancel(auth);
523 }
524
525 /* Copy data */
526 rb_strlcpy(listener->ip, ip, sizeof(listener->ip));
527 listener->port = port;
528 listener->addr = addr;
529
530 opm_enable = true; /* Implicitly set this to true for now if we have a listener */
531 rb_accept_tcp(listener->F, NULL, accept_opm, listener);
532 return true;
533}
534
535
4e85459a
EM
536static void
537opm_destroy(void)
538{
539 struct auth_client *auth;
540 rb_dictionary_iter iter;
541
542 /* Nuke all opm lookups */
543 RB_DICTIONARY_FOREACH(auth, &iter, auth_clients)
544 {
545 opm_cancel(auth);
546 }
547}
548
549static bool
550opm_start(struct auth_client *auth)
551{
1de169a2 552 rb_dlink_node *ptr;
4e85459a
EM
553 struct opm_lookup *lookup = rb_malloc(sizeof(struct opm_lookup));
554
1de169a2 555 if(!opm_enable || !rb_dlink_list_length(&proxy_scanners))
4e85459a
EM
556 {
557 notice_client(auth->cid, "*** Proxy scanning disabled, not scanning");
558 return true;
559 }
560
561 auth->data[PROVIDER_OPM] = lookup = rb_malloc(sizeof(struct opm_lookup));
562 auth->timeout[PROVIDER_OPM] = rb_current_time() + opm_timeout;
563
1de169a2
EM
564 RB_DLINK_FOREACH(ptr, proxy_scanners.head)
565 {
566 struct opm_proxy *proxy = ptr->data;
4e85459a 567 establish_connection(auth, proxy);
1de169a2 568 }
4e85459a
EM
569
570 notice_client(auth->cid, "*** Scanning for open proxies...");
571 set_provider_on(auth, PROVIDER_OPM);
572
573 return true;
574}
575
576static void
577opm_cancel(struct auth_client *auth)
578{
579 struct opm_lookup *lookup = auth->data[PROVIDER_OPM];
580
581 if(lookup != NULL)
582 {
583 rb_dlink_node *ptr, *nptr;
584
1661e365
EM
585 notice_client(auth->cid, "*** Did not detect open proxies");
586
4e85459a
EM
587 RB_DLINK_FOREACH_SAFE(ptr, nptr, lookup->scans.head)
588 {
589 struct opm_scan *scan = ptr->data;
590
591 rb_close(scan->F);
592 rb_free(scan);
593 }
594
595 rb_free(lookup);
596 provider_done(auth, PROVIDER_OPM);
597 }
598}
599
600static void
601add_conf_opm_timeout(const char *key __unused, int parc __unused, const char **parv)
602{
603 int timeout = atoi(parv[0]);
604
605 if(timeout < 0)
606 {
607 warn_opers(L_CRIT, "opm: opm timeout < 0 (value: %d)", timeout);
608 return;
609 }
610
611 opm_timeout = timeout;
612}
613
614static void
615set_opm_enabled(const char *key __unused, int parc __unused, const char **parv)
616{
4deb334f
EM
617 bool enable = (*parv[0] == '1');
618
619 if(!enable)
1661e365 620 {
4deb334f 621 if(listeners[LISTEN_IPV4].F != NULL || listeners[LISTEN_IPV6].F != NULL)
1661e365
EM
622 {
623 struct auth_client *auth;
624 rb_dictionary_iter iter;
625
626 /* Close the listening socket */
627 if(listeners[LISTEN_IPV4].F != NULL)
628 rb_close(listeners[LISTEN_IPV4].F);
629
630 if(listeners[LISTEN_IPV6].F != NULL)
631 rb_close(listeners[LISTEN_IPV6].F);
632
4deb334f
EM
633 listeners[LISTEN_IPV4].F = listeners[LISTEN_IPV6].F = NULL;
634
1661e365
EM
635 RB_DICTIONARY_FOREACH(auth, &iter, auth_clients)
636 {
637 opm_cancel(auth);
638 }
639 }
640 }
4e85459a 641 else
4deb334f
EM
642 {
643 if(listeners[LISTEN_IPV4].ip[0] != '\0' && listeners[LISTEN_IPV4].port != 0)
644 {
645 lrb_assert(listeners[LISTEN_IPV4].F == NULL);
646
647 /* Pre-configured IP/port, just re-establish */
648 create_listener(listeners[LISTEN_IPV4].ip, listeners[LISTEN_IPV4].port);
649 }
650
651 if(listeners[LISTEN_IPV6].ip[0] != '\0' && listeners[LISTEN_IPV6].port != 0)
652 {
653 lrb_assert(listeners[LISTEN_IPV6].F == NULL);
654
655 /* Pre-configured IP/port, just re-establish */
656 create_listener(listeners[LISTEN_IPV6].ip, listeners[LISTEN_IPV6].port);
657 }
658 }
659
660 opm_enable = enable;
4e85459a
EM
661}
662
1de169a2
EM
663static void
664set_opm_listener(const char *key __unused, int parc __unused, const char **parv)
4e85459a 665{
1de169a2
EM
666 const char *ip = parv[0];
667 int iport = atoi(parv[1]);
4e85459a 668
1de169a2 669 if(iport > 65535 || iport <= 0)
4e85459a 670 {
1de169a2 671 warn_opers(L_CRIT, "OPM: got a bad listener: %s:%s", parv[0], parv[1]);
4e85459a
EM
672 exit(EX_PROVIDER_ERROR);
673 }
674
1de169a2
EM
675 create_listener(ip, (uint16_t)iport);
676}
4deb334f 677
1de169a2
EM
678static void
679create_opm_scanner(const char *key __unused, int parc __unused, const char **parv)
680{
681 int iport = atoi(parv[1]);
682 struct opm_proxy *proxy = rb_malloc(sizeof(struct opm_proxy));
4deb334f 683
1de169a2 684 if(iport <= 0 || iport > 65535)
4deb334f 685 {
1de169a2
EM
686 warn_opers(L_CRIT, "OPM: got a bad scanner: %s (port %s)", parv[0], parv[1]);
687 exit(EX_PROVIDER_ERROR);
688 }
4deb334f 689
1de169a2 690 proxy->port = (uint16_t)iport;
4e85459a 691
1de169a2
EM
692 switch((proxy->proto = get_protocol_from_string(parv[0])))
693 {
694 case PROTO_SOCKS4:
695 snprintf(proxy->note, sizeof(proxy->note), "socks4:%hu", proxy->port);
696 break;
697 case PROTO_SOCKS5:
698 snprintf(proxy->note, sizeof(proxy->note), "socks5:%hu", proxy->port);
699 break;
700 default:
701 warn_opers(L_CRIT, "OPM: got an unknown proxy type: %s (port %hu)", parv[0], proxy->port);
702 exit(EX_PROVIDER_ERROR);
4deb334f 703 }
4e85459a 704
1de169a2 705 if(find_proxy_scanner(proxy->proto, proxy->port) != NULL)
4e85459a 706 {
1de169a2 707 warn_opers(L_CRIT, "OPM: got a duplicate scanner: %s (port %hu)", parv[0], proxy->port);
4e85459a
EM
708 exit(EX_PROVIDER_ERROR);
709 }
710
1de169a2
EM
711 rb_dlinkAdd(proxy, &proxy->node, &proxy_scanners);
712}
713
714static void
715delete_opm_scanner(const char *key __unused, int parc __unused, const char **parv)
716{
717 struct auth_client *auth;
718 struct opm_proxy *proxy;
719 protocol_t proto = get_protocol_from_string(parv[0]);
720 int iport = atoi(parv[1]);
721 rb_dictionary_iter iter;
722
723 if(iport <= 0 || iport > 65535)
4e85459a 724 {
1de169a2 725 warn_opers(L_CRIT, "OPM: got a bad scanner to delete: %s (port %s)", parv[0], parv[1]);
4e85459a
EM
726 exit(EX_PROVIDER_ERROR);
727 }
728
1de169a2 729 if(proto == PROTO_NONE)
4e85459a 730 {
1de169a2
EM
731 warn_opers(L_CRIT, "OPM: got an unknown proxy type to delete: %s (port %d)", parv[0], iport);
732 exit(EX_PROVIDER_ERROR);
4e85459a
EM
733 }
734
1de169a2 735 if((proxy = find_proxy_scanner(proto, (uint16_t)iport)) == NULL)
4e85459a 736 {
1de169a2
EM
737 warn_opers(L_CRIT, "OPM: cannot find proxy to delete: %s (port %d)", parv[0], iport);
738 exit(EX_PROVIDER_ERROR);
4e85459a
EM
739 }
740
1de169a2
EM
741 /* Abort remaining clients on this scanner */
742 RB_DICTIONARY_FOREACH(auth, &iter, auth_clients)
743 {
744 rb_dlink_node *ptr;
745 struct opm_lookup *lookup = auth->data[PROVIDER_OPM];
8c0b90de 746
1de169a2
EM
747 if(lookup == NULL)
748 continue;
4e85459a 749
1de169a2
EM
750 RB_DLINK_FOREACH(ptr, lookup->scans.head)
751 {
752 struct opm_scan *scan = ptr->data;
4e85459a 753
1de169a2
EM
754 if(scan->proxy->port == proxy->port && scan->proxy->proto == proxy->proto)
755 {
756 /* Match */
757 rb_dlinkDelete(&scan->node, &lookup->scans);
758 rb_free(scan);
4e85459a 759
1de169a2
EM
760 if(!rb_dlink_list_length(&lookup->scans))
761 opm_cancel(auth);
4e85459a 762
1de169a2
EM
763 break;
764 }
765 }
766 }
767
768 rb_dlinkDelete(&proxy->node, &proxy_scanners);
769 rb_free(proxy);
4deb334f
EM
770}
771
772static void
1de169a2 773delete_opm_scanner_all(const char *key __unused, int parc __unused, const char **parv __unused)
4deb334f 774{
1de169a2
EM
775 struct auth_client *auth;
776 rb_dlink_node *ptr, *nptr;
777 rb_dictionary_iter iter;
4deb334f 778
1de169a2 779 RB_DLINK_FOREACH_SAFE(ptr, nptr, proxy_scanners.head)
4deb334f 780 {
1de169a2
EM
781 rb_free(ptr->data);
782 rb_dlinkDelete(ptr, &proxy_scanners);
4deb334f
EM
783 }
784
1de169a2
EM
785 RB_DICTIONARY_FOREACH(auth, &iter, auth_clients)
786 {
787 opm_cancel(auth);
788 }
4e85459a
EM
789}
790
1de169a2 791
4e85459a
EM
792struct auth_opts_handler opm_options[] =
793{
794 { "opm_timeout", 1, add_conf_opm_timeout },
795 { "opm_enabled", 1, set_opm_enabled },
796 { "opm_listener", 2, set_opm_listener },
1de169a2
EM
797 { "opm_scanner", 2, create_opm_scanner },
798 { "opm_scanner_del", 2, delete_opm_scanner },
799 { "opm_scanner_del_all", 0, delete_opm_scanner_all },
4e85459a
EM
800 { NULL, 0, NULL },
801};
802
803struct auth_provider opm_provider =
804{
805 .id = PROVIDER_OPM,
806 .destroy = opm_destroy,
807 .start = opm_start,
808 .cancel = opm_cancel,
809 .timeout = opm_cancel,
810 .opt_handlers = opm_options,
811};