0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-09-29 20:28:52 +02:00

ircd: Remove authproc, sslproc, wsproc, bandbi.

This commit is contained in:
Jason Volk 2016-09-11 21:04:27 -07:00
parent d36541bb86
commit 922337386e
9 changed files with 0 additions and 3045 deletions

View file

@ -1,95 +0,0 @@
/*
* charybdis
* authproc.h: A header with the authd functions.
*
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
* Copyright (C) 1996-2002 Hybrid Development Team
* Copyright (C) 2002-2012 ircd-ratbox development team
* Copyright (C) 2016 William Pitcock <nenolod@dereferenced.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#pragma once
#define HAVE_CHARYBDIS_AUTHPROC_H
#ifdef __cplusplus
namespace ircd {
struct BlacklistStats
{
char *host;
uint8_t iptype;
unsigned int hits;
};
struct OPMScanner
{
char type[16]; /* Type of proxy */
uint16_t port; /* Port */
rb_dlink_node node;
};
struct OPMListener
{
char ipaddr[HOSTIPLEN]; /* Listener address */
uint16_t port; /* Listener port */
};
enum
{
LISTEN_IPV4,
LISTEN_IPV6,
LISTEN_LAST,
};
extern rb_helper *authd_helper;
extern rb_dictionary *bl_stats;
extern rb_dlink_list opm_list;
extern struct OPMListener opm_listeners[LISTEN_LAST];
void init_authd(void);
void configure_authd(void);
void restart_authd(void);
void rehash_authd(void);
void check_authd(void);
void authd_initiate_client(client::client *, bool defer);
void authd_deferred_client(client::client *);
void authd_accept_client(client::client *client_p, const char *ident, const char *host);
void authd_reject_client(client::client *client_p, const char *ident, const char *host, char cause, const char *data, const char *reason);
void authd_abort_client(client::client *);
void add_blacklist(const char *host, const char *reason, uint8_t iptype, rb_dlink_list *filters);
void del_blacklist(const char *host);
void del_blacklist_all(void);
bool set_authd_timeout(const char *key, int timeout);
void ident_check_enable(bool enabled);
void conf_create_opm_listener(const char *ip, uint16_t port);
void create_opm_listener(const char *ip, uint16_t port);
void conf_create_opm_proxy_scanner(const char *type, uint16_t port);
void create_opm_proxy_scanner(const char *type, uint16_t port);
void delete_opm_proxy_scanner(const char *type, uint16_t port);
void delete_opm_proxy_scanner_all(void);
void delete_opm_listener_all(void);
void opm_check_enable(bool enabled);
} // namespace ircd
#endif // __cplusplus

View file

@ -1,44 +0,0 @@
/**
* Copyright (C) 2016 Charybdis Development Team
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice is present in all copies.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#define HAVE_BANDBI_H
#ifdef __cplusplus
namespace ircd {
void init_bandb(void);
typedef enum
{
BANDB_KLINE,
BANDB_DLINE,
BANDB_XLINE,
BANDB_RESV,
LAST_BANDB_TYPE
} bandb_type;
void bandb_add(bandb_type, client::client *source_p, const char *mask1,
const char *mask2, const char *reason, const char *oper_reason, int perm);
void bandb_del(bandb_type, const char *mask1, const char *mask2);
void bandb_rehash_bans(void);
} // namespace ircd
#endif // __cplusplus

View file

@ -1,49 +0,0 @@
/*
* sslproc.h: An interface to the ratbox ssld helper daemon
* Copyright (C) 2007 Aaron Sethman <androsyn@ratbox.org>
* Copyright (C) 2007 ircd-ratbox development team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#pragma once
#define HAVE_IRCD_SSLPROC_H
#ifdef __cplusplus
namespace ircd {
struct _ssl_ctl;
typedef struct _ssl_ctl ssl_ctl_t;
enum ssld_status {
SSLD_ACTIVE,
SSLD_SHUTDOWN,
SSLD_DEAD,
};
void init_ssld(void);
void restart_ssld(void);
int start_ssldaemon(int count);
ssl_ctl_t *start_ssld_accept(rb_fde_t *sslF, rb_fde_t *plainF, uint32_t id);
ssl_ctl_t *start_ssld_connect(rb_fde_t *sslF, rb_fde_t *plainF, uint32_t id);
void start_zlib_session(void *data);
void ssld_update_config(void);
void ssld_decrement_clicount(ssl_ctl_t *ctl);
int get_ssld_count(void);
void ssld_foreach_info(void (*func)(void *data, pid_t pid, int cli_count, enum ssld_status status, const char *version), void *data);
} // namespace ircd
#endif // __cplusplus

View file

@ -66,9 +66,6 @@ namespace ircd
struct ConfItem;
struct Blacklist;
struct PrivilegeSet;
struct _ssl_ctl;
struct ev_ctl;
struct ws_ctl;
struct server_conf;
}
@ -118,8 +115,6 @@ namespace ircd
#include "chmode.h"
#include "channel.h"
#include "authproc.h"
#include "bandbi.h"
#include "capability.h"
#include "certfp.h"
#include "class.h"
@ -135,10 +130,8 @@ namespace ircd
#include "send.h"
#include "s_newconf.h"
#include "s_serv.h"
#include "sslproc.h"
#include "s_stats.h"
#include "substitution.h"
#include "supported.h"
#include "s_user.h"
#include "wsproc.h"
*/

View file

