]> jfr.im git - irc/rqf/shadowircd.git/blame - ssld/ssld.c
Copied libratbox and related stuff from shadowircd upstream.
[irc/rqf/shadowircd.git] / ssld / ssld.c
CommitLineData
7f87f8d2
VY
1/*
2 * ssld.c: The ircd-ratbox ssl/zlib helper daemon thingy
3 * Copyright (C) 2007 Aaron Sethman <androsyn@ratbox.org>
4 * Copyright (C) 2007 ircd-ratbox development team
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 * USA
20 *
94b4fbf9 21 * $Id$
7f87f8d2
VY
22 */
23
24
25#include "stdinc.h"
26
27#ifdef HAVE_LIBZ
28#include <zlib.h>
29#endif
30
31#define MAXPASSFD 4
32#ifndef READBUF_SIZE
33#define READBUF_SIZE 16384
34#endif
35
36static void setup_signals(void);
94b4fbf9 37static pid_t ppid;
7f87f8d2 38
94b4fbf9
VY
39static inline int32_t
40buf_to_int32(char *buf)
7f87f8d2 41{
76eaa67b 42 int32_t x;
df22ecbf 43 memcpy(&x, buf, sizeof(x));
7f87f8d2
VY
44 return x;
45}
46
94b4fbf9
VY
47static inline void
48int32_to_buf(char *buf, int32_t x)
7f87f8d2 49{
df22ecbf 50 memcpy(buf, &x, sizeof(x));
7f87f8d2
VY
51 return;
52}
53
94b4fbf9
VY
54static inline uint16_t
55buf_to_uint16(char *buf)
7f87f8d2 56{
76eaa67b 57 uint16_t x;
df22ecbf 58 memcpy(&x, buf, sizeof(x));
7f87f8d2
VY
59 return x;
60}
61
94b4fbf9
VY
62static inline void
63uint16_to_buf(char *buf, uint16_t x)
7f87f8d2 64{
df22ecbf 65 memcpy(buf, &x, sizeof(x));
7f87f8d2
VY
66 return;
67}
94b4fbf9 68
7f87f8d2 69
7f87f8d2 70static char inbuf[READBUF_SIZE];
df22ecbf 71#ifdef HAVE_LIBZ
7f87f8d2 72static char outbuf[READBUF_SIZE];
df22ecbf 73#endif
7f87f8d2
VY
74
75typedef struct _mod_ctl_buf
76{
77 rb_dlink_node node;
78 char *buf;
79 size_t buflen;
80 rb_fde_t *F[MAXPASSFD];
81 int nfds;
82} mod_ctl_buf_t;
83
84typedef struct _mod_ctl
85{
86 rb_dlink_node node;
87 int cli_count;
88 rb_fde_t *F;
89 rb_fde_t *F_pipe;
90 rb_dlink_list readq;
91 rb_dlink_list writeq;
92} mod_ctl_t;
93
94static mod_ctl_t *mod_ctl;
95
96
97#ifdef HAVE_LIBZ
98typedef struct _zlib_stream
99{
100 z_stream instream;
101 z_stream outstream;
102} zlib_stream_t;
103#endif
104
105typedef struct _conn
106{
107 rb_dlink_node node;
108 mod_ctl_t *ctl;
109 rawbuf_head_t *modbuf_out;
110 rawbuf_head_t *plainbuf_out;
111
76eaa67b 112 int32_t id;
7f87f8d2
VY
113
114 rb_fde_t *mod_fd;
115 rb_fde_t *plain_fd;
116 unsigned long long mod_out;
117 unsigned long long mod_in;
118 unsigned long long plain_in;
119 unsigned long long plain_out;
76eaa67b 120 uint8_t flags;
7f87f8d2
VY
121 void *stream;
122} conn_t;
123
124#define FLAG_SSL 0x01
125#define FLAG_ZIP 0x02
126#define FLAG_CORK 0x04
127#define FLAG_DEAD 0x08
94b4fbf9
VY
128#define FLAG_SSL_W_WANTS_R 0x10 /* output needs to wait until input possible */
129#define FLAG_SSL_R_WANTS_W 0x20 /* input needs to wait until output possible */
7f87f8d2
VY
130
131#define IsSSL(x) ((x)->flags & FLAG_SSL)
132#define IsZip(x) ((x)->flags & FLAG_ZIP)
133#define IsCork(x) ((x)->flags & FLAG_CORK)
134#define IsDead(x) ((x)->flags & FLAG_DEAD)
8f40f4bb
VY
135#define IsSSLWWantsR(x) ((x)->flags & FLAG_SSL_W_WANTS_R)
136#define IsSSLRWantsW(x) ((x)->flags & FLAG_SSL_R_WANTS_W)
7f87f8d2
VY
137
138#define SetSSL(x) ((x)->flags |= FLAG_SSL)
139#define SetZip(x) ((x)->flags |= FLAG_ZIP)
140#define SetCork(x) ((x)->flags |= FLAG_CORK)
141#define SetDead(x) ((x)->flags |= FLAG_DEAD)
8f40f4bb
VY
142#define SetSSLWWantsR(x) ((x)->flags |= FLAG_SSL_W_WANTS_R)
143#define SetSSLRWantsW(x) ((x)->flags |= FLAG_SSL_R_WANTS_W)
7f87f8d2
VY
144
145#define ClearSSL(x) ((x)->flags &= ~FLAG_SSL)
146#define ClearZip(x) ((x)->flags &= ~FLAG_ZIP)
147#define ClearCork(x) ((x)->flags &= ~FLAG_CORK)
148#define ClearDead(x) ((x)->flags &= ~FLAG_DEAD)
8f40f4bb
VY
149#define ClearSSLWWantsR(x) ((x)->flags &= ~FLAG_SSL_W_WANTS_R)
150#define ClearSSLRWantsW(x) ((x)->flags &= ~FLAG_SSL_R_WANTS_W)
7f87f8d2
VY
151
152#define NO_WAIT 0x0
153#define WAIT_PLAIN 0x1
154
df22ecbf
VY
155#define HASH_WALK_SAFE(i, max, ptr, next, table) for(i = 0; i < max; i++) { RB_DLINK_FOREACH_SAFE(ptr, next, table[i].head)
156#define HASH_WALK_END }
7f87f8d2
VY
157#define CONN_HASH_SIZE 2000
158#define connid_hash(x) (&connid_hash_table[(x % CONN_HASH_SIZE)])
159
df22ecbf
VY
160
161
7f87f8d2
VY
162static rb_dlink_list connid_hash_table[CONN_HASH_SIZE];
163static rb_dlink_list dead_list;
164
94b4fbf9 165static void conn_mod_read_cb(rb_fde_t *fd, void *data);
7f87f8d2
VY
166static void conn_mod_write_sendq(rb_fde_t *, void *data);
167static void conn_plain_write_sendq(rb_fde_t *, void *data);
168static void mod_write_ctl(rb_fde_t *, void *data);
94b4fbf9
VY
169static void conn_plain_read_cb(rb_fde_t *fd, void *data);
170static void mod_cmd_write_queue(mod_ctl_t * ctl, const void *data, size_t len);
7f87f8d2
VY
171static const char *remote_closed = "Remote host closed the connection";
172static int ssl_ok;
173#ifdef HAVE_LIBZ
174static int zlib_ok = 1;
175#else
176static int zlib_ok = 0;
177#endif
df22ecbf
VY
178
179
180#ifdef HAVE_LIBZ
7f87f8d2
VY
181static void *
182ssld_alloc(void *unused, size_t count, size_t size)
183{
184 return rb_malloc(count * size);
185}
186
187static void
188ssld_free(void *unused, void *ptr)
189{
94b4fbf9 190 rb_free(ptr);
7f87f8d2 191}
df22ecbf 192#endif
7f87f8d2
VY
193
194static conn_t *
76eaa67b 195conn_find_by_id(int32_t id)
7f87f8d2
VY
196{
197 rb_dlink_node *ptr;
198 conn_t *conn;
199
200 RB_DLINK_FOREACH(ptr, (connid_hash(id))->head)
201 {
202 conn = ptr->data;
203 if(conn->id == id && !IsDead(conn))
204 return conn;
205 }
206 return NULL;
207}
208
209static void
76eaa67b 210conn_add_id_hash(conn_t * conn, int32_t id)
7f87f8d2
VY
211{
212 conn->id = id;
213 rb_dlinkAdd(conn, &conn->node, connid_hash(id));
214}
215
216static void
217free_conn(conn_t * conn)
218{
219 rb_free_rawbuffer(conn->modbuf_out);
220 rb_free_rawbuffer(conn->plainbuf_out);
df22ecbf 221#ifdef HAVE_LIBZ
7f87f8d2
VY
222 if(IsZip(conn))
223 {
224 zlib_stream_t *stream = conn->stream;
225 inflateEnd(&stream->instream);
94b4fbf9 226 deflateEnd(&stream->outstream);
7f87f8d2 227 }
df22ecbf 228#endif
7f87f8d2
VY
229 rb_free(conn);
230}
231
232static void
233clean_dead_conns(void *unused)
234{
235 conn_t *conn;
236 rb_dlink_node *ptr, *next;
237 RB_DLINK_FOREACH_SAFE(ptr, next, dead_list.head)
238 {
239 conn = ptr->data;
240 free_conn(conn);
241 }
242 dead_list.tail = dead_list.head = NULL;
243}
244
245
246static void
247close_conn(conn_t * conn, int wait_plain, const char *fmt, ...)
248{
249 va_list ap;
94b4fbf9 250 char reason[128]; /* must always be under 250 bytes */
7f87f8d2
VY
251 char buf[256];
252 int len;
253 if(IsDead(conn))
254 return;
94b4fbf9 255
7f87f8d2
VY
256 rb_rawbuf_flush(conn->modbuf_out, conn->mod_fd);
257 rb_rawbuf_flush(conn->plainbuf_out, conn->plain_fd);
258 rb_close(conn->mod_fd);
259 SetDead(conn);
260
261 if(!wait_plain || fmt == NULL)
262 {
263 rb_close(conn->plain_fd);
94b4fbf9 264
7f87f8d2
VY
265 if(conn->id >= 0)
266 rb_dlinkDelete(&conn->node, connid_hash(conn->id));
267 rb_dlinkAdd(conn, &conn->node, &dead_list);
268 return;
269 }
94b4fbf9 270 rb_setselect(conn->plain_fd, RB_SELECT_WRITE | RB_SELECT_READ, NULL, NULL);
7f87f8d2
VY
271 va_start(ap, fmt);
272 rb_vsnprintf(reason, sizeof(reason), fmt, ap);
273 va_end(ap);
274
275 buf[0] = 'D';
276 int32_to_buf(&buf[1], conn->id);
277 strcpy(&buf[5], reason);
278 len = (strlen(reason) + 1) + 5;
279 mod_cmd_write_queue(conn->ctl, buf, len);
280}
281
282static conn_t *
94b4fbf9 283make_conn(mod_ctl_t * ctl, rb_fde_t *mod_fd, rb_fde_t *plain_fd)
7f87f8d2
VY
284{
285 conn_t *conn = rb_malloc(sizeof(conn_t));
286 conn->ctl = ctl;
287 conn->modbuf_out = rb_new_rawbuffer();
288 conn->plainbuf_out = rb_new_rawbuffer();
289 conn->mod_fd = mod_fd;
290 conn->plain_fd = plain_fd;
291 conn->id = -1;
292 conn->stream = NULL;
293 rb_set_nb(mod_fd);
294 rb_set_nb(plain_fd);
295 return conn;
296}
297
df22ecbf
VY
298static void
299check_handshake_flood(void *unused)
300{
301 conn_t *conn;
302 rb_dlink_node *ptr, *next;
303 unsigned int count;
304 int i;
305 HASH_WALK_SAFE(i, CONN_HASH_SIZE, ptr, next, connid_hash_table)
306 {
307 conn = ptr->data;
308 if(!IsSSL(conn))
309 continue;
94b4fbf9 310
df22ecbf
VY
311 count = rb_ssl_handshake_count(conn->mod_fd);
312 /* nothing needs to do this more than twice in ten seconds i don't think */
313 if(count > 2)
314 close_conn(conn, WAIT_PLAIN, "Handshake flooding");
315 else
316 rb_ssl_clear_handshake_count(conn->mod_fd);
94b4fbf9
VY
317 }
318HASH_WALK_END}
df22ecbf 319
7f87f8d2 320static void
94b4fbf9 321conn_mod_write_sendq(rb_fde_t *fd, void *data)
7f87f8d2
VY
322{
323 conn_t *conn = data;
324 const char *err;
325 int retlen;
326 if(IsDead(conn))
327 return;
328
8f40f4bb
VY
329 if(IsSSLWWantsR(conn))
330 {
331 ClearSSLWWantsR(conn);
332 conn_mod_read_cb(conn->mod_fd, conn);
333 if(IsDead(conn))
334 return;
335 }
336
94b4fbf9 337 while((retlen = rb_rawbuf_flush(conn->modbuf_out, fd)) > 0)
7f87f8d2
VY
338 conn->mod_out += retlen;
339
340 if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno)))
341 {
342 if(retlen == 0)
343 close_conn(conn, WAIT_PLAIN, "%s", remote_closed);
344 if(IsSSL(conn) && retlen == RB_RW_SSL_ERROR)
345 err = rb_get_ssl_strerror(conn->mod_fd);
346 else
347 err = strerror(errno);
348 close_conn(conn, WAIT_PLAIN, "Write error: %s", err);
349 return;
350 }
351 if(rb_rawbuf_length(conn->modbuf_out) > 0)
352 {
8f40f4bb
VY
353 if(retlen != RB_RW_SSL_NEED_READ)
354 rb_setselect(conn->mod_fd, RB_SELECT_WRITE, conn_mod_write_sendq, conn);
355 else
356 {
357 rb_setselect(conn->mod_fd, RB_SELECT_READ, conn_mod_write_sendq, conn);
358 rb_setselect(conn->mod_fd, RB_SELECT_WRITE, NULL, NULL);
359 SetSSLWWantsR(conn);
360 }
7f87f8d2
VY
361 }
362 else
363 rb_setselect(conn->mod_fd, RB_SELECT_WRITE, NULL, NULL);
364
365 if(IsCork(conn) && rb_rawbuf_length(conn->modbuf_out) == 0)
366 {
367 ClearCork(conn);
368 conn_plain_read_cb(conn->plain_fd, conn);
369 }
370
371}
372
373static void
374conn_mod_write(conn_t * conn, void *data, size_t len)
375{
376 if(IsDead(conn)) /* no point in queueing to a dead man */
377 return;
378 rb_rawbuf_append(conn->modbuf_out, data, len);
379}
380
381static void
382conn_plain_write(conn_t * conn, void *data, size_t len)
383{
384 if(IsDead(conn)) /* again no point in queueing to dead men */
385 return;
386 rb_rawbuf_append(conn->plainbuf_out, data, len);
387}
388
389static void
390mod_cmd_write_queue(mod_ctl_t * ctl, const void *data, size_t len)
391{
392 mod_ctl_buf_t *ctl_buf;
393 ctl_buf = rb_malloc(sizeof(mod_ctl_buf_t));
394 ctl_buf->buf = rb_malloc(len);
395 ctl_buf->buflen = len;
396 memcpy(ctl_buf->buf, data, len);
397 ctl_buf->nfds = 0;
398 rb_dlinkAddTail(ctl_buf, &ctl_buf->node, &ctl->writeq);
399 mod_write_ctl(ctl->F, ctl);
400}
401
402#ifdef HAVE_LIBZ
403static void
404common_zlib_deflate(conn_t * conn, void *buf, size_t len)
405{
406 int ret, have;
94b4fbf9 407 z_stream *outstream = &((zlib_stream_t *) conn->stream)->outstream;
7f87f8d2
VY
408 outstream->next_in = buf;
409 outstream->avail_in = len;
410 outstream->next_out = (Bytef *) outbuf;
411 outstream->avail_out = sizeof(outbuf);
412
413 ret = deflate(outstream, Z_SYNC_FLUSH);
414 if(ret != Z_OK)
415 {
416 /* deflate error */
417 close_conn(conn, WAIT_PLAIN, "Deflate failed: %s", zError(ret));
418 return;
419 }
420 if(outstream->avail_out == 0)
421 {
422 /* avail_out empty */
423 close_conn(conn, WAIT_PLAIN, "error compressing data, avail_out == 0");
424 return;
425 }
426 if(outstream->avail_in != 0)
427 {
94b4fbf9 428 /* avail_in isn't empty... */
7f87f8d2
VY
429 close_conn(conn, WAIT_PLAIN, "error compressing data, avail_in != 0");
430 return;
431 }
432 have = sizeof(outbuf) - outstream->avail_out;
433 conn_mod_write(conn, outbuf, have);
434}
435
436static void
437common_zlib_inflate(conn_t * conn, void *buf, size_t len)
438{
94b4fbf9
VY
439 int ret, have = 0;
440 ((zlib_stream_t *) conn->stream)->instream.next_in = buf;
441 ((zlib_stream_t *) conn->stream)->instream.avail_in = len;
442 ((zlib_stream_t *) conn->stream)->instream.next_out = (Bytef *) outbuf;
443 ((zlib_stream_t *) conn->stream)->instream.avail_out = sizeof(outbuf);
7f87f8d2 444
94b4fbf9 445 while(((zlib_stream_t *) conn->stream)->instream.avail_in)
7f87f8d2 446 {
94b4fbf9 447 ret = inflate(&((zlib_stream_t *) conn->stream)->instream, Z_NO_FLUSH);
7f87f8d2
VY
448 if(ret != Z_OK)
449 {
450 if(!strncmp("ERROR ", buf, 6))
451 {
452 close_conn(conn, WAIT_PLAIN, "Received uncompressed ERROR");
453 return;
454 }
455 close_conn(conn, WAIT_PLAIN, "Inflate failed: %s", zError(ret));
456 return;
457 }
94b4fbf9 458 have = sizeof(outbuf) - ((zlib_stream_t *) conn->stream)->instream.avail_out;
7f87f8d2 459
94b4fbf9 460 if(((zlib_stream_t *) conn->stream)->instream.avail_in)
7f87f8d2
VY
461 {
462 conn_plain_write(conn, outbuf, have);
463 have = 0;
94b4fbf9
VY
464 ((zlib_stream_t *) conn->stream)->instream.next_out = (Bytef *) outbuf;
465 ((zlib_stream_t *) conn->stream)->instream.avail_out = sizeof(outbuf);
7f87f8d2
VY
466 }
467 }
468 if(have == 0)
469 return;
470
471 conn_plain_write(conn, outbuf, have);
472}
473#endif
474
475static int
476plain_check_cork(conn_t * conn)
477{
478 if(rb_rawbuf_length(conn->modbuf_out) >= 4096)
479 {
480 /* if we have over 4k pending outbound, don't read until
481 * we've cleared the queue */
482 SetCork(conn);
483 rb_setselect(conn->plain_fd, RB_SELECT_READ, NULL, NULL);
484 /* try to write */
485 conn_mod_write_sendq(conn->mod_fd, conn);
486 return 1;
487 }
488 return 0;
489}
490
491
492static void
94b4fbf9 493conn_plain_read_cb(rb_fde_t *fd, void *data)
7f87f8d2
VY
494{
495 conn_t *conn = data;
496 int length = 0;
497 if(conn == NULL)
498 return;
499
500 if(IsDead(conn))
501 return;
502
503 if(plain_check_cork(conn))
504 return;
505
94b4fbf9 506 while(1)
7f87f8d2
VY
507 {
508 if(IsDead(conn))
509 return;
510
511 length = rb_read(conn->plain_fd, inbuf, sizeof(inbuf));
512
513 if(length == 0 || (length < 0 && !rb_ignore_errno(errno)))
514 {
515 close_conn(conn, NO_WAIT, NULL);
516 return;
517 }
518
519 if(length < 0)
520 {
521 rb_setselect(conn->plain_fd, RB_SELECT_READ, conn_plain_read_cb, conn);
522 conn_mod_write_sendq(conn->mod_fd, conn);
523 return;
524 }
525 conn->plain_in += length;
526
527#ifdef HAVE_LIBZ
528 if(IsZip(conn))
529 common_zlib_deflate(conn, inbuf, length);
530 else
531#endif
532 conn_mod_write(conn, inbuf, length);
533 if(IsDead(conn))
534 return;
535 if(plain_check_cork(conn))
536 return;
537 }
538}
539
540static void
94b4fbf9 541conn_mod_read_cb(rb_fde_t *fd, void *data)
7f87f8d2
VY
542{
543 conn_t *conn = data;
544 const char *err = remote_closed;
545 int length;
546 if(conn == NULL)
547 return;
548 if(IsDead(conn))
549 return;
550
8f40f4bb
VY
551 if(IsSSLRWantsW(conn))
552 {
553 ClearSSLRWantsW(conn);
554 conn_mod_write_sendq(conn->mod_fd, conn);
555 if(IsDead(conn))
556 return;
557 }
558
94b4fbf9 559 while(1)
7f87f8d2
VY
560 {
561 if(IsDead(conn))
562 return;
563
564 length = rb_read(conn->mod_fd, inbuf, sizeof(inbuf));
565
566 if(length == 0 || (length < 0 && !rb_ignore_errno(errno)))
567 {
94b4fbf9
VY
568 if(length == 0)
569 {
7f87f8d2
VY
570 close_conn(conn, WAIT_PLAIN, "%s", remote_closed);
571 return;
572 }
573
574 if(IsSSL(conn) && length == RB_RW_SSL_ERROR)
575 err = rb_get_ssl_strerror(conn->mod_fd);
576 else
577 err = strerror(errno);
578 close_conn(conn, WAIT_PLAIN, "Read error: %s", err);
579 return;
580 }
581 if(length < 0)
582 {
8f40f4bb
VY
583 if(length != RB_RW_SSL_NEED_WRITE)
584 rb_setselect(conn->mod_fd, RB_SELECT_READ, conn_mod_read_cb, conn);
585 else
586 {
587 rb_setselect(conn->mod_fd, RB_SELECT_READ, NULL, NULL);
588 rb_setselect(conn->mod_fd, RB_SELECT_WRITE, conn_mod_read_cb, conn);
589 SetSSLRWantsW(conn);
590 }
7f87f8d2
VY
591 conn_plain_write_sendq(conn->plain_fd, conn);
592 return;
94b4fbf9 593 }
7f87f8d2
VY
594 conn->mod_in += length;
595#ifdef HAVE_LIBZ
596 if(IsZip(conn))
597 common_zlib_inflate(conn, inbuf, length);
598 else
599#endif
600 conn_plain_write(conn, inbuf, length);
601 }
602}
603
604static void
94b4fbf9 605conn_plain_write_sendq(rb_fde_t *fd, void *data)
7f87f8d2
VY
606{
607 conn_t *conn = data;
608 int retlen;
609
610 if(IsDead(conn))
611 return;
612
94b4fbf9 613 while((retlen = rb_rawbuf_flush(conn->plainbuf_out, fd)) > 0)
7f87f8d2
VY
614 {
615 conn->plain_out += retlen;
616 }
617 if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno)))
618 {
619 close_conn(data, NO_WAIT, NULL);
620 return;
621 }
94b4fbf9 622
7f87f8d2
VY
623
624 if(rb_rawbuf_length(conn->plainbuf_out) > 0)
625 rb_setselect(conn->plain_fd, RB_SELECT_WRITE, conn_plain_write_sendq, conn);
626 else
627 rb_setselect(conn->plain_fd, RB_SELECT_WRITE, NULL, NULL);
628}
629
630static int
631maxconn(void)
632{
633#if defined(RLIMIT_NOFILE) && defined(HAVE_SYS_RESOURCE_H)
634 struct rlimit limit;
635
636 if(!getrlimit(RLIMIT_NOFILE, &limit))
637 {
638 return limit.rlim_cur;
639 }
640#endif /* RLIMIT_FD_MAX */
641 return MAXCONNECTIONS;
642}
643
644static void
94b4fbf9 645ssl_process_accept_cb(rb_fde_t *F, int status, struct sockaddr *addr, rb_socklen_t len, void *data)
7f87f8d2
VY
646{
647 conn_t *conn = data;
648 if(status == RB_OK)
649 {
650 conn_mod_read_cb(conn->mod_fd, conn);
651 conn_plain_read_cb(conn->plain_fd, conn);
652 return;
653 }
9cb93263 654 /* ircd doesn't care about the reason for this */
7f87f8d2
VY
655 close_conn(conn, NO_WAIT, 0);
656 return;
657}
658
659static void
94b4fbf9 660ssl_process_connect_cb(rb_fde_t *F, int status, void *data)
7f87f8d2
VY
661{
662 conn_t *conn = data;
663 if(status == RB_OK)
664 {
665 conn_mod_read_cb(conn->mod_fd, conn);
666 conn_plain_read_cb(conn->plain_fd, conn);
7f87f8d2 667 }
9cb93263
JT
668 else if(status == RB_ERR_TIMEOUT)
669 close_conn(conn, WAIT_PLAIN, "SSL handshake timed out");
670 else if(status == RB_ERROR_SSL)
671 close_conn(conn, WAIT_PLAIN, "%s", rb_get_ssl_strerror(conn->mod_fd));
672 else
673 close_conn(conn, WAIT_PLAIN, "SSL handshake failed");
7f87f8d2
VY
674}
675
676
677static void
678ssl_process_accept(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb)
679{
680 conn_t *conn;
76eaa67b 681 int32_t id;
7f87f8d2
VY
682
683 conn = make_conn(ctl, ctlb->F[0], ctlb->F[1]);
684
685 id = buf_to_int32(&ctlb->buf[1]);
686
687 if(id >= 0)
688 conn_add_id_hash(conn, id);
689 SetSSL(conn);
690
691 if(rb_get_type(conn->mod_fd) & RB_FD_UNKNOWN)
692 {
94b4fbf9 693
7f87f8d2
VY
694 rb_set_type(conn->mod_fd, RB_FD_SOCKET);
695 }
696 if(rb_get_type(conn->mod_fd) == RB_FD_UNKNOWN)
697 rb_set_type(conn->plain_fd, RB_FD_SOCKET);
698
699 rb_ssl_start_accepted(ctlb->F[0], ssl_process_accept_cb, conn, 10);
700}
701
702static void
703ssl_process_connect(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb)
704{
705 conn_t *conn;
76eaa67b 706 int32_t id;
7f87f8d2
VY
707 conn = make_conn(ctl, ctlb->F[0], ctlb->F[1]);
708
709 id = buf_to_int32(&ctlb->buf[1]);
710
711 if(id >= 0)
712 conn_add_id_hash(conn, id);
713 SetSSL(conn);
714
715 if(rb_get_type(conn->mod_fd) == RB_FD_UNKNOWN)
716 rb_set_type(conn->mod_fd, RB_FD_SOCKET);
717
718 if(rb_get_type(conn->mod_fd) == RB_FD_UNKNOWN)
719 rb_set_type(conn->plain_fd, RB_FD_SOCKET);
720
721
722 rb_ssl_start_connected(ctlb->F[0], ssl_process_connect_cb, conn, 10);
723}
724
725static void
726process_stats(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb)
727{
728 char outstat[512];
729 conn_t *conn;
730 const char *odata;
76eaa67b 731 int32_t id;
7f87f8d2
VY
732
733 id = buf_to_int32(&ctlb->buf[1]);
734
735 if(id < 0)
736 return;
94b4fbf9 737
7f87f8d2
VY
738 odata = &ctlb->buf[5];
739 conn = conn_find_by_id(id);
740
741 if(conn == NULL)
742 return;
743
744 rb_snprintf(outstat, sizeof(outstat), "S %s %llu %llu %llu %llu", odata,
745 conn->plain_out, conn->mod_in, conn->plain_in, conn->mod_out);
746 conn->plain_out = 0;
747 conn->plain_in = 0;
748 conn->mod_in = 0;
749 conn->mod_out = 0;
750 mod_cmd_write_queue(ctl, outstat, strlen(outstat) + 1); /* +1 is so we send the \0 as well */
751}
752
753#ifdef HAVE_LIBZ
754static void
94b4fbf9 755zlib_send_zip_ready(mod_ctl_t * ctl, conn_t * conn)
7f87f8d2
VY
756{
757 char buf[5];
94b4fbf9 758
7f87f8d2
VY
759 buf[0] = 'R';
760 int32_to_buf(&buf[1], conn->id);
761 mod_cmd_write_queue(conn->ctl, buf, sizeof(buf));
762}
763
764static void
765zlib_process(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb)
766{
76eaa67b 767 uint8_t level;
7f87f8d2 768 size_t recvqlen;
76eaa67b 769 size_t hdr = (sizeof(uint8_t) * 2) + sizeof(int32_t);
7f87f8d2
VY
770 void *recvq_start;
771 z_stream *instream, *outstream;
772 conn_t *conn;
76eaa67b 773 int32_t id;
7f87f8d2
VY
774
775 conn = make_conn(ctl, ctlb->F[0], ctlb->F[1]);
776 if(rb_get_type(conn->mod_fd) == RB_FD_UNKNOWN)
777 rb_set_type(conn->mod_fd, RB_FD_SOCKET);
778
779 if(rb_get_type(conn->plain_fd) == RB_FD_UNKNOWN)
780 rb_set_type(conn->plain_fd, RB_FD_SOCKET);
781
782 id = buf_to_int32(&ctlb->buf[1]);
783 conn_add_id_hash(conn, id);
784
94b4fbf9 785 level = (uint8_t)ctlb->buf[5];
7f87f8d2
VY
786
787 recvqlen = ctlb->buflen - hdr;
788 recvq_start = &ctlb->buf[6];
789
790 SetZip(conn);
791 conn->stream = rb_malloc(sizeof(zlib_stream_t));
94b4fbf9
VY
792 instream = &((zlib_stream_t *) conn->stream)->instream;
793 outstream = &((zlib_stream_t *) conn->stream)->outstream;
794
7f87f8d2
VY
795 instream->total_in = 0;
796 instream->total_out = 0;
797 instream->zalloc = (alloc_func) ssld_alloc;
798 instream->zfree = (free_func) ssld_free;
799 instream->data_type = Z_ASCII;
94b4fbf9 800 inflateInit(&((zlib_stream_t *) conn->stream)->instream);
7f87f8d2
VY
801
802 outstream->total_in = 0;
803 outstream->total_out = 0;
804 outstream->zalloc = (alloc_func) ssld_alloc;
805 outstream->zfree = (free_func) ssld_free;
806 outstream->data_type = Z_ASCII;
807
808 if(level > 9)
809 level = Z_DEFAULT_COMPRESSION;
810
94b4fbf9 811 deflateInit(&((zlib_stream_t *) conn->stream)->outstream, level);
7f87f8d2
VY
812 if(recvqlen > 0)
813 common_zlib_inflate(conn, recvq_start, recvqlen);
814 zlib_send_zip_ready(ctl, conn);
815 conn_mod_read_cb(conn->mod_fd, conn);
816 conn_plain_read_cb(conn->plain_fd, conn);
817 return;
818
819}
820#endif
821
822static void
823init_prng(mod_ctl_t * ctl, mod_ctl_buf_t * ctl_buf)
824{
825 char *path;
826 prng_seed_t seed_type;
94b4fbf9
VY
827
828 seed_type = (prng_seed_t) ctl_buf->buf[1];
7f87f8d2
VY
829 path = &ctl_buf->buf[2];
830 rb_init_prng(path, seed_type);
831}
832
833
834static void
835ssl_new_keys(mod_ctl_t * ctl, mod_ctl_buf_t * ctl_buf)
836{
837 char *buf;
838 char *cert, *key, *dhparam;
839
840 buf = &ctl_buf->buf[2];
841 cert = buf;
842 buf += strlen(cert) + 1;
843 key = buf;
844 buf += strlen(key) + 1;
845 dhparam = buf;
846 if(strlen(dhparam) == 0)
847 dhparam = NULL;
848
849 if(!rb_setup_ssl_server(cert, key, dhparam))
850 {
851 const char *invalid = "I";
852 mod_cmd_write_queue(ctl, invalid, strlen(invalid));
853 return;
94b4fbf9 854 }
7f87f8d2
VY
855}
856
857static void
94b4fbf9 858send_nossl_support(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb)
7f87f8d2
VY
859{
860 static const char *nossl_cmd = "N";
861 conn_t *conn;
76eaa67b 862 int32_t id;
7f87f8d2
VY
863
864 if(ctlb != NULL)
94b4fbf9 865 {
7f87f8d2
VY
866 conn = make_conn(ctl, ctlb->F[0], ctlb->F[1]);
867 id = buf_to_int32(&ctlb->buf[1]);
868
869 if(id >= 0)
870 conn_add_id_hash(conn, id);
871 close_conn(conn, WAIT_PLAIN, "libratbox reports no SSL/TLS support");
94b4fbf9
VY
872 }
873 mod_cmd_write_queue(ctl, nossl_cmd, strlen(nossl_cmd));
7f87f8d2
VY
874}
875
876static void
94b4fbf9 877send_i_am_useless(mod_ctl_t * ctl)
7f87f8d2
VY
878{
879 static const char *useless = "U";
880 mod_cmd_write_queue(ctl, useless, strlen(useless));
881}
882
883static void
94b4fbf9 884send_nozlib_support(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb)
7f87f8d2
VY
885{
886 static const char *nozlib_cmd = "z";
887 conn_t *conn;
76eaa67b 888 int32_t id;
7f87f8d2
VY
889 if(ctlb != NULL)
890 {
891 conn = make_conn(ctl, ctlb->F[0], ctlb->F[1]);
892 id = buf_to_int32(&ctlb->buf[1]);
893
894 if(id >= 0)
895 conn_add_id_hash(conn, id);
896 close_conn(conn, WAIT_PLAIN, "libratbox reports no zlib support");
94b4fbf9 897 }
7f87f8d2
VY
898 mod_cmd_write_queue(ctl, nozlib_cmd, strlen(nozlib_cmd));
899}
900
901static void
902mod_process_cmd_recv(mod_ctl_t * ctl)
903{
904 rb_dlink_node *ptr, *next;
905 mod_ctl_buf_t *ctl_buf;
906
907 RB_DLINK_FOREACH_SAFE(ptr, next, ctl->readq.head)
908 {
909 ctl_buf = ptr->data;
910
911 switch (*ctl_buf->buf)
912 {
913 case 'A':
914 {
915 if(!ssl_ok)
916 {
917 send_nossl_support(ctl, ctl_buf);
918 break;
919 }
920 ssl_process_accept(ctl, ctl_buf);
921 break;
922 }
923 case 'C':
924 {
925 if(!ssl_ok)
926 {
927 send_nossl_support(ctl, ctl_buf);
928 break;
929 }
930 ssl_process_connect(ctl, ctl_buf);
931 break;
932 }
933
934 case 'K':
935 {
936 if(!ssl_ok)
937 {
938 send_nossl_support(ctl, ctl_buf);
939 break;
940 }
941 ssl_new_keys(ctl, ctl_buf);
942 break;
943 }
944 case 'I':
94b4fbf9
VY
945 init_prng(ctl, ctl_buf);
946 break;
7f87f8d2
VY
947 case 'S':
948 {
949 process_stats(ctl, ctl_buf);
950 break;
951 }
952#ifdef HAVE_LIBZ
953 case 'Z':
954 {
955 /* just zlib only */
956 zlib_process(ctl, ctl_buf);
957 break;
958 }
959#else
960 case 'Y':
961 case 'Z':
03d5e1e4 962 send_nozlib_support(ctl, ctl_buf);
7f87f8d2 963 break;
94b4fbf9 964
7f87f8d2
VY
965#endif
966 default:
967 break;
968 /* Log unknown commands */
969 }
970 rb_dlinkDelete(ptr, &ctl->readq);
971 rb_free(ctl_buf->buf);
972 rb_free(ctl_buf);
973 }
974
975}
976
977
978
979static void
94b4fbf9 980mod_read_ctl(rb_fde_t *F, void *data)
7f87f8d2
VY
981{
982 mod_ctl_buf_t *ctl_buf;
983 mod_ctl_t *ctl = data;
984 int retlen;
985
986 do
987 {
988 ctl_buf = rb_malloc(sizeof(mod_ctl_buf_t));
989 ctl_buf->buf = rb_malloc(READBUF_SIZE);
990 ctl_buf->buflen = READBUF_SIZE;
991 retlen = rb_recv_fd_buf(ctl->F, ctl_buf->buf, ctl_buf->buflen, ctl_buf->F,
992 MAXPASSFD);
993 if(retlen <= 0)
994 {
995 rb_free(ctl_buf->buf);
996 rb_free(ctl_buf);
997 }
998 else
999 {
1000 ctl_buf->buflen = retlen;
1001 rb_dlinkAddTail(ctl_buf, &ctl_buf->node, &ctl->readq);
1002 }
1003 }
94b4fbf9 1004 while(retlen > 0);
7f87f8d2
VY
1005
1006 if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno)))
1007 exit(0);
1008
1009 mod_process_cmd_recv(ctl);
1010 rb_setselect(ctl->F, RB_SELECT_READ, mod_read_ctl, ctl);
1011}
1012
1013static void
94b4fbf9 1014mod_write_ctl(rb_fde_t *F, void *data)
7f87f8d2
VY
1015{
1016 mod_ctl_t *ctl = data;
1017 mod_ctl_buf_t *ctl_buf;
1018 rb_dlink_node *ptr, *next;
1019 int retlen, x;
1020
1021 RB_DLINK_FOREACH_SAFE(ptr, next, ctl->writeq.head)
1022 {
1023 ctl_buf = ptr->data;
1024 retlen = rb_send_fd_buf(ctl->F, ctl_buf->F, ctl_buf->nfds, ctl_buf->buf,
94b4fbf9 1025 ctl_buf->buflen, ppid);
7f87f8d2
VY
1026 if(retlen > 0)
1027 {
1028 rb_dlinkDelete(ptr, &ctl->writeq);
94b4fbf9 1029 for(x = 0; x < ctl_buf->nfds; x++)
7f87f8d2
VY
1030 rb_close(ctl_buf->F[x]);
1031 rb_free(ctl_buf->buf);
1032 rb_free(ctl_buf);
1033
1034 }
1035 if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno)))
94b4fbf9
VY
1036 exit(0);
1037
7f87f8d2
VY
1038 rb_setselect(ctl->F, RB_SELECT_WRITE, mod_write_ctl, ctl);
1039 }
1040}
1041
1042
1043static void
94b4fbf9 1044read_pipe_ctl(rb_fde_t *F, void *data)
7f87f8d2
VY
1045{
1046 int retlen;
94b4fbf9 1047 while((retlen = rb_read(F, inbuf, sizeof(inbuf))) > 0)
7f87f8d2
VY
1048 {
1049 ;; /* we don't do anything with the pipe really, just care if the other process dies.. */
1050 }
1051 if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno)))
1052 exit(0);
1053 rb_setselect(F, RB_SELECT_READ, read_pipe_ctl, NULL);
1054
1055}
1056
1057int
1058main(int argc, char **argv)
1059{
94b4fbf9 1060 const char *s_ctlfd, *s_pipe, *s_pid;
7f87f8d2
VY
1061 int ctlfd, pipefd, x, maxfd;
1062 maxfd = maxconn();
94b4fbf9 1063
7f87f8d2
VY
1064 s_ctlfd = getenv("CTL_FD");
1065 s_pipe = getenv("CTL_PIPE");
94b4fbf9 1066 s_pid = getenv("CTL_PPID");
7f87f8d2 1067
94b4fbf9 1068 if(s_ctlfd == NULL || s_pipe == NULL || s_pid == NULL)
7f87f8d2 1069 {
94b4fbf9
VY
1070 fprintf(stderr,
1071 "This is ircd-ratbox ssld. You know you aren't supposed to run me directly?\n");
1072 fprintf(stderr,
1073 "You get an Id tag for this: $Id$\n");
7f87f8d2
VY
1074 fprintf(stderr, "Have a nice life\n");
1075 exit(1);
1076 }
1077
1078 ctlfd = atoi(s_ctlfd);
1079 pipefd = atoi(s_pipe);
94b4fbf9
VY
1080 ppid = atoi(s_pid);
1081 x = 0;
1082#ifndef _WIN32
1083 for(x = 0; x < maxfd; x++)
7f87f8d2
VY
1084 {
1085 if(x != ctlfd && x != pipefd && x > 2)
1086 close(x);
1087 }
7f87f8d2
VY
1088 x = open("/dev/null", O_RDWR);
1089 if(x >= 0)
1090 {
1091 if(ctlfd != 0 && pipefd != 0)
1092 dup2(x, 0);
1093 if(ctlfd != 1 && pipefd != 1)
1094 dup2(x, 1);
1095 if(ctlfd != 2 && pipefd != 2)
1096 dup2(x, 2);
1097 if(x > 2)
1098 close(x);
1099 }
94b4fbf9 1100#endif
7f87f8d2
VY
1101 setup_signals();
1102 rb_lib_init(NULL, NULL, NULL, 0, maxfd, 1024, 4096);
1103 rb_init_rawbuffers(1024);
94b4fbf9 1104 ssl_ok = rb_supports_ssl();
7f87f8d2
VY
1105 mod_ctl = rb_malloc(sizeof(mod_ctl_t));
1106 mod_ctl->F = rb_open(ctlfd, RB_FD_SOCKET, "ircd control socket");
1107 mod_ctl->F_pipe = rb_open(pipefd, RB_FD_PIPE, "ircd pipe");
1108 rb_set_nb(mod_ctl->F);
1109 rb_set_nb(mod_ctl->F_pipe);
1110 rb_event_addish("clean_dead_conns", clean_dead_conns, NULL, 10);
df22ecbf 1111 rb_event_add("check_handshake_flood", check_handshake_flood, NULL, 10);
7f87f8d2
VY
1112 read_pipe_ctl(mod_ctl->F_pipe, NULL);
1113 mod_read_ctl(mod_ctl->F, mod_ctl);
1114 if(!zlib_ok && !ssl_ok)
1115 {
1116 /* this is really useless... */
1117 send_i_am_useless(mod_ctl);
1118 /* sleep until the ircd kills us */
94b4fbf9 1119 rb_sleep(2 << 30, 0);
7f87f8d2
VY
1120 exit(1);
1121 }
1122
1123 if(!zlib_ok)
1124 send_nozlib_support(mod_ctl, NULL);
1125 if(!ssl_ok)
1126 send_nossl_support(mod_ctl, NULL);
1127 rb_lib_loop(0);
1128 return 0;
1129}
1130
1131
94b4fbf9 1132#ifndef _WIN32
7f87f8d2
VY
1133static void
1134dummy_handler(int sig)
1135{
1136 return;
1137}
94b4fbf9 1138#endif
7f87f8d2
VY
1139
1140static void
1141setup_signals()
1142{
94b4fbf9 1143#ifndef _WIN32
7f87f8d2
VY
1144 struct sigaction act;
1145
1146 act.sa_flags = 0;
1147 act.sa_handler = SIG_IGN;
1148 sigemptyset(&act.sa_mask);
1149 sigaddset(&act.sa_mask, SIGPIPE);
1150 sigaddset(&act.sa_mask, SIGALRM);
1151#ifdef SIGTRAP
1152 sigaddset(&act.sa_mask, SIGTRAP);
1153#endif
1154
1155#ifdef SIGWINCH
1156 sigaddset(&act.sa_mask, SIGWINCH);
1157 sigaction(SIGWINCH, &act, 0);
1158#endif
1159 sigaction(SIGPIPE, &act, 0);
1160#ifdef SIGTRAP
1161 sigaction(SIGTRAP, &act, 0);
1162#endif
1163
1164 act.sa_handler = dummy_handler;
1165 sigaction(SIGALRM, &act, 0);
94b4fbf9 1166#endif
7f87f8d2 1167}