@ -1,47 +0,0 @@
/*
* wsproc.h: An interface to the charybdis websocket helper daemon
* Copyright (C) 2007 Aaron Sethman <androsyn@ratbox.org>
* Copyright (C) 2007 ircd-ratbox development team
* Copyright (C) 2016 William Pitcock <nenolod@dereferenced.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#pragma once
#define HAVE_IRCD_WSPROC_H
#ifdef __cplusplus
namespace ircd {
struct ws_ctl;
typedef struct ws_ctl ws_ctl_t;
enum wsockd_status {
WSOCKD_ACTIVE,
WSOCKD_SHUTDOWN,
WSOCKD_DEAD,
};
void init_wsockd(void);
void restart_wsockd(void);
int start_wsockd(int count);
ws_ctl_t *start_wsockd_accept(rb_fde_t *wsF, rb_fde_t *plainF, uint32_t id);
void wsockd_decrement_clicount(ws_ctl_t *ctl);
int get_wsockd_count(void);
void wsockd_foreach_info(void (*func)(void *data, pid_t pid, int cli_count, enum wsockd_status status), void *data);
} // namespace ircd
#endif // __cplusplus

View file

@ -1,781 +0,0 @@
/*
* authd.c: An interface to authd.
* (based somewhat on ircd-ratbox dns.c)
*
* Copyright (C) 2005 Aaron Sethman <androsyn@ratbox.org>
* Copyright (C) 2005-2012 ircd-ratbox development team
* Copyright (C) 2016 William Pitcock <nenolod@dereferenced.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
namespace ircd {
typedef void (*authd_cb_t)(int, char **);
struct authd_cb
{
authd_cb_t fn;
int min_parc;
};
static int start_authd(void);
static void parse_authd_reply(rb_helper * helper);
static void restart_authd_cb(rb_helper * helper);
static EVH timeout_dead_authd_clients;
static void cmd_accept_client(int parc, char **parv);
static void cmd_reject_client(int parc, char **parv);
static void cmd_dns_result(int parc, char **parv);
static void cmd_notice_client(int parc, char **parv);
static void cmd_oper_warn(int parc, char **parv);
static void cmd_stats_results(int parc, char **parv);
rb_helper *authd_helper;
static char *authd_path;
uint32_t cid;
static rb_dictionary *cid_clients;
static struct ev_entry *timeout_ev;
rb_dictionary *bl_stats;
rb_dlink_list opm_list;
struct OPMListener opm_listeners[LISTEN_LAST];
std::array<authd_cb, 256> authd_cmd_tab =
[]{
std::array<authd_cb, 256> ret {0};
ret['A'] = { cmd_accept_client, 4 };
ret['E'] = { cmd_dns_result, 5 };
ret['N'] = { cmd_notice_client, 3 };
ret['R'] = { cmd_reject_client, 7 };
ret['W'] = { cmd_oper_warn, 3 };
ret['X'] = { cmd_stats_results, 3 };
ret['Y'] = { cmd_stats_results, 3 };
ret['Z'] = { cmd_stats_results, 3 };
return ret;
}();
static int
start_authd(void)
{
char fullpath[PATH_MAX + 1];
#ifdef _WIN32
const char *suffix = ".exe";
#else
const char *suffix = "";
#endif
if(authd_path == NULL)
{
snprintf(fullpath, sizeof(fullpath), "%s%cauthd%s", path::get(path::LIBEXEC), RB_PATH_SEPARATOR, suffix);
if(access(fullpath, X_OK) == -1)
{
snprintf(fullpath, sizeof(fullpath), "%s%cbin%cauthd%s",
ConfigFileEntry.dpath, RB_PATH_SEPARATOR, RB_PATH_SEPARATOR, suffix);
if(access(fullpath, X_OK) == -1)
{
// TODO: double dipping
ierror("Unable to execute authd in %s or %s/bin",
path::get(path::LIBEXEC),
ConfigFileEntry.dpath);
// TODO: double dipping
sendto_realops_snomask(sno::GENERAL, L_ALL,
"Unable to execute authd in %s or %s/bin",
path::get(path::LIBEXEC),
ConfigFileEntry.dpath);
return 1;
}
}
authd_path = rb_strdup(fullpath);
}
if(cid_clients == NULL)
cid_clients = rb_dictionary_create("authd cid to uid mapping", rb_uint32cmp);
if(timeout_ev == NULL)
timeout_ev = rb_event_addish("timeout_dead_authd_clients", timeout_dead_authd_clients, NULL, 1);
authd_helper = rb_helper_start("authd", authd_path, parse_authd_reply, restart_authd_cb);
if(authd_helper == NULL)
{
ierror("Unable to start authd helper: %s", strerror(errno));
sendto_realops_snomask(sno::GENERAL, L_ALL, "Unable to start authd helper: %s", strerror(errno));
return 1;
}
ilog(L_MAIN, "authd helper started");
sendto_realops_snomask(sno::GENERAL, L_ALL, "authd helper started");
rb_helper_run(authd_helper);
return 0;
}
static inline uint32_t
str_to_cid(const char *str)
{
long lcid = strtol(str, NULL, 16);
if(lcid > UINT32_MAX || lcid <= 0)
{
iwarn("authd sent us back a bad client ID: %lx", lcid);
restart_authd();
return 0;
}
return (uint32_t)lcid;
}
static inline client::client *
cid_to_client(uint32_t ncid, bool del)
{
client::client *client_p;
if(del)
client_p = (client::client *)rb_dictionary_delete(cid_clients, RB_UINT_TO_POINTER(ncid));
else
client_p = (client::client *)rb_dictionary_retrieve(cid_clients, RB_UINT_TO_POINTER(ncid));
/* If the client's not found, that's okay, it may have already gone away.
* --Elizafox */
return client_p;
}
static inline client::client *
str_cid_to_client(const char *str, bool del)
{
uint32_t ncid = str_to_cid(str);
if(ncid == 0)
return NULL;
return cid_to_client(ncid, del);
}
static void
cmd_accept_client(int parc, char **parv)
{
client::client *client_p;
/* cid to uid (retrieve and delete) */
if((client_p = str_cid_to_client(parv[1], true)) == NULL)
return;
authd_accept_client(client_p, parv[2], parv[3]);
}
static void
cmd_dns_result(int parc, char **parv)
{
dns_results_callback(parv[1], parv[2], parv[3], parv[4]);
}
static void
cmd_notice_client(int parc, char **parv)
{
client::client *client_p;
if((client_p = str_cid_to_client(parv[1], false)) == NULL)
return;
sendto_one_notice(client_p, ":%s", parv[2]);
}
static void
cmd_reject_client(int parc, char **parv)
{
client::client *client_p;
/* cid to uid (retrieve and delete) */
if((client_p = str_cid_to_client(parv[1], true)) == NULL)
return;
authd_reject_client(client_p, parv[3], parv[4], toupper(*parv[2]), parv[5], parv[6]);
}
static void
cmd_oper_warn(int parc, char **parv)
{
switch(*parv[1])
{
case 'D': /* Debug */
sendto_realops_snomask(sno::DEBUG, L_ALL, "authd debug: %s", parv[2]);
idebug("authd: %s", parv[2]);
break;
case 'I': /* Info */
sendto_realops_snomask(sno::GENERAL, L_ALL, "authd info: %s", parv[2]);
inotice("authd: %s", parv[2]);
break;
case 'W': /* Warning */
sendto_realops_snomask(sno::GENERAL, L_ALL, "authd WARNING: %s", parv[2]);
iwarn("authd: %s", parv[2]);
break;
case 'C': /* Critical (error) */
sendto_realops_snomask(sno::GENERAL, L_ALL, "authd CRITICAL: %s", parv[2]);
ierror("authd: %s", parv[2]);
break;
default: /* idk */
sendto_realops_snomask(sno::GENERAL, L_ALL, "authd sent us an unknown oper notice type (%s): %s", parv[1], parv[2]);
ilog(L_MAIN, "authd unknown oper notice type (%s): %s", parv[1], parv[2]);
break;
}
}
static void
cmd_stats_results(int parc, char **parv)
{
/* Select by type */
switch(*parv[2])
{
case 'D':
/* parv[0] conveys status */
if(parc < 4)
{
iwarn("authd sent a result with wrong number of arguments: got %d", parc);
restart_authd();
return;
}
dns_stats_results_callback(parv[1], parv[0], parc - 3, (const char **)&parv[3]);
break;
default:
break;
}
}
static void
parse_authd_reply(rb_helper * helper)
{
ssize_t len;
int parc;
char buf[READBUF_SIZE];
char *parv[MAXPARA + 1];
while((len = rb_helper_read(helper, buf, sizeof(buf))) > 0)
{
struct authd_cb *cmd;
parc = rb_string_to_array(buf, parv, MAXPARA+1);
cmd = &authd_cmd_tab[(unsigned char)*parv[0]];
if(cmd->fn != NULL)
{
if(cmd->min_parc > parc)
{
iwarn("authd sent a result with wrong number of arguments: expected %d, got %d",
cmd->min_parc, parc);
restart_authd();
continue;
}
cmd->fn(parc, parv);
}
else
{
iwarn("authd sent us a bad command type: %c", *parv[0]);
restart_authd();
continue;
}
}
}
void
init_authd(void)
{
if(start_authd())
{
ierror("Unable to start authd helper: %s", strerror(errno));
exit(0);
}
}
void
configure_authd(void)
{
/* Timeouts */
set_authd_timeout("ident_timeout", GlobalSetOptions.ident_timeout);
set_authd_timeout("rdns_timeout", ConfigFileEntry.connect_timeout);
set_authd_timeout("rbl_timeout", ConfigFileEntry.connect_timeout);
ident_check_enable(!ConfigFileEntry.disable_auth);
/* Configure OPM */
if(rb_dlink_list_length(&opm_list) > 0 &&
(opm_listeners[LISTEN_IPV4].ipaddr[0] != '\0' ||
opm_listeners[LISTEN_IPV6].ipaddr[0] != '\0'))
{
rb_dlink_node *ptr;
if(opm_listeners[LISTEN_IPV4].ipaddr[0] != '\0')
rb_helper_write(authd_helper, "O opm_listener %s %hu",
opm_listeners[LISTEN_IPV4].ipaddr, opm_listeners[LISTEN_IPV4].port);
#ifdef RB_IPV6
if(opm_listeners[LISTEN_IPV6].ipaddr[0] != '\0')
rb_helper_write(authd_helper, "O opm_listener %s %hu",
opm_listeners[LISTEN_IPV6].ipaddr, opm_listeners[LISTEN_IPV6].port);
#endif
RB_DLINK_FOREACH(ptr, opm_list.head)
{
struct OPMScanner *scanner = (OPMScanner *)ptr->data;
rb_helper_write(authd_helper, "O opm_scanner %s %hu",
scanner->type, scanner->port);
}
opm_check_enable(true);
}
else
opm_check_enable(false);
}
static void
authd_free_client(client::client *client_p)
{
if(client_p == NULL || client_p->preClient == NULL)
return;
if(client_p->preClient->auth.cid == 0)
return;
if(authd_helper != NULL)
rb_helper_write(authd_helper, "E %x", client_p->preClient->auth.cid);
client_p->preClient->auth.accepted = true;
client_p->preClient->auth.cid = 0;
}
static void
authd_free_client_cb(rb_dictionary_element *delem, void *unused)
{
client::client *client_p = (client::client *)delem->data;
authd_free_client(client_p);
}
void
authd_abort_client(client::client *client_p)
{
rb_dictionary_delete(cid_clients, RB_UINT_TO_POINTER(client_p->preClient->auth.cid));
authd_free_client(client_p);
}
static void
restart_authd_cb(rb_helper * helper)
{
rb_dictionary_iter iter;
client::client *client_p;
iwarn("authd: restart_authd_cb called, authd died?");
sendto_realops_snomask(sno::GENERAL, L_ALL, "authd: restart_authd_cb called, authd died?");
if(helper != NULL)
{
rb_helper_close(helper);
authd_helper = NULL;
}
rb_dictionary_destroy(cid_clients, authd_free_client_cb, NULL);
cid_clients = NULL;
start_authd();
configure_authd();
}
void
restart_authd(void)
{
ierror("authd restarting...");
restart_authd_cb(authd_helper);
}
void
rehash_authd(void)
{
rb_helper_write(authd_helper, "R");
}
void
check_authd(void)
{
if(authd_helper == NULL)
restart_authd();
}
static inline uint32_t
generate_cid(void)
{
if(++cid == 0)
cid = 1;
return cid;
}
/* Basically when this is called we begin handing off the client to authd for
* processing. authd "owns" the client until processing is finished, or we
* timeout from authd. authd will make a decision whether or not to accept the
* client, but it's up to other parts of the code (for now) to decide if we're
* gonna accept the client and ignore authd's suggestion.
*
* --Elizafox
*
* If this is an SSL connection we must defer handing off the client for
* reading until it is open and we have the certificate fingerprint, otherwise
* it's possible for the client to immediately send data before authd completes
* and before the status of the connection is communicated via ssld. This data
* could then be processed too early by read_packet().
*/
void
authd_initiate_client(client::client *client_p, bool defer)
{
char client_ipaddr[HOSTIPLEN+1];
char listen_ipaddr[HOSTIPLEN+1];
uint16_t client_port, listen_port;
uint32_t authd_cid;
if(client_p->preClient == NULL || client_p->preClient->auth.cid != 0)
return;
authd_cid = client_p->preClient->auth.cid = generate_cid();
/* Collisions are extremely unlikely, so disregard the possibility */
rb_dictionary_add(cid_clients, RB_UINT_TO_POINTER(authd_cid), client_p);
/* Retrieve listener and client IP's */
rb_inet_ntop_sock((struct sockaddr *)&client_p->preClient->lip, listen_ipaddr, sizeof(listen_ipaddr));
rb_inet_ntop_sock((struct sockaddr *)&client_p->localClient->ip, client_ipaddr, sizeof(client_ipaddr));
/* Retrieve listener and client ports */
listen_port = ntohs(GET_SS_PORT(&client_p->preClient->lip));
client_port = ntohs(GET_SS_PORT(&client_p->localClient->ip));
if(defer)
client_p->preClient->auth.flags |= AUTHC_F_DEFERRED;
/* Add a bit of a fudge factor... */
client_p->preClient->auth.timeout = rb_current_time() + ConfigFileEntry.connect_timeout + 10;
rb_helper_write(authd_helper, "C %x %s %hu %s %hu", authd_cid, listen_ipaddr, listen_port, client_ipaddr, client_port);
}
static inline void
authd_read_client(client::client *client_p)
{
/*
* When a client has auth'ed, we want to start reading what it sends
* us. This is what read_packet() does.
* -- adrian
*
* Above comment was originally in s_auth.c, but moved here with below code.
* --Elizafox
*/
rb_dlinkAddTail(client_p, &client_p->node, &global_client_list);
read_packet(client_p->localClient->F, client_p);
}
/* When this is called we have a decision on client acceptance.
*
* After this point authd no longer "owns" the client, but if
* it's flagged as deferred then we're still waiting for a call
* to authd_deferred_client().
*/
static inline void
authd_decide_client(client::client *client_p, const char *ident, const char *host, bool accept, char cause, const char *data, const char *reason)
{
if(client_p->preClient == NULL || client_p->preClient->auth.cid == 0)
return;
if(*ident != '*')
{
rb_strlcpy(client_p->username, ident, sizeof(client_p->username));
set_got_id(*client_p);
ServerStats.is_asuc++;
}
else
ServerStats.is_abad++; /* s_auth used to do this, stay compatible */
if(*host != '*')
rb_strlcpy(client_p->host, host, sizeof(client_p->host));
rb_dictionary_delete(cid_clients, RB_UINT_TO_POINTER(client_p->preClient->auth.cid));
client_p->preClient->auth.accepted = accept;
client_p->preClient->auth.cause = cause;
client_p->preClient->auth.data = (data == NULL ? NULL : rb_strdup(data));
client_p->preClient->auth.reason = (reason == NULL ? NULL : rb_strdup(reason));
client_p->preClient->auth.cid = 0;
client_p->preClient->auth.flags |= AUTHC_F_COMPLETE;
if((client_p->preClient->auth.flags & AUTHC_F_DEFERRED) == 0)
authd_read_client(client_p);
}
void
authd_deferred_client(client::client *client_p)
{
client_p->preClient->auth.flags &= ~AUTHC_F_DEFERRED;
if(client_p->preClient->auth.flags & AUTHC_F_COMPLETE)
authd_read_client(client_p);
}
/* Convenience function to accept client */
void
authd_accept_client(client::client *client_p, const char *ident, const char *host)
{
authd_decide_client(client_p, ident, host, true, '\0', NULL, NULL);
}
/* Convenience function to reject client */
void
authd_reject_client(client::client *client_p, const char *ident, const char *host, char cause, const char *data, const char *reason)
{
authd_decide_client(client_p, ident, host, false, cause, data, reason);
}
static void
timeout_dead_authd_clients(void *notused)
{
rb_dictionary_iter iter;
client::client *client_p;
rb_dlink_list freelist = { NULL, NULL, 0 };
rb_dlink_node *ptr, *nptr;
void *elem;
RB_DICTIONARY_FOREACH(elem, &iter, cid_clients)
{
client_p = (client::client *)elem;
if(client_p->preClient->auth.timeout < rb_current_time())
{
authd_free_client(client_p);
rb_dlinkAddAlloc(client_p, &freelist);
}
}
/* RB_DICTIONARY_FOREACH is not safe for deletion, so we do this crap */
RB_DLINK_FOREACH_SAFE(ptr, nptr, freelist.head)
{
client_p = (client::client *)ptr->data;
rb_dictionary_delete(cid_clients, RB_UINT_TO_POINTER(client_p->preClient->auth.cid));
}
}
/* Send a new blacklist to authd */
void
add_blacklist(const char *host, const char *reason, uint8_t iptype, rb_dlink_list *filters)
{
rb_dlink_node *ptr;
struct BlacklistStats *stats = (BlacklistStats *)rb_malloc(sizeof(struct BlacklistStats));
char filterbuf[BUFSIZE] = "*";
size_t s = 0;
if(bl_stats == NULL)
bl_stats = rb_dictionary_create("blacklist statistics", reinterpret_cast<int (*)(const void *, const void *)>(rb_strcasecmp));
/* Build a list of comma-separated values for authd.
* We don't check for validity - do it elsewhere.
*/
RB_DLINK_FOREACH(ptr, filters->head)
{
char *filter = (char *)ptr->data;
size_t filterlen = strlen(filter) + 1;
if(s + filterlen > sizeof(filterbuf))
break;
snprintf(&filterbuf[s], sizeof(filterbuf) - s, "%s,", filter);
s += filterlen;
}
if(s)
filterbuf[s - 1] = '\0';
stats->host = rb_strdup(host);
stats->iptype = iptype;
stats->hits = 0;
rb_dictionary_add(bl_stats, stats->host, stats);
rb_helper_write(authd_helper, "O rbl %s %hhu %s :%s", host, iptype, filterbuf, reason);
}
/* Delete a blacklist */
void
del_blacklist(const char *host)
{
struct BlacklistStats *stats = (BlacklistStats *)rb_dictionary_retrieve(bl_stats, host);
if(stats != NULL)
{
rb_dictionary_delete(bl_stats, host);
rb_free(stats->host);
rb_free(stats);
}
rb_helper_write(authd_helper, "O rbl_del %s", host);
}
static void
blacklist_delete(rb_dictionary_element *delem, void *unused)
{
struct BlacklistStats *stats = (BlacklistStats *)delem->data;
rb_free(stats->host);
rb_free(stats);
}
/* Delete all the blacklists */
void
del_blacklist_all(void)
{
if(bl_stats != NULL)
rb_dictionary_destroy(bl_stats, blacklist_delete, NULL);
bl_stats = NULL;
rb_helper_write(authd_helper, "O rbl_del_all");
}
/* Adjust an authd timeout value */
bool
set_authd_timeout(const char *key, int timeout)
{
if(timeout <= 0)
return false;
rb_helper_write(authd_helper, "O %s %d", key, timeout);
return true;
}
/* Enable identd checks */
void
ident_check_enable(bool enabled)
{
rb_helper_write(authd_helper, "O ident_enabled %d", enabled ? 1 : 0);
}
/* Create an OPM listener
* XXX - This is a big nasty hack, but it avoids resending duplicate data when
* configure_authd() is called.
*/
void
conf_create_opm_listener(const char *ip, uint16_t port)
{
char ipbuf[HOSTIPLEN];
struct OPMListener *listener;
rb_strlcpy(ipbuf, ip, sizeof(ipbuf));
if(ipbuf[0] == ':')
{
memmove(ipbuf + 1, ipbuf, sizeof(ipbuf) - 1);
ipbuf[0] = '0';
}
/* I am much too lazy to use rb_inet_pton and GET_SS_FAMILY for now --Elizafox */
listener = &opm_listeners[(strchr(ipbuf, ':') != NULL ? LISTEN_IPV6 : LISTEN_IPV4)];
rb_strlcpy(listener->ipaddr, ipbuf, sizeof(listener->ipaddr));
listener->port = port;
}
void
create_opm_listener(const char *ip, uint16_t port)
{
char ipbuf[HOSTIPLEN];
/* XXX duplicated in conf_create_opm_listener */
rb_strlcpy(ipbuf, ip, sizeof(ipbuf));
if(ipbuf[0] == ':')
{
memmove(ipbuf + 1, ipbuf, sizeof(ipbuf) - 1);
ipbuf[0] = '0';
}
conf_create_opm_listener(ip, port);
rb_helper_write(authd_helper, "O opm_listener %s %hu", ipbuf, port);
}
void
delete_opm_listener_all(void)
{
memset(&opm_listeners, 0, sizeof(opm_listeners));
rb_helper_write(authd_helper, "O opm_listener_del_all");
}
/* Disable all OPM scans */
void
opm_check_enable(bool enabled)
{
rb_helper_write(authd_helper, "O opm_enabled %d", enabled ? 1 : 0);
}
/* Create an OPM proxy scanner
* XXX - This is a big nasty hack, but it avoids resending duplicate data when
* configure_authd() is called.
*/
void
conf_create_opm_proxy_scanner(const char *type, uint16_t port)
{
struct OPMScanner *scanner = (OPMScanner *)rb_malloc(sizeof(struct OPMScanner));
rb_strlcpy(scanner->type, type, sizeof(scanner->type));
scanner->port = port;
rb_dlinkAdd(scanner, &scanner->node, &opm_list);
}
void
create_opm_proxy_scanner(const char *type, uint16_t port)
{
conf_create_opm_proxy_scanner(type, port);
rb_helper_write(authd_helper, "O opm_scanner %s %hu", type, port);
}
void
delete_opm_proxy_scanner(const char *type, uint16_t port)
{
rb_dlink_node *ptr, *nptr;
RB_DLINK_FOREACH_SAFE(ptr, nptr, opm_list.head)
{
struct OPMScanner *scanner = (OPMScanner *)ptr->data;
if(rb_strncasecmp(scanner->type, type, sizeof(scanner->type)) == 0 &&
scanner->port == port)
{
rb_dlinkDelete(ptr, &opm_list);
rb_free(scanner);
break;
}
}
rb_helper_write(authd_helper, "O opm_scanner_del %s %hu", type, port);
}
void
delete_opm_proxy_scanner_all(void)
{
rb_dlink_node *ptr, *nptr;
RB_DLINK_FOREACH_SAFE(ptr, nptr, opm_list.head)
{
struct OPMScanner *scanner = (OPMScanner *)ptr->data;
rb_dlinkDelete(ptr, &opm_list);
rb_free(scanner);
}
rb_helper_write(authd_helper, "O opm_scanner_del_all");
}
} // namespace ircd

View file

@ -1,437 +0,0 @@
/* src/bandbi.c
* An interface to the ban db.
*
* Copyright (C) 2006 Lee Hardy <lee -at- leeh.co.uk>
* Copyright (C) 2006 ircd-ratbox development team
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1.Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2.Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3.The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace ircd {
static void
bandb_handle_failure(rb_helper *helper, char **parv, int parc) __attribute__((noreturn));
static char bandb_add_letter[LAST_BANDB_TYPE] = {
'K', 'D', 'X', 'R'
};
rb_dlink_list bandb_pending;
static rb_helper *bandb_helper;
static int start_bandb(void);
static void bandb_parse(rb_helper *);
static void bandb_restart_cb(rb_helper *);
static char *bandb_path;
void
init_bandb(void)
{
if(start_bandb())
{
ilog(L_MAIN, "Unable to start bandb helper: %s", strerror(errno));
exit(0);
}
}
static int
start_bandb(void)
{
char fullpath[PATH_MAX + 1];
#ifdef _WIN32
const char *suffix = ".exe";
#else
const char *suffix = "";
#endif
rb_setenv("BANDB_DBPATH", path::get(path::BANDB), 1);
if(bandb_path == NULL)
{
snprintf(fullpath, sizeof(fullpath), "%s%cbandb%s", path::get(path::LIBEXEC), RB_PATH_SEPARATOR, suffix);
if(access(fullpath, X_OK) == -1)
{
snprintf(fullpath, sizeof(fullpath), "%s%cbin%cbandb%s",
ConfigFileEntry.dpath, RB_PATH_SEPARATOR, RB_PATH_SEPARATOR, suffix);
if(access(fullpath, X_OK) == -1)
{
ilog(L_MAIN,
"Unable to execute bandb%s in %s or %s/bin",
suffix, path::get(path::LIBEXEC), ConfigFileEntry.dpath);
return 0;
}
}
bandb_path = rb_strdup(fullpath);
}
bandb_helper = rb_helper_start("bandb", bandb_path, bandb_parse, bandb_restart_cb);
if(bandb_helper == NULL)
{
ilog(L_MAIN, "Unable to start bandb: %s", strerror(errno));
sendto_realops_snomask(sno::GENERAL, L_ALL, "Unable to start bandb: %s",
strerror(errno));
return 1;
}
rb_helper_run(bandb_helper);
return 0;
}
void
bandb_add(bandb_type type, client::client *source_p, const char *mask1,
const char *mask2, const char *reason, const char *oper_reason, int perm)
{
if(bandb_helper == NULL)
return;
static char buf[BUFSIZE];
snprintf(buf, sizeof(buf), "%c %s ", bandb_add_letter[type], mask1);
if(!EmptyString(mask2))
rb_snprintf_append(buf, sizeof(buf), "%s ", mask2);
rb_snprintf_append(buf, sizeof(buf), "%s %ld %d :%s",
get_oper_name(source_p), (long int)rb_current_time(), perm, reason);
if(!EmptyString(oper_reason))
rb_snprintf_append(buf, sizeof(buf), "|%s", oper_reason);
rb_helper_write(bandb_helper, "%s", buf);
}
static char bandb_del_letter[LAST_BANDB_TYPE] = {
'k', 'd', 'x', 'r'
};
void
bandb_del(bandb_type type, const char *mask1, const char *mask2)
{
if(bandb_helper == NULL)
return;
static char buf[BUFSIZE];
buf[0] = '\0';
rb_snprintf_append(buf, sizeof(buf), "%c %s", bandb_del_letter[type], mask1);
if(!EmptyString(mask2))
rb_snprintf_append(buf, sizeof(buf), " %s", mask2);
rb_helper_write(bandb_helper, "%s", buf);
}
static void
bandb_handle_ban(char *parv[], int parc)
{
struct ConfItem *aconf;
char *p;
int para = 1;
aconf = make_conf();
aconf->port = 0;
if(parv[0][0] == 'K')
aconf->user = rb_strdup(parv[para++]);
aconf->host = rb_strdup(parv[para++]);
aconf->info.oper = operhash_add(parv[para++]);
switch (parv[0][0])
{
case 'K':
aconf->status = CONF_KILL;
break;
case 'D':
aconf->status = CONF_DLINE;
break;
case 'X':
aconf->status = CONF_XLINE;
break;
case 'R':
if(chan::has_prefix(aconf->host))
aconf->status = CONF_RESV_CHANNEL;
else
aconf->status = CONF_RESV_NICK;
break;
}
if((p = strchr(parv[para], '|')))
{
*p++ = '\0';
aconf->spasswd = rb_strdup(p);
}
aconf->passwd = rb_strdup(parv[para]);
rb_dlinkAddAlloc(aconf, &bandb_pending);
}
static int
bandb_check_kline(struct ConfItem *aconf)
{
struct rb_sockaddr_storage daddr;
struct ConfItem *kconf = NULL;
int aftype;
const char *p;
aftype = parse_netmask(aconf->host, &daddr, NULL);
if(aftype != HM_HOST)
{
#ifdef RB_IPV6
if(aftype == HM_IPV6)
aftype = AF_INET6;
else
#endif
aftype = AF_INET;
kconf = find_conf_by_address(aconf->host, NULL, NULL, (struct sockaddr *)&daddr,
CONF_KILL, aftype, aconf->user, NULL);
}
else
kconf = find_conf_by_address(aconf->host, NULL, NULL, NULL, CONF_KILL, 0, aconf->user, NULL);
if(kconf && ((kconf->flags & CONF_FLAGS_TEMPORARY) == 0))
return 0;
for(p = aconf->user; *p; p++)
if(!rfc1459::is_user(*p) && !rfc1459::is_kwild(*p))
return 0;
for(p = aconf->host; *p; p++)
if(!rfc1459::is_host(*p) && !rfc1459::is_kwild(*p))
return 0;
return 1;
}
static int
bandb_check_dline(struct ConfItem *aconf)
{
struct rb_sockaddr_storage daddr;
int bits;
if(!parse_netmask(aconf->host, &daddr, &bits))
return 0;
return 1;
}
static int
bandb_check_xline(struct ConfItem *aconf)
{
struct ConfItem *xconf;
/* XXX perhaps convert spaces to \s? -- jilles */
xconf = find_xline_mask(aconf->host);
if(xconf != NULL && !(xconf->flags & CONF_FLAGS_TEMPORARY))
return 0;
return 1;
}
static int
bandb_check_resv_channel(struct ConfItem *aconf)
{
const char *p;
if(hash_find_resv(aconf->host) || strlen(aconf->host) > CHANNELLEN)
return 0;
for(p = aconf->host; *p; p++)
if(!rfc1459::is_chan(*p))
return 0;
return 1;
}
static int
bandb_check_resv_nick(struct ConfItem *aconf)
{
if(!clean_resv_nick(aconf->host))
return 0;
if(find_nick_resv(aconf->host))
return 0;
return 1;
}
static void
bandb_handle_clear(void)
{
rb_dlink_node *ptr, *next_ptr;
RB_DLINK_FOREACH_SAFE(ptr, next_ptr, bandb_pending.head)
{
free_conf((ConfItem *)ptr->data);
rb_dlinkDestroy(ptr, &bandb_pending);
}
}
static void
bandb_handle_finish(void)
{
struct ConfItem *aconf;
rb_dlink_node *ptr, *next_ptr;
clear_out_address_conf_bans();
clear_s_newconf_bans();
RB_DLINK_FOREACH_SAFE(ptr, next_ptr, bandb_pending.head)
{
aconf = (ConfItem *)ptr->data;
rb_dlinkDestroy(ptr, &bandb_pending);
switch (aconf->status)
{
case CONF_KILL:
if(bandb_check_kline(aconf))
add_conf_by_address(aconf->host, CONF_KILL, aconf->user, NULL, aconf);
else
free_conf(aconf);
break;
case CONF_DLINE:
if(bandb_check_dline(aconf))
add_conf_by_address(aconf->host, CONF_DLINE, aconf->user, NULL, aconf);
else
free_conf(aconf);
break;
case CONF_XLINE:
if(bandb_check_xline(aconf))
rb_dlinkAddAlloc(aconf, &xline_conf_list);
else
free_conf(aconf);
break;
case CONF_RESV_CHANNEL:
if(bandb_check_resv_channel(aconf))
add_to_resv_hash(aconf->host, aconf);
else
free_conf(aconf);
break;
case CONF_RESV_NICK:
if(bandb_check_resv_nick(aconf))
rb_dlinkAddAlloc(aconf, &resv_conf_list);
else
free_conf(aconf);
break;
}
}
client::check_banned_lines();
}
static void
bandb_handle_failure(rb_helper *helper, char **parv, int parc)
{
if(server_state_foreground)
fprintf(stderr, "bandb - bandb failure: %s\n", parv[1]);
ilog(L_MAIN, "bandb - bandb failure: %s", parv[1]);
sendto_realops_snomask(sno::GENERAL, L_ALL, "bandb - bandb failure: %s", parv[1]);
exit(1);
}
static void
bandb_parse(rb_helper *helper)
{
static char buf[READBUF_SIZE];
char *parv[MAXPARA + 1];
int len, parc;
while((len = rb_helper_read(helper, buf, sizeof(buf))))
{
parc = rb_string_to_array(buf, parv, MAXPARA);
if(parc < 1)
continue;
switch (parv[0][0])
{
case '!':
bandb_handle_failure(helper, parv, parc);
break;
case 'K':
case 'D':
case 'X':
case 'R':
bandb_handle_ban(parv, parc);
break;
case 'C':
bandb_handle_clear();
break;
case 'F':
bandb_handle_finish();
break;
}
}
}
void
bandb_rehash_bans(void)
{
if(bandb_helper != NULL)
rb_helper_write(bandb_helper, "L");
}
static void
bandb_restart_cb(rb_helper *helper)
{
ilog(L_MAIN, "bandb - bandb_restart_cb called, bandb helper died?");
sendto_realops_snomask(sno::GENERAL, L_ALL,
"bandb - bandb_restart_cb called, bandb helper died?");
if(helper != NULL)
{
rb_helper_close(helper);
bandb_helper = NULL;
}
start_bandb();
return;
}
} // namespace ircd

File diff suppressed because it is too large Load diff

View file

@ -1,583 +0,0 @@
/*
* sslproc.c: An interface to wsockd
* Copyright (C) 2007 Aaron Sethman <androsyn@ratbox.org>
* Copyright (C) 2007 ircd-ratbox development team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
namespace ircd {
static void ws_read_ctl(rb_fde_t * F, void *data);
static int wsockd_count;
static char tmpbuf[READBUF_SIZE];
static char nul = '\0';
#define MAXPASSFD 4
#define READSIZE 1024
typedef struct _ws_ctl_buf
{
rb_dlink_node node;
char *buf;
size_t buflen;
rb_fde_t *F[MAXPASSFD];
int nfds;
} ws_ctl_buf_t;
struct ws_ctl
{
rb_dlink_node node;
int cli_count;
rb_fde_t *F;
rb_fde_t *P;
pid_t pid;
rb_dlink_list readq;
rb_dlink_list writeq;
uint8_t shutdown;
uint8_t dead;
};
static rb_dlink_list wsock_daemons;
static inline uint32_t
buf_to_uint32(char *buf)
{
uint32_t x;
memcpy(&x, buf, sizeof(x));
return x;
}
static inline void
uint32_to_buf(char *buf, uint32_t x)
{
memcpy(buf, &x, sizeof(x));
return;
}
static ws_ctl_t *
allocate_ws_daemon(rb_fde_t * F, rb_fde_t * P, int pid)
{
ws_ctl_t *ctl;
if(F == NULL || pid < 0)
return NULL;
ctl = (ws_ctl_t *)rb_malloc(sizeof(ws_ctl_t));
ctl->F = F;
ctl->P = P;
ctl->pid = pid;
wsockd_count++;
rb_dlinkAdd(ctl, &ctl->node, &wsock_daemons);
return ctl;
}
static void
free_ws_daemon(ws_ctl_t * ctl)
{
rb_dlink_node *ptr;
ws_ctl_buf_t *ctl_buf;
int x;
if(ctl->cli_count)
return;
RB_DLINK_FOREACH(ptr, ctl->readq.head)
{
ctl_buf = (ws_ctl_buf_t *)ptr->data;
for(x = 0; x < ctl_buf->nfds; x++)
rb_close(ctl_buf->F[x]);
rb_free(ctl_buf->buf);
rb_free(ctl_buf);
}
RB_DLINK_FOREACH(ptr, ctl->writeq.head)
{
ctl_buf = (ws_ctl_buf_t *)ptr->data;
for(x = 0; x < ctl_buf->nfds; x++)
rb_close(ctl_buf->F[x]);
rb_free(ctl_buf->buf);
rb_free(ctl_buf);
}
rb_close(ctl->F);
rb_close(ctl->P);
rb_dlinkDelete(&ctl->node, &wsock_daemons);
rb_free(ctl);
}
static char *wsockd_path;
static int wsockd_spin_count = 0;
static time_t last_spin;
static int wsockd_wait = 0;
void
restart_wsockd(void)
{
rb_dlink_node *ptr, *next;
ws_ctl_t *ctl;
RB_DLINK_FOREACH_SAFE(ptr, next, wsock_daemons.head)
{
ctl = (ws_ctl_t *)ptr->data;
if(ctl->dead)
continue;
if(ctl->shutdown)
continue;
ctl->shutdown = 1;
wsockd_count--;
if(!ctl->cli_count)
{
rb_kill(ctl->pid, SIGKILL);
free_ws_daemon(ctl);
}
}
start_wsockd(ServerInfo.wsockd_count);
}
#if 0
static void
ws_killall(void)
{
rb_dlink_node *ptr, *next;
ws_ctl_t *ctl;
RB_DLINK_FOREACH_SAFE(ptr, next, wsock_daemons.head)
{
ctl = ptr->data;
if(ctl->dead)
continue;
ctl->dead = 1;
if(!ctl->shutdown)
wsockd_count--;
rb_kill(ctl->pid, SIGKILL);
if(!ctl->cli_count)
free_ws_daemon(ctl);
}
}
#endif
static void
ws_dead(ws_ctl_t * ctl)
{
if(ctl->dead)
return;
ctl->dead = 1;
rb_kill(ctl->pid, SIGKILL); /* make sure the process is really gone */
if(!ctl->shutdown)
{
wsockd_count--;
ilog(L_MAIN, "wsockd helper died - attempting to restart");
sendto_realops_snomask(sno::GENERAL, L_ALL, "wsockd helper died - attempting to restart");
start_wsockd(1);
}
}
static void
ws_do_pipe(rb_fde_t * F, void *data)
{
int retlen;
ws_ctl_t *ctl = (ws_ctl_t *)data;
retlen = rb_write(F, "0", 1);
if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno)))
{
ws_dead(ctl);
return;
}
rb_setselect(F, RB_SELECT_READ, ws_do_pipe, data);
}
static void
restart_wsockd_event(void *unused)
{
wsockd_spin_count = 0;
last_spin = 0;
wsockd_wait = 0;
if(ServerInfo.wsockd_count > get_wsockd_count())
{
int start = ServerInfo.wsockd_count - get_wsockd_count();
ilog(L_MAIN, "Attempting to restart wsockd processes");
sendto_realops_snomask(sno::GENERAL, L_ALL, "Attempting to restart wsockd processes");
start_wsockd(start);
}
}
int
start_wsockd(int count)
{
rb_fde_t *F1, *F2;
rb_fde_t *P1, *P2;
#ifdef _WIN32
const char *suffix = ".exe";
#else
const char *suffix = "";
#endif
char fullpath[PATH_MAX + 1];
char fdarg[6];
const char *parv[2];
char buf[128];
char s_pid[10];
pid_t pid;
int started = 0, i;
if(wsockd_wait)
return 0;
if(wsockd_spin_count > 20 && (rb_current_time() - last_spin < 5))
{
ilog(L_MAIN, "wsockd helper is spinning - will attempt to restart in 1 minute");
sendto_realops_snomask(sno::GENERAL, L_ALL,
"wsockd helper is spinning - will attempt to restart in 1 minute");
rb_event_add("restart_wsockd_event", restart_wsockd_event, NULL, 60);
wsockd_wait = 1;
return 0;
}
wsockd_spin_count++;
last_spin = rb_current_time();
if(wsockd_path == NULL)
{
snprintf(fullpath, sizeof(fullpath), "%s%cwsockd%s", path::get(path::LIBEXEC), RB_PATH_SEPARATOR, suffix);
if(access(fullpath, X_OK) == -1)
{
snprintf(fullpath, sizeof(fullpath), "%s%cbin%cwsockd%s",
ConfigFileEntry.dpath, RB_PATH_SEPARATOR, RB_PATH_SEPARATOR, suffix);
if(access(fullpath, X_OK) == -1)
{
ilog(L_MAIN,
"Unable to execute wsockd%s in %s or %s/bin",
suffix, path::get(path::LIBEXEC), ConfigFileEntry.dpath);
return 0;
}
}
wsockd_path = rb_strdup(fullpath);
}
rb_strlcpy(buf, "-ircd wsockd daemon", sizeof(buf));
parv[0] = buf;
parv[1] = NULL;
for(i = 0; i < count; i++)
{
ws_ctl_t *ctl;
if(rb_socketpair(AF_UNIX, SOCK_DGRAM, 0, &F1, &F2, "wsockd handle passing socket") == -1)
{
ilog(L_MAIN, "Unable to create wsockd - rb_socketpair failed: %s", strerror(errno));
return started;
}
rb_set_buffers(F1, READBUF_SIZE);
rb_set_buffers(F2, READBUF_SIZE);
snprintf(fdarg, sizeof(fdarg), "%d", rb_get_fd(F2));
rb_setenv("CTL_FD", fdarg, 1);
if(rb_pipe(&P1, &P2, "wsockd pipe") == -1)
{
ilog(L_MAIN, "Unable to create wsockd - rb_pipe failed: %s", strerror(errno));
return started;
}
snprintf(fdarg, sizeof(fdarg), "%d", rb_get_fd(P1));
rb_setenv("CTL_PIPE", fdarg, 1);
snprintf(s_pid, sizeof(s_pid), "%d", (int)getpid());
rb_setenv("CTL_PPID", s_pid, 1);
#ifdef _WIN32
SetHandleInformation((HANDLE) rb_get_fd(F2), HANDLE_FLAG_INHERIT, 1);
SetHandleInformation((HANDLE) rb_get_fd(P1), HANDLE_FLAG_INHERIT, 1);
#endif
pid = rb_spawn_process(wsockd_path, (const char **) parv);
if(pid == -1)
{
ilog(L_MAIN, "Unable to create wsockd: %s\n", strerror(errno));
rb_close(F1);
rb_close(F2);
rb_close(P1);
rb_close(P2);
return started;
}
started++;
rb_close(F2);
rb_close(P1);
ctl = allocate_ws_daemon(F1, P2, pid);
ws_read_ctl(ctl->F, ctl);
ws_do_pipe(P2, ctl);
}
return started;
}
static void
ws_process_dead_fd(ws_ctl_t * ctl, ws_ctl_buf_t * ctl_buf)
{
client::client *client_p;
char reason[256];
uint32_t fd;
if(ctl_buf->buflen < 6)
return; /* bogus message..drop it.. XXX should warn here */
fd = buf_to_uint32(&ctl_buf->buf[1]);
rb_strlcpy(reason, &ctl_buf->buf[5], sizeof(reason));
client_p = find_cli_connid_hash(fd);
if(client_p == NULL)
return;
if(is_any_server(*client_p) || is_registered(*client_p))
{
/* read any last moment ERROR, QUIT or the like -- jilles */
if (!strcmp(reason, "Remote host closed the connection"))
read_packet(client_p->localClient->F, client_p);
if (is_any_dead(*client_p))
return;
}
exit_client(client_p, client_p, &me, reason);
}
static void
ws_process_cmd_recv(ws_ctl_t * ctl)
{
rb_dlink_node *ptr, *next;
ws_ctl_buf_t *ctl_buf;
unsigned long len;
if(ctl->dead)
return;
RB_DLINK_FOREACH_SAFE(ptr, next, ctl->readq.head)
{
ctl_buf = (ws_ctl_buf_t *)ptr->data;
switch (*ctl_buf->buf)
{
case 'D':
ws_process_dead_fd(ctl, ctl_buf);
break;
default:
ilog(L_MAIN, "Received invalid command from wsockd: %s", ctl_buf->buf);
sendto_realops_snomask(sno::GENERAL, L_ALL, "Received invalid command from wsockd");
break;
}
rb_dlinkDelete(ptr, &ctl->readq);
rb_free(ctl_buf->buf);
rb_free(ctl_buf);
}
}
static void
ws_read_ctl(rb_fde_t * F, void *data)
{
ws_ctl_buf_t *ctl_buf;
ws_ctl_t *ctl = (ws_ctl_t *)data;
int retlen;
if(ctl->dead)
return;
do
{
ctl_buf = (ws_ctl_buf_t *)rb_malloc(sizeof(ws_ctl_buf_t));
ctl_buf->buf = (char *)rb_malloc(READSIZE);
retlen = rb_recv_fd_buf(ctl->F, ctl_buf->buf, READSIZE, ctl_buf->F, 4);
ctl_buf->buflen = retlen;
if(retlen <= 0)
{
rb_free(ctl_buf->buf);
rb_free(ctl_buf);
}
else
rb_dlinkAddTail(ctl_buf, &ctl_buf->node, &ctl->readq);
}
while(retlen > 0);
if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno)))
{
ws_dead(ctl);
return;
}
ws_process_cmd_recv(ctl);
rb_setselect(ctl->F, RB_SELECT_READ, ws_read_ctl, ctl);
}
static ws_ctl_t *
which_wsockd(void)
{
ws_ctl_t *ctl, *lowest = NULL;
rb_dlink_node *ptr;
RB_DLINK_FOREACH(ptr, wsock_daemons.head)
{
ctl = (ws_ctl_t *)ptr->data;
if(ctl->dead)
continue;
if(ctl->shutdown)
continue;
if(lowest == NULL)
{
lowest = ctl;
continue;
}
if(ctl->cli_count < lowest->cli_count)
lowest = ctl;
}
return (lowest);
}
static void
ws_write_ctl(rb_fde_t * F, void *data)
{
ws_ctl_t *ctl = (ws_ctl_t *)data;
ws_ctl_buf_t *ctl_buf;
rb_dlink_node *ptr, *next;
int retlen, x;
if(ctl->dead)
return;
RB_DLINK_FOREACH_SAFE(ptr, next, ctl->writeq.head)
{
ctl_buf = (ws_ctl_buf_t *)ptr->data;
/* in theory unix sock_dgram shouldn't ever short write this.. */
retlen = rb_send_fd_buf(ctl->F, ctl_buf->F, ctl_buf->nfds, ctl_buf->buf, ctl_buf->buflen, ctl->pid);
if(retlen > 0)
{
rb_dlinkDelete(ptr, &ctl->writeq);
for(x = 0; x < ctl_buf->nfds; x++)
rb_close(ctl_buf->F[x]);
rb_free(ctl_buf->buf);
rb_free(ctl_buf);
}
if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno)))
{
ws_dead(ctl);
return;
}
else
{
rb_setselect(ctl->F, RB_SELECT_WRITE, ws_write_ctl, ctl);
}
}
}
static void
ws_cmd_write_queue(ws_ctl_t * ctl, rb_fde_t ** F, int count, const void *buf, size_t buflen)
{
ws_ctl_buf_t *ctl_buf;
int x;
/* don't bother */
if(ctl->dead)
return;
ctl_buf = (ws_ctl_buf_t *)rb_malloc(sizeof(ws_ctl_buf_t));
ctl_buf->buf = (char *)rb_malloc(buflen);
memcpy(ctl_buf->buf, buf, buflen);
ctl_buf->buflen = buflen;
for(x = 0; x < count && x < MAXPASSFD; x++)
{
ctl_buf->F[x] = F[x];
}
ctl_buf->nfds = count;
rb_dlinkAddTail(ctl_buf, &ctl_buf->node, &ctl->writeq);
ws_write_ctl(ctl->F, ctl);
}
ws_ctl_t *
start_wsockd_accept(rb_fde_t * sslF, rb_fde_t * plainF, uint32_t id)
{
rb_fde_t *F[2];
ws_ctl_t *ctl;
char buf[5];
F[0] = sslF;
F[1] = plainF;
buf[0] = 'A';
uint32_to_buf(&buf[1], id);
ctl = which_wsockd();
if(!ctl)
return NULL;
ctl->cli_count++;
ws_cmd_write_queue(ctl, F, 2, buf, sizeof(buf));
return ctl;
}
void
wsockd_decrement_clicount(ws_ctl_t * ctl)
{
if(ctl == NULL)
return;
ctl->cli_count--;
if(ctl->shutdown && !ctl->cli_count)
{
ctl->dead = 1;
rb_kill(ctl->pid, SIGKILL);
}
if(ctl->dead && !ctl->cli_count)
{
free_ws_daemon(ctl);
}
}
static void
cleanup_dead_ws(void *unused)
{
rb_dlink_node *ptr, *next;
ws_ctl_t *ctl;
RB_DLINK_FOREACH_SAFE(ptr, next, wsock_daemons.head)
{
ctl = (ws_ctl_t *)ptr->data;
if(ctl->dead && !ctl->cli_count)
{
free_ws_daemon(ctl);
}
}
}
int
get_wsockd_count(void)
{
return wsockd_count;
}
void
wsockd_foreach_info(void (*func)(void *data, pid_t pid, int cli_count, enum wsockd_status status), void *data)
{
rb_dlink_node *ptr, *next;
ws_ctl_t *ctl;
RB_DLINK_FOREACH_SAFE(ptr, next, wsock_daemons.head)
{
ctl = (ws_ctl_t *)ptr->data;
func(data, ctl->pid, ctl->cli_count,
ctl->dead ? WSOCKD_DEAD :
(ctl->shutdown ? WSOCKD_SHUTDOWN : WSOCKD_ACTIVE));
}
}
void
init_wsockd(void)
{
rb_event_addish("cleanup_dead_ws", cleanup_dead_ws, NULL, 60);
}
}