mirror of
https://github.com/matrix-construct/construct
synced 2024-05-21 04:13:47 +02:00
What is the Matrix? Control.
This commit is contained in:
parent
8ee7073e5e
commit
b592b69b86
|
@ -1,17 +1,10 @@
|
|||
AUTOMAKE_OPTIONS = foreign
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
SUBDIRS = include/rb
|
||||
SUBDIRS += include/ircd
|
||||
SUBDIRS += rb
|
||||
SUBDIRS = include/ircd
|
||||
SUBDIRS += ircd
|
||||
SUBDIRS += charybdis
|
||||
#SUBDIRS += authd
|
||||
#SUBDIRS += bandb
|
||||
#SUBDIRS += ssld
|
||||
#SUBDIRS += wsockd
|
||||
SUBDIRS += modules
|
||||
#SUBDIRS += extensions
|
||||
SUBDIRS += tools
|
||||
SUBDIRS += help
|
||||
SUBDIRS += doc
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/include \
|
||||
@BOOST_CPPFLAGS@
|
||||
|
||||
AM_LDFLAGS = \
|
||||
-L$(top_srcdir)/ircd \
|
||||
-L$(top_srcdir)/rb \
|
||||
@BOOST_LDFLAGS@
|
||||
|
||||
|
||||
bin_PROGRAMS = authd
|
||||
|
||||
authd_LDADD = \
|
||||
$(top_srcdir)/ircd/libircd.la \
|
||||
$(top_srcdir)/rb/librb.la \
|
||||
@BOOST_LIBS@
|
||||
|
||||
authd_SOURCES = \
|
||||
authd.cc \
|
||||
dns.cc \
|
||||
getaddrinfo.cc \
|
||||
getnameinfo.cc \
|
||||
notice.cc \
|
||||
provider.cc \
|
||||
res.cc \
|
||||
reslib.cc \
|
||||
reslist.cc \
|
||||
providers/blacklist.cc \
|
||||
providers/ident.cc \
|
||||
providers/rdns.cc \
|
||||
providers/opm.cc
|
||||
|
||||
|
||||
mrproper-local:
|
||||
rm -rf providers/.deps
|
||||
rm -f providers/.dirstamp
|
231
authd/authd.cc
231
authd/authd.cc
|
@ -1,231 +0,0 @@
|
|||
/* authd/authd.c - main code for authd
|
||||
* Copyright (c) 2016 William Pitcock <nenolod@dereferenced.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "authd.h"
|
||||
#include "dns.h"
|
||||
#include "provider.h"
|
||||
#include "notice.h"
|
||||
|
||||
#define MAXPARA 10
|
||||
|
||||
using namespace ircd::defaults;
|
||||
|
||||
static void error_cb(rb_helper *helper) __attribute__((noreturn));
|
||||
static void handle_reload(int parc, char *parv[]);
|
||||
static void handle_stat(int parc, char *parv[]);
|
||||
static void handle_options(int parc, char *parv[]);
|
||||
|
||||
rb_helper *authd_helper = NULL;
|
||||
std::array<authd_cmd_handler, 256> authd_cmd_handlers =
|
||||
[]{
|
||||
std::array<authd_cmd_handler, 256> ret;
|
||||
ret['C'] = handle_new_connection;
|
||||
ret['D'] = handle_resolve_dns;
|
||||
ret['E'] = handle_cancel_connection;
|
||||
ret['O'] = handle_options;
|
||||
ret['R'] = handle_reload;
|
||||
ret['S'] = handle_stat;
|
||||
return ret;
|
||||
}();
|
||||
|
||||
std::array<authd_stat_handler, 256> authd_stat_handlers =
|
||||
[]{
|
||||
std::array<authd_stat_handler, 256> ret;
|
||||
ret['D'] = enumerate_nameservers;
|
||||
return ret;
|
||||
}();
|
||||
|
||||
std::array<authd_reload_handler, 256> authd_reload_handlers =
|
||||
[]{
|
||||
std::array<authd_reload_handler, 256> ret;
|
||||
ret['D'] = reload_nameservers;
|
||||
return ret;
|
||||
}();
|
||||
|
||||
rb_dictionary *authd_option_handlers;
|
||||
|
||||
static void
|
||||
handle_stat(int parc, char *parv[])
|
||||
{
|
||||
authd_stat_handler handler;
|
||||
unsigned long long rid;
|
||||
|
||||
if(parc < 3)
|
||||
{
|
||||
warn_opers(L_CRIT, "BUG: handle_stat received too few parameters (at least 3 expected, got %d)", parc);
|
||||
return;
|
||||
}
|
||||
|
||||
if((rid = strtoull(parv[1], NULL, 16)) > UINT32_MAX)
|
||||
{
|
||||
warn_opers(L_CRIT, "BUG: handle_stat got a rid that was too large: %s", parv[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(handler = authd_stat_handlers[(unsigned char)parv[2][0]]))
|
||||
return;
|
||||
|
||||
handler((uint32_t)rid, parv[2][0]);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_options(int parc, char *parv[])
|
||||
{
|
||||
struct auth_opts_handler *handler;
|
||||
|
||||
if(parc < 2)
|
||||
{
|
||||
warn_opers(L_CRIT, "BUG: handle_options received too few parameters (at least 2 expected, got %d)", parc);
|
||||
return;
|
||||
}
|
||||
|
||||
if((handler = (auth_opts_handler *)rb_dictionary_retrieve(authd_option_handlers, parv[1])) == NULL)
|
||||
{
|
||||
warn_opers(L_CRIT, "BUG: handle_options got a bad option type %s", parv[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
if((parc - 2) < handler->min_parc)
|
||||
{
|
||||
warn_opers(L_CRIT, "BUG: handle_options received too few parameters (at least %d expected, got %d)", handler->min_parc, parc);
|
||||
return;
|
||||
}
|
||||
|
||||
handler->handler(parv[1], parc - 2, (const char **)&parv[2]);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_reload(int parc, char *parv[])
|
||||
{
|
||||
authd_reload_handler handler;
|
||||
|
||||
if(parc <= 2)
|
||||
{
|
||||
/* Reload all handlers */
|
||||
for(size_t i = 0; i < 256; i++)
|
||||
{
|
||||
if ((handler = authd_reload_handlers[(unsigned char) i]) != NULL)
|
||||
handler('\0');
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(handler = authd_reload_handlers[(unsigned char)parv[1][0]]))
|
||||
return;
|
||||
|
||||
handler(parv[1][0]);
|
||||
}
|
||||
|
||||
static void
|
||||
parse_request(rb_helper *helper)
|
||||
{
|
||||
static char *parv[MAXPARA + 1];
|
||||
static char readbuf[READBUF_SIZE];
|
||||
int parc;
|
||||
int len;
|
||||
authd_cmd_handler handler;
|
||||
|
||||
while((len = rb_helper_read(helper, readbuf, sizeof(readbuf))) > 0)
|
||||
{
|
||||
parc = rb_string_to_array(readbuf, parv, MAXPARA);
|
||||
|
||||
if(parc < 1)
|
||||
continue;
|
||||
|
||||
handler = authd_cmd_handlers[(unsigned char)parv[0][0]];
|
||||
if (handler != NULL)
|
||||
handler(parc, parv);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
error_cb(rb_helper *helper)
|
||||
{
|
||||
exit(EX_ERROR);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
static void
|
||||
dummy_handler(int sig)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
setup_signals(void)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
struct sigaction act;
|
||||
|
||||
act.sa_flags = 0;
|
||||
act.sa_handler = SIG_IGN;
|
||||
sigemptyset(&act.sa_mask);
|
||||
sigaddset(&act.sa_mask, SIGPIPE);
|
||||
sigaddset(&act.sa_mask, SIGALRM);
|
||||
#ifdef SIGTRAP
|
||||
sigaddset(&act.sa_mask, SIGTRAP);
|
||||
#endif
|
||||
|
||||
#ifdef SIGWINCH
|
||||
sigaddset(&act.sa_mask, SIGWINCH);
|
||||
sigaction(SIGWINCH, &act, 0);
|
||||
#endif
|
||||
sigaction(SIGPIPE, &act, 0);
|
||||
#ifdef SIGTRAP
|
||||
sigaction(SIGTRAP, &act, 0);
|
||||
#endif
|
||||
|
||||
act.sa_handler = dummy_handler;
|
||||
sigaction(SIGALRM, &act, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
setup_signals();
|
||||
|
||||
authd_helper = rb_helper_child(parse_request, error_cb, NULL, NULL, NULL, 256, 256, 256); /* XXX fix me */
|
||||
if(authd_helper == NULL)
|
||||
{
|
||||
fprintf(stderr, "authd is not meant to be invoked by end users\n");
|
||||
exit(EX_ERROR);
|
||||
}
|
||||
|
||||
rb_set_time();
|
||||
setup_signals();
|
||||
|
||||
authd_option_handlers = rb_dictionary_create("authd options handlers", reinterpret_cast<int (*)(const void *, const void *)>(rb_strcasecmp));
|
||||
|
||||
init_resolver();
|
||||
init_providers();
|
||||
rb_init_prng(NULL, RB_PRNG_DEFAULT);
|
||||
|
||||
rb_helper_loop(authd_helper, 0);
|
||||
|
||||
/*
|
||||
* XXX this function will never be called from here -- is it necessary?
|
||||
*/
|
||||
destroy_providers();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
/* authd/dns.h - header for authd DNS functions
|
||||
* Copyright (c) 2016 William Pitcock <nenolod@dereferenced.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _AUTHD_H
|
||||
#define _AUTHD_H
|
||||
|
||||
#include <ircd/stdinc.h>
|
||||
|
||||
typedef enum exit_reasons
|
||||
{
|
||||
EX_ERROR = 1,
|
||||
EX_DNS_ERROR = 2,
|
||||
EX_PROVIDER_ERROR = 3,
|
||||
} exit_reasons;
|
||||
|
||||
typedef void (*provider_opts_handler_t)(const char *, int, const char **);
|
||||
|
||||
struct auth_opts_handler
|
||||
{
|
||||
const char *option;
|
||||
int min_parc;
|
||||
provider_opts_handler_t handler;
|
||||
};
|
||||
|
||||
extern rb_helper *authd_helper;
|
||||
|
||||
typedef void (*authd_cmd_handler)(int parc, char *parv[]);
|
||||
typedef void (*authd_stat_handler)(uint32_t rid, const char letter);
|
||||
typedef void (*authd_reload_handler)(const char letter);
|
||||
|
||||
extern std::array<authd_cmd_handler, 256> authd_cmd_handlers;
|
||||
extern std::array<authd_stat_handler, 256> authd_stat_handlers;
|
||||
extern std::array<authd_reload_handler, 256> authd_reload_handlers;
|
||||
|
||||
extern rb_dictionary *authd_option_handlers;
|
||||
|
||||
#endif
|
318
authd/dns.cc
318
authd/dns.cc
|
@ -1,318 +0,0 @@
|
|||
/* authd/dns.c - authd DNS functions
|
||||
* Copyright (c) 2016 William Pitcock <nenolod@dereferenced.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "authd.h"
|
||||
#include "dns.h"
|
||||
#include "notice.h"
|
||||
#include "res.h"
|
||||
|
||||
using namespace ircd::defaults;
|
||||
|
||||
static void handle_lookup_ip_reply(void *data, struct DNSReply *reply);
|
||||
static void handle_lookup_hostname_reply(void *data, struct DNSReply *reply);
|
||||
|
||||
uint64_t query_count = 0;
|
||||
|
||||
/* A bit different from ircd... you just get a dns_query object.
|
||||
*
|
||||
* It gets freed whenever the res code gets back to us.
|
||||
*/
|
||||
struct dns_query *
|
||||
lookup_ip(const char *host, int aftype, DNSCB callback, void *data)
|
||||
{
|
||||
struct dns_query *query = (dns_query *)rb_malloc(sizeof(struct dns_query));
|
||||
int g_type;
|
||||
|
||||
if(aftype == AF_INET)
|
||||
{
|
||||
query->type = QUERY_A;
|
||||
g_type = T_A;
|
||||
}
|
||||
#ifdef RB_IPV6
|
||||
else if(aftype == AF_INET6)
|
||||
{
|
||||
query->type = QUERY_AAAA;
|
||||
g_type = T_AAAA;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
rb_free(query);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
query->id = query_count++;
|
||||
query->callback = callback;
|
||||
query->data = data;
|
||||
|
||||
query->query.ptr = query;
|
||||
query->query.callback = handle_lookup_ip_reply;
|
||||
|
||||
gethost_byname_type(host, &query->query, g_type);
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
/* See lookup_ip's comment */
|
||||
struct dns_query *
|
||||
lookup_hostname(const char *ip, DNSCB callback, void *data)
|
||||
{
|
||||
struct dns_query *query = (dns_query *)rb_malloc(sizeof(struct dns_query));
|
||||
int aftype;
|
||||
|
||||
if(!rb_inet_pton_sock(ip, (struct sockaddr *)&query->addr))
|
||||
{
|
||||
rb_free(query);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
aftype = GET_SS_FAMILY(&query->addr);
|
||||
|
||||
if(aftype == AF_INET)
|
||||
query->type = QUERY_PTR_A;
|
||||
#ifdef RB_IPV6
|
||||
else if(aftype == AF_INET6)
|
||||
query->type = QUERY_PTR_AAAA;
|
||||
#endif
|
||||
else
|
||||
{
|
||||
rb_free(query);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
query->id = query_count++;
|
||||
query->callback = callback;
|
||||
query->data = data;
|
||||
|
||||
query->query.ptr = query;
|
||||
query->query.callback = handle_lookup_hostname_reply;
|
||||
|
||||
gethost_byaddr(&query->addr, &query->query);
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
/* Cancel a pending query */
|
||||
void
|
||||
cancel_query(struct dns_query *query)
|
||||
{
|
||||
query->callback = NULL;
|
||||
query->data = NULL;
|
||||
}
|
||||
|
||||
/* Callback from gethost_byname_type */
|
||||
static void
|
||||
handle_lookup_ip_reply(void *data, struct DNSReply *reply)
|
||||
{
|
||||
struct dns_query *query = (dns_query *)data;
|
||||
char ip[HOSTIPLEN] = "*";
|
||||
|
||||
if(query == NULL)
|
||||
{
|
||||
/* Shouldn't happen */
|
||||
warn_opers(L_CRIT, "DNS: handle_lookup_ip_reply: query == NULL!");
|
||||
exit(EX_DNS_ERROR);
|
||||
}
|
||||
|
||||
if(reply == NULL)
|
||||
goto end;
|
||||
|
||||
switch(query->type)
|
||||
{
|
||||
case QUERY_A:
|
||||
if(GET_SS_FAMILY(&reply->addr) == AF_INET)
|
||||
rb_inet_ntop_sock((struct sockaddr *)&reply->addr, ip, sizeof(ip));
|
||||
break;
|
||||
#ifdef RB_IPV6
|
||||
case QUERY_AAAA:
|
||||
if(GET_SS_FAMILY(&reply->addr) == AF_INET6)
|
||||
{
|
||||
rb_inet_ntop_sock((struct sockaddr *)&reply->addr, ip, sizeof(ip));
|
||||
if(ip[0] == ':')
|
||||
{
|
||||
memmove(&ip[1], ip, strlen(ip));
|
||||
ip[0] = '0';
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
warn_opers(L_CRIT, "DNS: handle_lookup_ip_reply: unknown query type %d",
|
||||
query->type);
|
||||
exit(EX_DNS_ERROR);
|
||||
}
|
||||
|
||||
end:
|
||||
if(query->callback)
|
||||
query->callback(ip, ip[0] != '*', query->type, query->data);
|
||||
|
||||
rb_free(query);
|
||||
}
|
||||
|
||||
/* Callback from gethost_byaddr */
|
||||
static void
|
||||
handle_lookup_hostname_reply(void *data, struct DNSReply *reply)
|
||||
{
|
||||
struct dns_query *query = (dns_query *)data;
|
||||
char *hostname = NULL;
|
||||
|
||||
if(query == NULL)
|
||||
{
|
||||
/* Shouldn't happen */
|
||||
warn_opers(L_CRIT, "DNS: handle_lookup_hostname_reply: query == NULL!");
|
||||
exit(EX_DNS_ERROR);
|
||||
}
|
||||
|
||||
if(reply == NULL)
|
||||
goto end;
|
||||
|
||||
if(query->type == QUERY_PTR_A)
|
||||
{
|
||||
struct sockaddr_in *ip, *ip_fwd;
|
||||
ip = (struct sockaddr_in *) &query->addr;
|
||||
ip_fwd = (struct sockaddr_in *) &reply->addr;
|
||||
|
||||
if(ip->sin_addr.s_addr == ip_fwd->sin_addr.s_addr)
|
||||
hostname = reply->h_name;
|
||||
}
|
||||
#ifdef RB_IPV6
|
||||
else if(query->type == QUERY_PTR_AAAA)
|
||||
{
|
||||
struct sockaddr_in6 *ip, *ip_fwd;
|
||||
ip = (struct sockaddr_in6 *) &query->addr;
|
||||
ip_fwd = (struct sockaddr_in6 *) &reply->addr;
|
||||
|
||||
if(memcmp(&ip->sin6_addr, &ip_fwd->sin6_addr, sizeof(struct in6_addr)) == 0)
|
||||
hostname = reply->h_name;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
/* Shouldn't happen */
|
||||
warn_opers(L_CRIT, "DNS: handle_lookup_hostname_reply: unknown query type %d",
|
||||
query->type);
|
||||
exit(EX_DNS_ERROR);
|
||||
}
|
||||
end:
|
||||
if(query->callback)
|
||||
query->callback(hostname, hostname != NULL, query->type, query->data);
|
||||
|
||||
rb_free(query);
|
||||
}
|
||||
|
||||
static void
|
||||
submit_dns_answer(const char *reply, bool status, query_type type, void *data)
|
||||
{
|
||||
char *id = (char *)data;
|
||||
|
||||
if(!id || type == QUERY_INVALID)
|
||||
{
|
||||
warn_opers(L_CRIT, "DNS: submit_dns_answer gave us a bad query");
|
||||
exit(EX_DNS_ERROR);
|
||||
}
|
||||
|
||||
if(reply == NULL || status == false)
|
||||
{
|
||||
rb_helper_write(authd_helper, "E %s E %c *", id, type);
|
||||
rb_free(id);
|
||||
return;
|
||||
}
|
||||
|
||||
rb_helper_write(authd_helper, "E %s O %c %s", id, type, reply);
|
||||
rb_free(id);
|
||||
}
|
||||
|
||||
void
|
||||
handle_resolve_dns(int parc, char *parv[])
|
||||
{
|
||||
char *id = rb_strdup(parv[1]);
|
||||
char qtype = *parv[2];
|
||||
char *record = parv[3];
|
||||
int aftype = AF_INET;
|
||||
|
||||
switch(qtype)
|
||||
{
|
||||
#ifdef RB_IPV6
|
||||
case '6':
|
||||
aftype = AF_INET6;
|
||||
#endif
|
||||
case '4':
|
||||
if(!lookup_ip(record, aftype, submit_dns_answer, id))
|
||||
submit_dns_answer(NULL, false, query_type(qtype), NULL);
|
||||
break;
|
||||
#ifdef RB_IPV6
|
||||
case 'S':
|
||||
#endif
|
||||
case 'R':
|
||||
if(!lookup_hostname(record, submit_dns_answer, id))
|
||||
submit_dns_answer(NULL, false, query_type(qtype), NULL);
|
||||
break;
|
||||
default:
|
||||
warn_opers(L_CRIT, "DNS: handle_resolve_dns got an unknown query: %c", qtype);
|
||||
exit(EX_DNS_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
enumerate_nameservers(uint32_t rid, const char letter)
|
||||
{
|
||||
char buf[(HOSTIPLEN + 1) * IRCD_MAXNS];
|
||||
size_t s = 0;
|
||||
|
||||
if (!irc_nscount)
|
||||
{
|
||||
/* Shouldn't happen */
|
||||
warn_opers(L_CRIT, "DNS: no name servers!");
|
||||
stats_error(rid, letter, "NONAMESERVERS");
|
||||
exit(EX_DNS_ERROR);
|
||||
}
|
||||
|
||||
for(int i = 0; i < irc_nscount; i++)
|
||||
{
|
||||
char addr[HOSTIPLEN];
|
||||
size_t addrlen;
|
||||
|
||||
rb_inet_ntop_sock((struct sockaddr *)&irc_nsaddr_list[i], addr, sizeof(addr));
|
||||
|
||||
if (!addr[0])
|
||||
{
|
||||
/* Shouldn't happen */
|
||||
warn_opers(L_CRIT, "DNS: bad nameserver!");
|
||||
stats_error(rid, letter, "INVALIDNAMESERVER");
|
||||
exit(EX_DNS_ERROR);
|
||||
}
|
||||
|
||||
addrlen = strlen(addr) + 1;
|
||||
(void)snprintf(&buf[s], sizeof(buf) - s, "%s ", addr);
|
||||
s += addrlen;
|
||||
}
|
||||
|
||||
if(s > 0)
|
||||
buf[--s] = '\0';
|
||||
|
||||
stats_result(rid, letter, "%s", buf);
|
||||
}
|
||||
|
||||
void
|
||||
reload_nameservers(const char letter)
|
||||
{
|
||||
/* Not a whole lot to it */
|
||||
restart_resolver();
|
||||
}
|
61
authd/dns.h
61
authd/dns.h
|
@ -1,61 +0,0 @@
|
|||
/* authd/dns.h - header for authd DNS functions
|
||||
* Copyright (c) 2016 William Pitcock <nenolod@dereferenced.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _AUTHD_DNS_H
|
||||
#define _AUTHD_DNS_H
|
||||
|
||||
#define DNS_REQ_IDLEN 10
|
||||
|
||||
#include <ircd/stdinc.h>
|
||||
#include "res.h"
|
||||
#include "reslib.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
QUERY_INVALID = 0,
|
||||
QUERY_A = '4',
|
||||
QUERY_AAAA = '6',
|
||||
QUERY_PTR_A = 'R',
|
||||
QUERY_PTR_AAAA = 'S',
|
||||
} query_type;
|
||||
|
||||
/* Similar to that in ircd */
|
||||
typedef void (*DNSCB)(const char *res, bool status, query_type type, void *data);
|
||||
|
||||
struct dns_query
|
||||
{
|
||||
struct DNSQuery query;
|
||||
query_type type;
|
||||
struct rb_sockaddr_storage addr;
|
||||
uint64_t id;
|
||||
|
||||
DNSCB callback;
|
||||
void *data;
|
||||
};
|
||||
|
||||
extern struct dns_query *lookup_hostname(const char *ip, DNSCB callback, void *data);
|
||||
extern struct dns_query *lookup_ip(const char *host, int aftype, DNSCB callback, void *data);
|
||||
extern void cancel_query(struct dns_query *query);
|
||||
|
||||
extern void handle_resolve_dns(int parc, char *parv[]);
|
||||
extern void enumerate_nameservers(uint32_t rid, const char letter);
|
||||
extern void reload_nameservers(const char letter);
|
||||
|
||||
#endif
|
|
@ -1,617 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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. Neither the name of the project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``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 PROJECT OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <rb/rb.h>
|
||||
#include <ircd/stdinc.h>
|
||||
#include "getaddrinfo.h"
|
||||
|
||||
static const char in_addrany[] = { 0, 0, 0, 0 };
|
||||
static const char in_loopback[] = { 127, 0, 0, 1 };
|
||||
static const char in6_addrany[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
static const char in6_loopback[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
|
||||
};
|
||||
|
||||
static const struct afd {
|
||||
int a_af;
|
||||
int a_addrlen;
|
||||
int a_socklen;
|
||||
int a_off;
|
||||
const char *a_addrany;
|
||||
const char *a_loopback;
|
||||
int a_scoped;
|
||||
} afdl [] = {
|
||||
#define N_INET6 0
|
||||
#ifdef IPV6
|
||||
{PF_INET6, sizeof(struct in6_addr),
|
||||
sizeof(struct sockaddr_in6),
|
||||
offsetof(struct sockaddr_in6, sin6_addr),
|
||||
in6_addrany, in6_loopback, 1},
|
||||
#endif
|
||||
#define N_INET 1
|
||||
{PF_INET, sizeof(struct in_addr),
|
||||
sizeof(struct sockaddr_in),
|
||||
offsetof(struct sockaddr_in, sin_addr),
|
||||
in_addrany, in_loopback, 0},
|
||||
{0, 0, 0, 0, NULL, NULL, 0},
|
||||
};
|
||||
|
||||
struct explore {
|
||||
int e_af;
|
||||
int e_socktype;
|
||||
int e_protocol;
|
||||
const char *e_protostr;
|
||||
int e_wild;
|
||||
#define WILD_AF(ex) ((ex)->e_wild & 0x01)
|
||||
#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02)
|
||||
#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04)
|
||||
};
|
||||
|
||||
static const struct explore explore[] = {
|
||||
#ifdef IPV6
|
||||
{ PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
|
||||
{ PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
|
||||
{ PF_INET6, SOCK_RAW, ANY, NULL, 0x05 },
|
||||
#endif
|
||||
{ PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
|
||||
{ PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
|
||||
{ PF_INET, SOCK_RAW, ANY, NULL, 0x05 },
|
||||
{ PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
|
||||
{ PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
|
||||
{ PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 },
|
||||
{ -1, 0, 0, NULL, 0 },
|
||||
};
|
||||
|
||||
#define PTON_MAX 16
|
||||
|
||||
static bool str_isnumber(const char *);
|
||||
static int explore_null(const struct rb_addrinfo *,
|
||||
const char *, struct rb_addrinfo **);
|
||||
static int explore_numeric(const struct rb_addrinfo *, const char *,
|
||||
const char *, struct rb_addrinfo **);
|
||||
static struct rb_addrinfo *get_ai(const struct rb_addrinfo *,
|
||||
const struct afd *, const char *);
|
||||
static int get_portmatch(const struct rb_addrinfo *, const char *);
|
||||
static int get_port(struct rb_addrinfo *, const char *, int);
|
||||
static const struct afd *find_afd(int);
|
||||
#if 0
|
||||
/* We will need this should we ever want gai_strerror() */
|
||||
static char *ai_errlist[] = {
|
||||
"Success",
|
||||
"Address family for hostname not supported", /* EAI_ADDRFAMILY */
|
||||
"Temporary failure in name resolution", /* EAI_AGAIN */
|
||||
"Invalid value for ai_flags", /* EAI_BADFLAGS */
|
||||
"Non-recoverable failure in name resolution", /* EAI_FAIL */
|
||||
"ai_family not supported", /* EAI_FAMILY */
|
||||
"Memory allocation failure", /* EAI_MEMORY */
|
||||
"No address associated with hostname", /* EAI_NODATA */
|
||||
"hostname nor servname provided, or not known", /* EAI_NONAME */
|
||||
"servname not supported for ai_socktype", /* EAI_SERVICE */
|
||||
"ai_socktype not supported", /* EAI_SOCKTYPE */
|
||||
"System error returned in errno", /* EAI_SYSTEM */
|
||||
"Invalid value for hints", /* EAI_BADHINTS */
|
||||
"Resolved protocol is unknown", /* EAI_PROTOCOL */
|
||||
"Unknown error", /* EAI_MAX */
|
||||
};
|
||||
#endif
|
||||
/* XXX macros that make external reference is BAD. */
|
||||
|
||||
#define GET_AI(ai, afd, addr) \
|
||||
do { \
|
||||
/* external reference: pai, error, and label free */ \
|
||||
(ai) = get_ai(pai, (afd), (addr)); \
|
||||
if ((ai) == NULL) { \
|
||||
error = EAI_MEMORY; \
|
||||
goto free; \
|
||||
} \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define GET_PORT(ai, serv) \
|
||||
do { \
|
||||
/* external reference: error and label free */ \
|
||||
error = get_port((ai), (serv), 0); \
|
||||
if (error != 0) \
|
||||
goto free; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define ERR(err) \
|
||||
do { \
|
||||
/* external reference: error, and label bad */ \
|
||||
error = (err); \
|
||||
goto bad; \
|
||||
/*NOTREACHED*/ \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define MATCH_FAMILY(x, y, w) \
|
||||
((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC)))
|
||||
#define MATCH(x, y, w) \
|
||||
((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY)))
|
||||
|
||||
#if 0
|
||||
/* We will need this should we ever want gai_strerror() */
|
||||
char *
|
||||
gai_strerror(int ecode)
|
||||
{
|
||||
if (ecode < 0 || ecode > EAI_MAX)
|
||||
ecode = EAI_MAX;
|
||||
return ai_errlist[ecode];
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
rb_freeaddrinfo(struct rb_addrinfo *ai)
|
||||
{
|
||||
struct rb_addrinfo *next;
|
||||
|
||||
do {
|
||||
next = ai->ai_next;
|
||||
if (ai->ai_canonname)
|
||||
rb_free(ai->ai_canonname);
|
||||
/* no need to free(ai->ai_addr) */
|
||||
rb_free(ai);
|
||||
ai = next;
|
||||
} while (ai);
|
||||
}
|
||||
|
||||
static bool
|
||||
str_isnumber(const char *p)
|
||||
{
|
||||
char *ep;
|
||||
|
||||
if (*p == '\0')
|
||||
return false;
|
||||
|
||||
ep = NULL;
|
||||
errno = 0;
|
||||
(void)strtoul(p, &ep, 10);
|
||||
if (errno == 0 && ep && *ep == '\0')
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
int
|
||||
rb_getaddrinfo(const char *hostname, const char *servname,
|
||||
const struct rb_addrinfo *hints, struct rb_addrinfo **res)
|
||||
{
|
||||
struct rb_addrinfo sentinel;
|
||||
struct rb_addrinfo *cur;
|
||||
int error = 0;
|
||||
struct rb_addrinfo ai;
|
||||
struct rb_addrinfo ai0;
|
||||
struct rb_addrinfo *pai;
|
||||
const struct explore *ex;
|
||||
|
||||
memset(&sentinel, 0, sizeof(sentinel));
|
||||
cur = &sentinel;
|
||||
pai = &ai;
|
||||
pai->ai_flags = 0;
|
||||
pai->ai_family = PF_UNSPEC;
|
||||
pai->ai_socktype = ANY;
|
||||
pai->ai_protocol = ANY;
|
||||
pai->ai_addrlen = 0;
|
||||
pai->ai_canonname = NULL;
|
||||
pai->ai_addr = NULL;
|
||||
pai->ai_next = NULL;
|
||||
|
||||
if (hostname == NULL && servname == NULL)
|
||||
return EAI_NONAME;
|
||||
if (hints) {
|
||||
/* error check for hints */
|
||||
if (hints->ai_addrlen || hints->ai_canonname ||
|
||||
hints->ai_addr || hints->ai_next)
|
||||
ERR(EAI_BADHINTS); /* xxx */
|
||||
if (hints->ai_flags & ~AI_MASK)
|
||||
ERR(EAI_BADFLAGS);
|
||||
switch (hints->ai_family) {
|
||||
case PF_UNSPEC:
|
||||
case PF_INET:
|
||||
#ifdef IPV6
|
||||
case PF_INET6:
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
ERR(EAI_FAMILY);
|
||||
}
|
||||
memcpy(pai, hints, sizeof(*pai));
|
||||
|
||||
/*
|
||||
* if both socktype/protocol are specified, check if they
|
||||
* are meaningful combination.
|
||||
*/
|
||||
if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
|
||||
for (ex = explore; ex->e_af >= 0; ex++) {
|
||||
if (pai->ai_family != ex->e_af)
|
||||
continue;
|
||||
if (ex->e_socktype == ANY)
|
||||
continue;
|
||||
if (ex->e_protocol == ANY)
|
||||
continue;
|
||||
if (pai->ai_socktype == ex->e_socktype &&
|
||||
pai->ai_protocol != ex->e_protocol) {
|
||||
ERR(EAI_BADHINTS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* check for special cases. (1) numeric servname is disallowed if
|
||||
* socktype/protocol are left unspecified. (2) servname is disallowed
|
||||
* for raw and other inet{,6} sockets.
|
||||
*/
|
||||
if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
|
||||
#ifdef IPV6
|
||||
|| MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
|
||||
#endif
|
||||
) {
|
||||
ai0 = *pai; /* backup *pai */
|
||||
|
||||
if (pai->ai_family == PF_UNSPEC) {
|
||||
#ifdef IPV6
|
||||
pai->ai_family = PF_INET6;
|
||||
#else
|
||||
pai->ai_family = PF_INET;
|
||||
#endif
|
||||
}
|
||||
error = get_portmatch(pai, servname);
|
||||
if (error)
|
||||
ERR(error);
|
||||
|
||||
*pai = ai0;
|
||||
}
|
||||
|
||||
ai0 = *pai;
|
||||
|
||||
/* NULL hostname, or numeric hostname */
|
||||
for (ex = explore; ex->e_af >= 0; ex++) {
|
||||
*pai = ai0;
|
||||
|
||||
/* PF_UNSPEC entries are prepared for DNS queries only */
|
||||
if (ex->e_af == PF_UNSPEC)
|
||||
continue;
|
||||
|
||||
if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
|
||||
continue;
|
||||
if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
|
||||
continue;
|
||||
if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
|
||||
continue;
|
||||
|
||||
if (pai->ai_family == PF_UNSPEC)
|
||||
pai->ai_family = ex->e_af;
|
||||
if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
|
||||
pai->ai_socktype = ex->e_socktype;
|
||||
if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
|
||||
pai->ai_protocol = ex->e_protocol;
|
||||
|
||||
if (hostname == NULL)
|
||||
error = explore_null(pai, servname, &cur->ai_next);
|
||||
else
|
||||
error = explore_numeric(pai, hostname, servname, &cur->ai_next);
|
||||
|
||||
if (error)
|
||||
goto free;
|
||||
|
||||
while (cur && cur->ai_next)
|
||||
cur = cur->ai_next;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* If numreic representation of AF1 can be interpreted as FQDN
|
||||
* representation of AF2, we need to think again about the code below.
|
||||
*/
|
||||
if (sentinel.ai_next)
|
||||
goto good;
|
||||
|
||||
if (pai->ai_flags & AI_NUMERICHOST)
|
||||
ERR(EAI_NONAME);
|
||||
if (hostname == NULL)
|
||||
ERR(EAI_NODATA);
|
||||
|
||||
/* XXX */
|
||||
if (sentinel.ai_next)
|
||||
error = 0;
|
||||
|
||||
if (error)
|
||||
goto free;
|
||||
if (error == 0) {
|
||||
if (sentinel.ai_next) {
|
||||
good:
|
||||
*res = sentinel.ai_next;
|
||||
return SUCCESS;
|
||||
} else
|
||||
error = EAI_FAIL;
|
||||
}
|
||||
free:
|
||||
bad:
|
||||
if (sentinel.ai_next)
|
||||
rb_freeaddrinfo(sentinel.ai_next);
|
||||
*res = NULL;
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* hostname == NULL.
|
||||
* passive socket -> anyaddr (0.0.0.0 or ::)
|
||||
* non-passive socket -> localhost (127.0.0.1 or ::1)
|
||||
*/
|
||||
static int
|
||||
explore_null(const struct rb_addrinfo *pai, const char *servname, struct rb_addrinfo **res)
|
||||
{
|
||||
int s;
|
||||
const struct afd *afd;
|
||||
struct rb_addrinfo *cur;
|
||||
struct rb_addrinfo sentinel;
|
||||
int error;
|
||||
|
||||
*res = NULL;
|
||||
sentinel.ai_next = NULL;
|
||||
cur = &sentinel;
|
||||
|
||||
/*
|
||||
* filter out AFs that are not supported by the kernel
|
||||
* XXX errno?
|
||||
*/
|
||||
s = socket(pai->ai_family, SOCK_DGRAM, 0);
|
||||
if (s < 0) {
|
||||
#ifdef _WIN32
|
||||
errno = WSAGetLastError();
|
||||
#endif
|
||||
if (errno != EMFILE)
|
||||
return 0;
|
||||
} else
|
||||
#ifdef _WIN32
|
||||
closesocket(s);
|
||||
#else
|
||||
close(s);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* if the servname does not match socktype/protocol, ignore it.
|
||||
*/
|
||||
if (get_portmatch(pai, servname) != 0)
|
||||
return 0;
|
||||
|
||||
afd = find_afd(pai->ai_family);
|
||||
if (afd == NULL)
|
||||
return 0;
|
||||
|
||||
if (pai->ai_flags & AI_PASSIVE) {
|
||||
GET_AI(cur->ai_next, afd, afd->a_addrany);
|
||||
GET_PORT(cur->ai_next, servname);
|
||||
} else {
|
||||
GET_AI(cur->ai_next, afd, afd->a_loopback);
|
||||
GET_PORT(cur->ai_next, servname);
|
||||
}
|
||||
cur = cur->ai_next;
|
||||
|
||||
*res = sentinel.ai_next;
|
||||
return 0;
|
||||
|
||||
free:
|
||||
if (sentinel.ai_next)
|
||||
rb_freeaddrinfo(sentinel.ai_next);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* numeric hostname
|
||||
*/
|
||||
static int
|
||||
explore_numeric(const struct rb_addrinfo *pai, const char *hostname,
|
||||
const char *servname, struct rb_addrinfo **res)
|
||||
{
|
||||
const struct afd *afd;
|
||||
struct rb_addrinfo *cur;
|
||||
struct rb_addrinfo sentinel;
|
||||
int error;
|
||||
char pton[PTON_MAX];
|
||||
|
||||
*res = NULL;
|
||||
sentinel.ai_next = NULL;
|
||||
cur = &sentinel;
|
||||
|
||||
/*
|
||||
* if the servname does not match socktype/protocol, ignore it.
|
||||
*/
|
||||
if (get_portmatch(pai, servname) != 0)
|
||||
return 0;
|
||||
|
||||
afd = find_afd(pai->ai_family);
|
||||
if (afd == NULL)
|
||||
return 0;
|
||||
|
||||
switch (afd->a_af) {
|
||||
#if 0 /*X/Open spec*/
|
||||
case AF_INET:
|
||||
if (rb_inet_pton
|
||||
if (inet_aton(hostname, (struct in_addr *)pton) == 1) {
|
||||
if (pai->ai_family == afd->a_af ||
|
||||
pai->ai_family == PF_UNSPEC /*?*/) {
|
||||
GET_AI(cur->ai_next, afd, pton);
|
||||
GET_PORT(cur->ai_next, servname);
|
||||
while (cur && cur->ai_next)
|
||||
cur = cur->ai_next;
|
||||
} else
|
||||
ERR(EAI_FAMILY); /*xxx*/
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
if (rb_inet_pton(afd->a_af, hostname, pton) == 1) {
|
||||
if (pai->ai_family == afd->a_af ||
|
||||
pai->ai_family == PF_UNSPEC /*?*/) {
|
||||
GET_AI(cur->ai_next, afd, pton);
|
||||
GET_PORT(cur->ai_next, servname);
|
||||
while (cur && cur->ai_next)
|
||||
cur = cur->ai_next;
|
||||
} else
|
||||
ERR(EAI_FAMILY); /* XXX */
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
*res = sentinel.ai_next;
|
||||
return 0;
|
||||
|
||||
free:
|
||||
bad:
|
||||
if (sentinel.ai_next)
|
||||
rb_freeaddrinfo(sentinel.ai_next);
|
||||
return error;
|
||||
}
|
||||
|
||||
static struct rb_addrinfo *
|
||||
get_ai(const struct rb_addrinfo *pai, const struct afd *afd, const char *addr)
|
||||
{
|
||||
char *p;
|
||||
struct rb_addrinfo *ai;
|
||||
|
||||
ai = (struct rb_addrinfo *)rb_malloc(sizeof(struct rb_addrinfo)
|
||||
+ (afd->a_socklen));
|
||||
if (ai == NULL)
|
||||
return NULL;
|
||||
|
||||
memcpy(ai, pai, sizeof(struct rb_addrinfo));
|
||||
ai->ai_addr = (struct sockaddr *)(void *)(ai + 1);
|
||||
memset(ai->ai_addr, 0, (size_t)afd->a_socklen);
|
||||
ai->ai_addrlen = afd->a_socklen;
|
||||
ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
|
||||
p = (char *)(void *)(ai->ai_addr);
|
||||
memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
|
||||
return ai;
|
||||
}
|
||||
|
||||
static int
|
||||
get_portmatch(const struct rb_addrinfo *ai, const char *servname)
|
||||
{
|
||||
struct rb_addrinfo xai;
|
||||
memcpy(&xai, ai, sizeof(struct rb_addrinfo));
|
||||
return(get_port(&xai, servname, 1));
|
||||
}
|
||||
|
||||
static int
|
||||
get_port(struct rb_addrinfo *ai, const char *servname, int matchonly)
|
||||
{
|
||||
const char *proto;
|
||||
struct servent *sp;
|
||||
int port;
|
||||
int allownumeric;
|
||||
|
||||
if (servname == NULL)
|
||||
return 0;
|
||||
switch (ai->ai_family) {
|
||||
case AF_INET:
|
||||
#ifdef AF_INET6
|
||||
case AF_INET6:
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (ai->ai_socktype) {
|
||||
case SOCK_RAW:
|
||||
return EAI_SERVICE;
|
||||
case SOCK_DGRAM:
|
||||
case SOCK_STREAM:
|
||||
allownumeric = 1;
|
||||
break;
|
||||
case ANY:
|
||||
allownumeric = 0;
|
||||
break;
|
||||
default:
|
||||
return EAI_SOCKTYPE;
|
||||
}
|
||||
|
||||
if (str_isnumber(servname)) {
|
||||
if (!allownumeric)
|
||||
return EAI_SERVICE;
|
||||
port = atoi(servname);
|
||||
if (port < 0 || port > 65535)
|
||||
return EAI_SERVICE;
|
||||
port = htons(port);
|
||||
} else {
|
||||
switch (ai->ai_socktype) {
|
||||
case SOCK_DGRAM:
|
||||
proto = "udp";
|
||||
break;
|
||||
case SOCK_STREAM:
|
||||
proto = "tcp";
|
||||
break;
|
||||
default:
|
||||
proto = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((sp = getservbyname(servname, proto)) == NULL)
|
||||
return EAI_SERVICE;
|
||||
port = sp->s_port;
|
||||
}
|
||||
|
||||
if (!matchonly) {
|
||||
switch (ai->ai_family) {
|
||||
case AF_INET:
|
||||
((struct sockaddr_in *)(void *)
|
||||
ai->ai_addr)->sin_port = port;
|
||||
break;
|
||||
#ifdef IPV6
|
||||
case AF_INET6:
|
||||
((struct sockaddr_in6 *)(void *)
|
||||
ai->ai_addr)->sin6_port = port;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct afd *
|
||||
find_afd(int af)
|
||||
{
|
||||
const struct afd *afd;
|
||||
|
||||
if (af == PF_UNSPEC)
|
||||
return(NULL);
|
||||
|
||||
for (afd = afdl; afd->a_af; afd++)
|
||||
{
|
||||
if (afd->a_af == af)
|
||||
return(afd);
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
#endif
|
|
@ -1,123 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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. Neither the name of the project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``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 PROJECT OR CONTRIBUTORS 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.
|
||||
*
|
||||
*/
|
||||
|
||||
struct rb_addrinfo {
|
||||
int ai_flags;
|
||||
int ai_family;
|
||||
int ai_socktype;
|
||||
int ai_protocol;
|
||||
size_t ai_addrlen;
|
||||
char *ai_canonname;
|
||||
struct sockaddr *ai_addr;
|
||||
struct rb_addrinfo *ai_next;
|
||||
};
|
||||
|
||||
#ifndef AI_PASSIVE
|
||||
#define AI_PASSIVE 0x00000001 /* get address to use bind() */
|
||||
#endif /* AI_PASSIVE */
|
||||
|
||||
#ifndef AI_NUMERICHOST
|
||||
#define AI_NUMERICHOST 0x00000004 /* prevent name resolution */
|
||||
#endif /* AI_NUMERICHOST */
|
||||
|
||||
#ifndef EAI_FAIL
|
||||
#define EAI_FAIL 4 /* non-recoverable failure in name resolution */
|
||||
#endif /* EAI_FAIL */
|
||||
|
||||
#ifndef EAI_FAMILY
|
||||
#define EAI_FAMILY 5 /* ai_family not supported */
|
||||
#endif /* EAI_FAMILY */
|
||||
|
||||
#ifndef EAI_MEMORY
|
||||
#define EAI_MEMORY 6 /* memory allocation failure */
|
||||
#endif /* EAI_MEMORY */
|
||||
|
||||
#ifndef EAI_NONAME
|
||||
#define EAI_NONAME 8 /* hostname nor servname provided, or not known */
|
||||
#endif /* EAI_NONAME */
|
||||
|
||||
#ifndef EAI_SYSTEM
|
||||
#define EAI_SYSTEM 11 /* system error returned in errno */
|
||||
#endif /* EAI_SYSTEM */
|
||||
|
||||
#ifndef NI_NUMERICHOST
|
||||
#define NI_NUMERICHOST 0x00000002
|
||||
#endif /* NI_NUMERICHOST */
|
||||
|
||||
#ifndef NI_NAMEREQD
|
||||
#define NI_NAMEREQD 0x00000004
|
||||
#endif /* NI_NAMEREQD */
|
||||
|
||||
#ifndef NI_NUMERICSERV
|
||||
#define NI_NUMERICSERV 0x00000008
|
||||
#endif /* NI_NUMERICSERV */
|
||||
|
||||
#ifndef NI_DGRAM
|
||||
#define NI_DGRAM 0x00000010
|
||||
#endif /* NI_DGRAM */
|
||||
|
||||
int rb_getaddrinfo(const char *hostname, const char *servname,
|
||||
const struct rb_addrinfo *hints, struct rb_addrinfo **res);
|
||||
void rb_freeaddrinfo(struct rb_addrinfo *ai);
|
||||
|
||||
#define SUCCESS 0
|
||||
#define ANY 0
|
||||
|
||||
#undef EAI_ADDRFAMILY
|
||||
#undef EAI_AGAIN
|
||||
#undef EAI_BADFLAGS
|
||||
#undef EAI_FAIL
|
||||
#undef EAI_FAMILY
|
||||
#undef EAI_MEMORY
|
||||
#undef EAI_NODATA
|
||||
#undef EAI_NONAME
|
||||
#undef EAI_SERVICE
|
||||
#undef EAI_SOCKTYPE
|
||||
#undef EAI_SYSTEM
|
||||
#undef EAI_BADHINTS
|
||||
#undef EAI_PROTOCOL
|
||||
#undef EAI_MAX
|
||||
#undef AI_MASK
|
||||
|
||||
#define EAI_ADDRFAMILY 1 /* address family for hostname not supported */
|
||||
#define EAI_AGAIN 2 /* temporary failure in name resolution */
|
||||
#define EAI_BADFLAGS 3 /* invalid value for ai_flags */
|
||||
#define EAI_FAIL 4 /* non-recoverable failure in name resolution */
|
||||
#define EAI_FAMILY 5 /* ai_family not supported */
|
||||
#define EAI_MEMORY 6 /* memory allocation failure */
|
||||
#define EAI_NODATA 7 /* no address associated with hostname */
|
||||
#define EAI_NONAME 8 /* hostname nor servname provided, or not known */
|
||||
#define EAI_SERVICE 9 /* servname not supported for ai_socktype */
|
||||
#define EAI_SOCKTYPE 10 /* ai_socktype not supported */
|
||||
#define EAI_SYSTEM 11 /* system error returned in errno */
|
||||
#define EAI_BADHINTS 12
|
||||
#define EAI_PROTOCOL 13
|
||||
#define EAI_MAX 14
|
||||
#define AI_MASK (AI_PASSIVE | AI_NUMERICHOST)
|
|
@ -1,240 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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. Neither the name of the project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``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 PROJECT OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Issues to be discussed:
|
||||
* - Thread safe-ness must be checked
|
||||
* - RFC2553 says that we should raise error on short buffer. X/Open says
|
||||
* we need to truncate the result. We obey RFC2553 (and X/Open should be
|
||||
* modified). ipngwg rough consensus seems to follow RFC2553.
|
||||
* - What is "local" in NI_FQDN?
|
||||
* - NI_NAMEREQD and NI_NUMERICHOST conflict with each other.
|
||||
* - (KAME extension) always attach textual scopeid (fe80::1%lo0), if
|
||||
* sin6_scope_id is filled - standardization status?
|
||||
* XXX breaks backward compat for code that expects no scopeid.
|
||||
* beware on merge.
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <rb/rb.h>
|
||||
#include "getaddrinfo.h"
|
||||
#include "getnameinfo.h"
|
||||
|
||||
static const struct afd {
|
||||
int a_af;
|
||||
int a_addrlen;
|
||||
rb_socklen_t a_socklen;
|
||||
int a_off;
|
||||
} afdl [] = {
|
||||
#ifdef IPV6
|
||||
{PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
|
||||
offsetof(struct sockaddr_in6, sin6_addr)},
|
||||
#endif
|
||||
{PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
|
||||
offsetof(struct sockaddr_in, sin_addr)},
|
||||
{0, 0, 0, 0},
|
||||
};
|
||||
|
||||
struct sockinet
|
||||
{
|
||||
unsigned char si_len;
|
||||
unsigned char si_family;
|
||||
unsigned short si_port;
|
||||
};
|
||||
|
||||
#ifdef IPV6
|
||||
static int ip6_parsenumeric(const struct sockaddr *, const char *, char *,
|
||||
size_t, int);
|
||||
#endif
|
||||
|
||||
int
|
||||
rb_getnameinfo(const struct sockaddr *sa, rb_socklen_t salen, char *host,
|
||||
size_t hostlen, char *serv, size_t servlen, int flags)
|
||||
{
|
||||
const struct afd *afd;
|
||||
struct servent *sp;
|
||||
unsigned short port;
|
||||
int family, i;
|
||||
const char *addr;
|
||||
uint32_t v4a;
|
||||
char numserv[512];
|
||||
char numaddr[512];
|
||||
|
||||
if (sa == NULL)
|
||||
return EAI_FAIL;
|
||||
|
||||
/* if (sa->sa_len != salen)
|
||||
return EAI_FAIL;
|
||||
*/
|
||||
family = sa->sa_family;
|
||||
for (i = 0; afdl[i].a_af; i++)
|
||||
if (afdl[i].a_af == family) {
|
||||
afd = &afdl[i];
|
||||
goto found;
|
||||
}
|
||||
return EAI_FAMILY;
|
||||
|
||||
found:
|
||||
if (salen != afd->a_socklen)
|
||||
return EAI_FAIL;
|
||||
|
||||
/* network byte order */
|
||||
port = ((const struct sockinet *)sa)->si_port;
|
||||
addr = (const char *)sa + afd->a_off;
|
||||
|
||||
if (serv == NULL || servlen == 0) {
|
||||
/*
|
||||
* do nothing in this case.
|
||||
* in case you are wondering if "&&" is more correct than
|
||||
* "||" here: rfc2553bis-03 says that serv == NULL OR
|
||||
* servlen == 0 means that the caller does not want the result.
|
||||
*/
|
||||
} else {
|
||||
if (flags & NI_NUMERICSERV)
|
||||
sp = NULL;
|
||||
else {
|
||||
sp = getservbyport(port,
|
||||
(flags & NI_DGRAM) ? "udp" : "tcp");
|
||||
}
|
||||
if (sp) {
|
||||
if (strlen(sp->s_name) + 1 > servlen)
|
||||
return EAI_MEMORY;
|
||||
rb_strlcpy(serv, sp->s_name, servlen);
|
||||
} else {
|
||||
snprintf(numserv, sizeof(numserv), "%u", ntohs(port));
|
||||
if (strlen(numserv) + 1 > servlen)
|
||||
return EAI_MEMORY;
|
||||
rb_strlcpy(serv, numserv, servlen);
|
||||
}
|
||||
}
|
||||
|
||||
switch (sa->sa_family) {
|
||||
case AF_INET:
|
||||
v4a = (uint32_t)
|
||||
ntohl(((const struct sockaddr_in *)sa)->sin_addr.s_addr);
|
||||
if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
|
||||
flags |= NI_NUMERICHOST;
|
||||
v4a >>= IN_CLASSA_NSHIFT;
|
||||
if (v4a == 0)
|
||||
flags |= NI_NUMERICHOST;
|
||||
break;
|
||||
#ifdef IPV6
|
||||
case AF_INET6:
|
||||
{
|
||||
const struct sockaddr_in6 *sin6;
|
||||
sin6 = (const struct sockaddr_in6 *)sa;
|
||||
switch (sin6->sin6_addr.s6_addr[0]) {
|
||||
case 0x00:
|
||||
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
|
||||
;
|
||||
else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
|
||||
;
|
||||
else
|
||||
flags |= NI_NUMERICHOST;
|
||||
break;
|
||||
default:
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
|
||||
flags |= NI_NUMERICHOST;
|
||||
}
|
||||
else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
|
||||
flags |= NI_NUMERICHOST;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
if (host == NULL || hostlen == 0) {
|
||||
/*
|
||||
* do nothing in this case.
|
||||
* in case you are wondering if "&&" is more correct than
|
||||
* "||" here: rfc2553bis-03 says that host == NULL or
|
||||
* hostlen == 0 means that the caller does not want the result.
|
||||
*/
|
||||
} else if (flags & NI_NUMERICHOST) {
|
||||
size_t numaddrlen;
|
||||
|
||||
/* NUMERICHOST and NAMEREQD conflicts with each other */
|
||||
if (flags & NI_NAMEREQD)
|
||||
return EAI_NONAME;
|
||||
|
||||
switch(afd->a_af) {
|
||||
#ifdef IPV6
|
||||
case AF_INET6:
|
||||
{
|
||||
int error;
|
||||
|
||||
if ((error = ip6_parsenumeric(sa, addr, host,
|
||||
hostlen, flags)) != 0)
|
||||
return(error);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
if (rb_inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
|
||||
== NULL)
|
||||
return EAI_SYSTEM;
|
||||
numaddrlen = strlen(numaddr);
|
||||
if (numaddrlen + 1 > hostlen) /* don't forget terminator */
|
||||
return EAI_MEMORY;
|
||||
rb_strlcpy(host, numaddr, hostlen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
#ifdef IPV6
|
||||
static int
|
||||
ip6_parsenumeric(const struct sockaddr *sa, const char *addr,
|
||||
char *host, size_t hostlen, int flags)
|
||||
{
|
||||
size_t numaddrlen;
|
||||
char numaddr[512];
|
||||
|
||||
if (rb_inet_ntop(AF_INET6, addr, numaddr, sizeof(numaddr)) == NULL)
|
||||
return(EAI_SYSTEM);
|
||||
|
||||
numaddrlen = strlen(numaddr);
|
||||
|
||||
if (numaddrlen + 1 > hostlen) /* don't forget terminator */
|
||||
return(EAI_MEMORY);
|
||||
|
||||
if (*numaddr == ':')
|
||||
{
|
||||
*host = '0';
|
||||
rb_strlcpy(host+1, numaddr, hostlen-1);
|
||||
}
|
||||
else
|
||||
rb_strlcpy(host, numaddr, hostlen);
|
||||
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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. Neither the name of the project nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``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 PROJECT OR CONTRIBUTORS 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.
|
||||
*
|
||||
*/
|
||||
|
||||
int rb_getnameinfo(const struct sockaddr *sa, rb_socklen_t salen, char *host,
|
||||
size_t hostlen, char *serv, size_t servlen, int flags);
|
||||
|
||||
#ifndef IN_MULTICAST
|
||||
#define IN_MULTICAST(a) ((((long int) (a)) & 0xf0000000) == 0xe0000000)
|
||||
#endif
|
||||
|
||||
#ifndef IN_EXPERIMENTAL
|
||||
#define IN_EXPERIMENTAL(a) ((((long int) (a)) & 0xe0000000) == 0xe0000000)
|
||||
#endif
|
|
@ -1,87 +0,0 @@
|
|||
/* authd/notice.c - send notices back to the ircd and to clients
|
||||
* Copyright (c) 2016 Elizabeth Myers <elizabeth@interlinked.me>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "authd.h"
|
||||
#include "notice.h"
|
||||
|
||||
using namespace ircd::defaults;
|
||||
|
||||
|
||||
/* Send a notice to a client */
|
||||
void
|
||||
notice_client(uint32_t cid, const char *fmt, ...)
|
||||
{
|
||||
char buf[BUFSIZE];
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
rb_helper_write(authd_helper, "N %x :%s", cid, buf);
|
||||
}
|
||||
|
||||
/* Send a warning to the IRC daemon for logging, etc. */
|
||||
void
|
||||
warn_opers(notice_level_t level, const char *fmt, ...)
|
||||
{
|
||||
char buf[BUFSIZE];
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
rb_helper_write(authd_helper, "W %c :%s", level, buf);
|
||||
}
|
||||
|
||||
/* Send a stats result */
|
||||
void
|
||||
stats_result(uint32_t cid, char letter, const char *fmt, ...)
|
||||
{
|
||||
char buf[BUFSIZE];
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
rb_helper_write(authd_helper, "Y %x %c %s", cid, letter, buf);
|
||||
}
|
||||
|
||||
/* Send a stats error */
|
||||
void
|
||||
stats_error(uint32_t cid, char letter, const char *fmt, ...)
|
||||
{
|
||||
char buf[BUFSIZE];
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
rb_helper_write(authd_helper, "X %x %c %s", cid, letter, buf);
|
||||
}
|
||||
|
||||
void
|
||||
stats_done(uint32_t cid, char letter)
|
||||
{
|
||||
rb_helper_write(authd_helper, "Z %x %c", cid, letter);
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
/* authd/notice.h - send notices back to the ircd and to clients
|
||||
* Copyright (c) 2016 Elizabeth Myers <elizabeth@interlinked.me>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __CHARYBDIS_AUTHD_NOTICE_H__
|
||||
#define __CHARYBDIS_AUTHD_NOTICE_H__
|
||||
|
||||
typedef enum
|
||||
{
|
||||
L_DEBUG = 'D',
|
||||
L_INFO = 'I',
|
||||
L_WARN = 'W',
|
||||
L_CRIT ='C',
|
||||
} notice_level_t;
|
||||
|
||||
void notice_client(uint32_t cid, const char *fmt, ...);
|
||||
void warn_opers(notice_level_t level, const char *fmt, ...);
|
||||
void stats_result(uint32_t cid, char letter, const char *fmt, ...);
|
||||
void stats_error(uint32_t cid, char letter, const char *fmt, ...);
|
||||
void stats_done(uint32_t cid, char letter);
|
||||
|
||||
#endif /* __CHARYBDIS_AUTHD_NOTICE_H__ */
|
|
@ -1,408 +0,0 @@
|
|||
/* authd/provider.c - authentication provider framework
|
||||
* Copyright (c) 2016 Elizabeth Myers <elizabeth@interlinked.me>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* The basic design here is to have "authentication providers" that do things
|
||||
* like query ident and blacklists and even open proxies.
|
||||
*
|
||||
* Providers are registered in the auth_providers linked list. It is planned to
|
||||
* use a bitmap to store provider ID's later.
|
||||
*
|
||||
* Providers can either return failure immediately, immediate acceptance, or do
|
||||
* work in the background (calling set_provider to signal this).
|
||||
*
|
||||
* Provider-specific data for each client can be kept in an index of the data
|
||||
* struct member (using the provider's ID).
|
||||
*
|
||||
* All providers must implement at a minimum a perform_provider function. You
|
||||
* don't have to implement the others if you don't need them.
|
||||
*
|
||||
* Providers may kick clients off by rejecting them. Upon rejection, all
|
||||
* providers are cancelled. They can also unconditionally accept them.
|
||||
*
|
||||
* When a provider is done and is neutral on accepting/rejecting a client, it
|
||||
* should call provider_done. Do NOT call this if you have accepted or rejected
|
||||
* the client.
|
||||
*
|
||||
* Eventually, stuff like *:line handling will be moved here, but that means we
|
||||
* have to talk to bandb directly first.
|
||||
*
|
||||
* --Elizafox, 9 March 2016
|
||||
*/
|
||||
|
||||
#include "authd.h"
|
||||
#include "provider.h"
|
||||
#include "notice.h"
|
||||
|
||||
using namespace ircd::defaults;
|
||||
|
||||
static EVH provider_timeout_event;
|
||||
|
||||
rb_dictionary *auth_clients;
|
||||
rb_dlink_list auth_providers;
|
||||
|
||||
static rb_dlink_list free_pids;
|
||||
static uint32_t allocated_pids;
|
||||
static struct ev_entry *timeout_ev;
|
||||
|
||||
/* Initalise all providers */
|
||||
void
|
||||
init_providers(void)
|
||||
{
|
||||
auth_clients = rb_dictionary_create("pending auth clients", rb_uint32cmp);
|
||||
timeout_ev = rb_event_addish("provider_timeout_event", provider_timeout_event, NULL, 1);
|
||||
|
||||
load_provider(&rdns_provider);
|
||||
load_provider(&ident_provider);
|
||||
load_provider(&blacklist_provider);
|
||||
load_provider(&opm_provider);
|
||||
}
|
||||
|
||||
/* Terminate all providers */
|
||||
void
|
||||
destroy_providers(void)
|
||||
{
|
||||
rb_dlink_node *ptr, *nptr;
|
||||
rb_dictionary_iter iter;
|
||||
struct auth_client *auth;
|
||||
|
||||
/* Cancel outstanding connections */
|
||||
void *elem;
|
||||
RB_DICTIONARY_FOREACH(elem, &iter, auth_clients)
|
||||
{
|
||||
auth = (auth_client *)elem;
|
||||
auth_client_ref(auth);
|
||||
|
||||
/* TBD - is this the right thing? */
|
||||
reject_client(auth, UINT32_MAX, "destroy",
|
||||
"Authentication system is down... try reconnecting in a few seconds");
|
||||
|
||||
auth_client_unref(auth);
|
||||
}
|
||||
|
||||
RB_DLINK_FOREACH_SAFE(ptr, nptr, auth_providers.head)
|
||||
{
|
||||
struct auth_provider *provider = (auth_provider *)ptr->data;
|
||||
|
||||
if(provider->destroy)
|
||||
provider->destroy();
|
||||
|
||||
rb_dlinkDelete(ptr, &auth_providers);
|
||||
}
|
||||
|
||||
rb_dictionary_destroy(auth_clients, NULL, NULL);
|
||||
rb_event_delete(timeout_ev);
|
||||
}
|
||||
|
||||
/* Load a provider */
|
||||
void
|
||||
load_provider(struct auth_provider *provider)
|
||||
{
|
||||
/* Assign a PID */
|
||||
if(rb_dlink_list_length(&free_pids) > 0)
|
||||
{
|
||||
/* use the free list */
|
||||
provider->id = RB_POINTER_TO_UINT(free_pids.head->data);
|
||||
rb_dlinkDestroy(free_pids.head, &free_pids);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(allocated_pids == MAX_PROVIDERS || allocated_pids == UINT32_MAX)
|
||||
{
|
||||
warn_opers(L_WARN, "Cannot load additional provider, max reached!");
|
||||
return;
|
||||
}
|
||||
|
||||
provider->id = allocated_pids++;
|
||||
}
|
||||
|
||||
if(provider->opt_handlers != NULL)
|
||||
{
|
||||
struct auth_opts_handler *handler;
|
||||
|
||||
for(handler = provider->opt_handlers; handler->option != NULL; handler++)
|
||||
rb_dictionary_add(authd_option_handlers, handler->option, handler);
|
||||
}
|
||||
|
||||
if(provider->stats_handler.letter != '\0')
|
||||
authd_stat_handlers[(unsigned char)provider->stats_handler.letter] = provider->stats_handler.handler;
|
||||
|
||||
if(provider->init != NULL)
|
||||
provider->init();
|
||||
|
||||
rb_dlinkAdd(provider, &provider->node, &auth_providers);
|
||||
}
|
||||
|
||||
void
|
||||
unload_provider(struct auth_provider *provider)
|
||||
{
|
||||
if(provider->opt_handlers != NULL)
|
||||
{
|
||||
struct auth_opts_handler *handler;
|
||||
|
||||
for(handler = provider->opt_handlers; handler->option != NULL; handler++)
|
||||
rb_dictionary_delete(authd_option_handlers, handler->option);
|
||||
}
|
||||
|
||||
if(provider->stats_handler.letter != '\0')
|
||||
authd_stat_handlers[(unsigned char)provider->stats_handler.letter] = NULL;
|
||||
|
||||
if(provider->destroy != NULL)
|
||||
provider->destroy();
|
||||
|
||||
rb_dlinkDelete(&provider->node, &auth_providers);
|
||||
|
||||
/* Reclaim ID */
|
||||
rb_dlinkAddAlloc(RB_UINT_TO_POINTER(provider->id), &free_pids);
|
||||
}
|
||||
|
||||
void
|
||||
auth_client_free(struct auth_client *auth)
|
||||
{
|
||||
rb_dictionary_delete(auth_clients, RB_UINT_TO_POINTER(auth->cid));
|
||||
rb_free(auth->data);
|
||||
rb_free(auth);
|
||||
}
|
||||
|
||||
/* Cancel outstanding providers for a client (if any). */
|
||||
void
|
||||
cancel_providers(struct auth_client *auth)
|
||||
{
|
||||
if(auth->providers_cancelled)
|
||||
return;
|
||||
|
||||
auth->providers_cancelled = true;
|
||||
|
||||
if(auth->providers_active > 0)
|
||||
{
|
||||
rb_dlink_node *ptr;
|
||||
|
||||
RB_DLINK_FOREACH(ptr, auth_providers.head)
|
||||
{
|
||||
struct auth_provider *provider = (auth_provider *)ptr->data;
|
||||
|
||||
if(provider->cancel != NULL && is_provider_running(auth, provider->id))
|
||||
/* Cancel if required */
|
||||
provider->cancel(auth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Provider is done */
|
||||
void
|
||||
provider_done(struct auth_client *auth, uint32_t id)
|
||||
{
|
||||
rb_dlink_node *ptr;
|
||||
|
||||
lrb_assert(is_provider_running(auth, id));
|
||||
lrb_assert(id != UINT32_MAX);
|
||||
lrb_assert(id < allocated_pids);
|
||||
|
||||
set_provider_done(auth, id);
|
||||
|
||||
if(auth->providers_active == 0 && !auth->providers_starting)
|
||||
{
|
||||
/* All done */
|
||||
accept_client(auth);
|
||||
return;
|
||||
}
|
||||
|
||||
RB_DLINK_FOREACH(ptr, auth_providers.head)
|
||||
{
|
||||
struct auth_provider *provider = (auth_provider *)ptr->data;
|
||||
|
||||
if(provider->completed != NULL && is_provider_running(auth, provider->id))
|
||||
/* Notify pending clients who asked for it */
|
||||
provider->completed(auth, id);
|
||||
}
|
||||
}
|
||||
|
||||
/* Reject a client and cancel any outstanding providers */
|
||||
void
|
||||
reject_client(struct auth_client *auth, uint32_t id, const char *data, const char *fmt, ...)
|
||||
{
|
||||
char buf[BUFSIZE];
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
/* We send back username and hostname in case ircd wants to overrule our decision.
|
||||
* In the future this may not be the case.
|
||||
* --Elizafox
|
||||
*/
|
||||
rb_helper_write(authd_helper, "R %x %c %s %s %s :%s",
|
||||
auth->cid, id != UINT32_MAX ? auth->data[id].provider->letter : '*',
|
||||
auth->username, auth->hostname,
|
||||
data == NULL ? "*" : data, buf);
|
||||
|
||||
if(id != UINT32_MAX)
|
||||
set_provider_done(auth, id);
|
||||
|
||||
cancel_providers(auth);
|
||||
}
|
||||
|
||||
/* Accept a client and cancel outstanding providers if any */
|
||||
void
|
||||
accept_client(struct auth_client *auth)
|
||||
{
|
||||
rb_helper_write(authd_helper, "A %x %s %s", auth->cid, auth->username, auth->hostname);
|
||||
cancel_providers(auth);
|
||||
}
|
||||
|
||||
/* Begin authenticating user */
|
||||
static void
|
||||
start_auth(const char *cid, const char *l_ip, const char *l_port, const char *c_ip, const char *c_port)
|
||||
{
|
||||
struct auth_client *auth;
|
||||
unsigned long long lcid = strtoull(cid, NULL, 16);
|
||||
rb_dlink_node *ptr;
|
||||
|
||||
if(lcid == 0 || lcid > UINT32_MAX)
|
||||
return;
|
||||
|
||||
auth = (auth_client *)rb_malloc(sizeof(struct auth_client));
|
||||
auth_client_ref(auth);
|
||||
auth->cid = (uint32_t)lcid;
|
||||
|
||||
if(rb_dictionary_find(auth_clients, RB_UINT_TO_POINTER(auth->cid)) == NULL)
|
||||
rb_dictionary_add(auth_clients, RB_UINT_TO_POINTER(auth->cid), auth);
|
||||
else
|
||||
{
|
||||
warn_opers(L_CRIT, "provider: duplicate client added via start_auth: %s", cid);
|
||||
exit(EX_PROVIDER_ERROR);
|
||||
}
|
||||
|
||||
rb_strlcpy(auth->l_ip, l_ip, sizeof(auth->l_ip));
|
||||
auth->l_port = (uint16_t)atoi(l_port); /* should be safe */
|
||||
(void) rb_inet_pton_sock(l_ip, (struct sockaddr *)&auth->l_addr);
|
||||
SET_SS_PORT(&auth->l_addr, htons(auth->l_port));
|
||||
|
||||
rb_strlcpy(auth->c_ip, c_ip, sizeof(auth->c_ip));
|
||||
auth->c_port = (uint16_t)atoi(c_port);
|
||||
(void) rb_inet_pton_sock(c_ip, (struct sockaddr *)&auth->c_addr);
|
||||
SET_SS_PORT(&auth->c_addr, htons(auth->c_port));
|
||||
|
||||
rb_strlcpy(auth->hostname, "*", sizeof(auth->hostname));
|
||||
rb_strlcpy(auth->username, "*", sizeof(auth->username));
|
||||
|
||||
auth->data = (auth_client_data *)rb_malloc(allocated_pids * sizeof(struct auth_client_data));
|
||||
|
||||
auth->providers_starting = true;
|
||||
RB_DLINK_FOREACH(ptr, auth_providers.head)
|
||||
{
|
||||
struct auth_provider *provider = (auth_provider *)ptr->data;
|
||||
|
||||
auth->data[provider->id].provider = provider;
|
||||
|
||||
lrb_assert(provider->start != NULL);
|
||||
|
||||
/* Execute providers */
|
||||
if(!provider->start(auth))
|
||||
/* Rejected immediately */
|
||||
goto done;
|
||||
|
||||
if(auth->providers_cancelled)
|
||||
break;
|
||||
}
|
||||
auth->providers_starting = false;
|
||||
|
||||
/* If no providers are running, accept the client */
|
||||
if(auth->providers_active == 0)
|
||||
accept_client(auth);
|
||||
|
||||
done:
|
||||
auth_client_unref(auth);
|
||||
}
|
||||
|
||||
/* Callback for the initiation */
|
||||
void
|
||||
handle_new_connection(int parc, char *parv[])
|
||||
{
|
||||
if(parc < 6)
|
||||
{
|
||||
warn_opers(L_CRIT, "provider: received too few params for new connection (6 expected, got %d)", parc);
|
||||
exit(EX_PROVIDER_ERROR);
|
||||
}
|
||||
|
||||
start_auth(parv[1], parv[2], parv[3], parv[4], parv[5]);
|
||||
}
|
||||
|
||||
void
|
||||
handle_cancel_connection(int parc, char *parv[])
|
||||
{
|
||||
struct auth_client *auth;
|
||||
unsigned long long lcid;
|
||||
|
||||
if(parc < 2)
|
||||
{
|
||||
warn_opers(L_CRIT, "provider: received too few params for new connection (2 expected, got %d)", parc);
|
||||
exit(EX_PROVIDER_ERROR);
|
||||
}
|
||||
|
||||
lcid = strtoull(parv[1], NULL, 16);
|
||||
if(lcid == 0 || lcid > UINT32_MAX)
|
||||
{
|
||||
warn_opers(L_CRIT, "provider: got a request to cancel a connection that can't exist: %s", parv[1]);
|
||||
exit(EX_PROVIDER_ERROR);
|
||||
}
|
||||
|
||||
if((auth = (auth_client *)rb_dictionary_retrieve(auth_clients, RB_UINT_TO_POINTER((uint32_t)lcid))) == NULL)
|
||||
{
|
||||
/* This could happen as a race if we've accepted/rejected but they cancel, so don't die here.
|
||||
* --Elizafox */
|
||||
return;
|
||||
}
|
||||
|
||||
auth_client_ref(auth);
|
||||
cancel_providers(auth);
|
||||
auth_client_unref(auth);
|
||||
}
|
||||
|
||||
static void
|
||||
provider_timeout_event(void *notused)
|
||||
{
|
||||
struct auth_client *auth;
|
||||
rb_dictionary_iter iter;
|
||||
const time_t curtime = rb_current_time();
|
||||
|
||||
void *elem;
|
||||
RB_DICTIONARY_FOREACH(elem, &iter, auth_clients)
|
||||
{
|
||||
rb_dlink_node *ptr;
|
||||
|
||||
auth = (auth_client *)elem;
|
||||
auth_client_ref(auth);
|
||||
|
||||
RB_DLINK_FOREACH(ptr, auth_providers.head)
|
||||
{
|
||||
struct auth_provider *provider = (auth_provider *)ptr->data;
|
||||
const time_t timeout = get_provider_timeout(auth, provider->id);
|
||||
|
||||
if(is_provider_running(auth, provider->id) && provider->timeout != NULL &&
|
||||
timeout > 0 && timeout < curtime)
|
||||
{
|
||||
provider->timeout(auth);
|
||||
}
|
||||
}
|
||||
|
||||
auth_client_unref(auth);
|
||||
}
|
||||
}
|
254
authd/provider.h
254
authd/provider.h
|
@ -1,254 +0,0 @@
|
|||
/* authd/provider.h - authentication provider framework
|
||||
* Copyright (c) 2016 Elizabeth Myers <elizabeth@interlinked.me>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __CHARYBDIS_AUTHD_PROVIDER_H__
|
||||
#define __CHARYBDIS_AUTHD_PROVIDER_H__
|
||||
|
||||
#include "authd.h"
|
||||
|
||||
#define MAX_PROVIDERS 32 /* This should be enough */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PROVIDER_STATUS_NOTRUN = 0,
|
||||
PROVIDER_STATUS_RUNNING,
|
||||
PROVIDER_STATUS_DONE,
|
||||
} provider_status_t;
|
||||
|
||||
struct auth_client_data
|
||||
{
|
||||
struct auth_provider *provider; /* Pointer back */
|
||||
time_t timeout; /* Provider timeout */
|
||||
void *data; /* Provider data */
|
||||
provider_status_t status; /* Provider status */
|
||||
};
|
||||
|
||||
struct auth_client
|
||||
{
|
||||
uint32_t cid; /* Client ID */
|
||||
|
||||
char l_ip[HOSTIPLEN + 1]; /* Listener IP address */
|
||||
uint16_t l_port; /* Listener port */
|
||||
struct rb_sockaddr_storage l_addr; /* Listener address/port */
|
||||
|
||||
char c_ip[HOSTIPLEN + 1]; /* Client IP address */
|
||||
uint16_t c_port; /* Client port */
|
||||
struct rb_sockaddr_storage c_addr; /* Client address/port */
|
||||
|
||||
char hostname[ircd::HOSTLEN + 1]; /* Used for DNS lookup */
|
||||
char username[ircd::USERLEN + 1]; /* Used for ident lookup */
|
||||
|
||||
bool providers_starting; /* Providers are still warming up */
|
||||
bool providers_cancelled; /* Providers are being cancelled */
|
||||
unsigned int providers_active; /* Number of active providers */
|
||||
unsigned int refcount; /* Held references */
|
||||
|
||||
struct auth_client_data *data; /* Provider-specific data */
|
||||
};
|
||||
|
||||
typedef bool (*provider_init_t)(void);
|
||||
typedef void (*provider_destroy_t)(void);
|
||||
|
||||
typedef bool (*provider_start_t)(struct auth_client *);
|
||||
typedef void (*provider_cancel_t)(struct auth_client *);
|
||||
typedef void (*uint32_timeout_t)(struct auth_client *);
|
||||
typedef void (*provider_complete_t)(struct auth_client *, uint32_t);
|
||||
|
||||
struct auth_stats_handler
|
||||
{
|
||||
char letter;
|
||||
authd_stat_handler handler;
|
||||
};
|
||||
|
||||
struct auth_provider
|
||||
{
|
||||
rb_dlink_node node;
|
||||
|
||||
uint32_t id; /* Provider ID */
|
||||
|
||||
const char *name; /* Name of the provider */
|
||||
char letter; /* Letter used on reject, etc. */
|
||||
|
||||
provider_init_t init; /* Initalise the provider */
|
||||
provider_destroy_t destroy; /* Terminate the provider */
|
||||
|
||||
provider_start_t start; /* Perform authentication */
|
||||
provider_cancel_t cancel; /* Authentication cancelled */
|
||||
uint32_timeout_t timeout; /* Timeout callback */
|
||||
provider_complete_t completed; /* Callback for when other performers complete (think dependency chains) */
|
||||
|
||||
struct auth_stats_handler stats_handler;
|
||||
|
||||
struct auth_opts_handler *opt_handlers;
|
||||
};
|
||||
|
||||
extern struct auth_provider rdns_provider;
|
||||
extern struct auth_provider ident_provider;
|
||||
extern struct auth_provider blacklist_provider;
|
||||
extern struct auth_provider opm_provider;
|
||||
|
||||
extern rb_dlink_list auth_providers;
|
||||
extern rb_dictionary *auth_clients;
|
||||
|
||||
void load_provider(struct auth_provider *provider);
|
||||
void unload_provider(struct auth_provider *provider);
|
||||
|
||||
void init_providers(void);
|
||||
void destroy_providers(void);
|
||||
void cancel_providers(struct auth_client *auth);
|
||||
|
||||
void provider_done(struct auth_client *auth, uint32_t id);
|
||||
void accept_client(struct auth_client *auth);
|
||||
void reject_client(struct auth_client *auth, uint32_t id, const char *data, const char *fmt, ...);
|
||||
|
||||
void handle_new_connection(int parc, char *parv[]);
|
||||
void handle_cancel_connection(int parc, char *parv[]);
|
||||
void auth_client_free(struct auth_client *auth);
|
||||
|
||||
static inline void
|
||||
auth_client_ref(struct auth_client *auth)
|
||||
{
|
||||
auth->refcount++;
|
||||
}
|
||||
|
||||
static inline void
|
||||
auth_client_unref(struct auth_client *auth)
|
||||
{
|
||||
auth->refcount--;
|
||||
if (auth->refcount == 0)
|
||||
auth_client_free(auth);
|
||||
}
|
||||
|
||||
/* Get a provider by name */
|
||||
static inline struct auth_provider *
|
||||
find_provider(const char *name)
|
||||
{
|
||||
rb_dlink_node *ptr;
|
||||
|
||||
RB_DLINK_FOREACH(ptr, auth_providers.head)
|
||||
{
|
||||
struct auth_provider *provider = (auth_provider *)ptr->data;
|
||||
|
||||
if(strcasecmp(provider->name, name) == 0)
|
||||
return provider;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get a provider's id by name */
|
||||
static inline bool
|
||||
get_provider_id(const char *name, uint32_t *id)
|
||||
{
|
||||
struct auth_provider *provider = find_provider(name);
|
||||
|
||||
if(provider != NULL)
|
||||
{
|
||||
*id = provider->id;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get a provider's raw status */
|
||||
static inline provider_status_t
|
||||
get_provider_status(struct auth_client *auth, uint32_t provider)
|
||||
{
|
||||
return auth->data[provider].status;
|
||||
}
|
||||
|
||||
/* Set a provider's raw status */
|
||||
static inline void
|
||||
set_provider_status(struct auth_client *auth, uint32_t provider, provider_status_t status)
|
||||
{
|
||||
auth->data[provider].status = status;
|
||||
}
|
||||
|
||||
/* Set the provider as running
|
||||
* If you're doing asynchronous work call this */
|
||||
static inline void
|
||||
set_provider_running(struct auth_client *auth, uint32_t provider)
|
||||
{
|
||||
auth->providers_active++;
|
||||
set_provider_status(auth, provider, PROVIDER_STATUS_RUNNING);
|
||||
}
|
||||
|
||||
/* Provider is no longer operating on this auth client
|
||||
* You should use provider_done and not this */
|
||||
static inline void
|
||||
set_provider_done(struct auth_client *auth, uint32_t provider)
|
||||
{
|
||||
set_provider_status(auth, provider, PROVIDER_STATUS_DONE);
|
||||
auth->providers_active--;
|
||||
}
|
||||
|
||||
/* Check if provider is operating on this auth client */
|
||||
static inline bool
|
||||
is_provider_running(struct auth_client *auth, uint32_t provider)
|
||||
{
|
||||
return get_provider_status(auth, provider) == PROVIDER_STATUS_RUNNING;
|
||||
}
|
||||
|
||||
/* Check if provider has finished on this client */
|
||||
static inline bool
|
||||
is_provider_done(struct auth_client *auth, uint32_t provider)
|
||||
{
|
||||
return get_provider_status(auth, provider) == PROVIDER_STATUS_DONE;
|
||||
}
|
||||
|
||||
/* Get provider auth client data */
|
||||
static inline void *
|
||||
get_provider_data(struct auth_client *auth, uint32_t id)
|
||||
{
|
||||
return auth->data[id].data;
|
||||
}
|
||||
|
||||
/* Set provider auth client data */
|
||||
static inline void
|
||||
set_provider_data(struct auth_client *auth, uint32_t id, void *data)
|
||||
{
|
||||
auth->data[id].data = data;
|
||||
}
|
||||
|
||||
/* Set timeout relative to current time on provider
|
||||
* When the timeout lapses, the provider's timeout call will execute */
|
||||
static inline void
|
||||
set_provider_timeout_relative(struct auth_client *auth, uint32_t id, time_t timeout)
|
||||
{
|
||||
auth->data[id].timeout = timeout + rb_current_time();
|
||||
}
|
||||
|
||||
/* Set timeout value in absolute time (Unix timestamp)
|
||||
* When the timeout lapses, the provider's timeout call will execute */
|
||||
static inline void
|
||||
set_provider_timeout_absolute(struct auth_client *auth, uint32_t id, time_t timeout)
|
||||
{
|
||||
auth->data[id].timeout = timeout;
|
||||
}
|
||||
|
||||
/* Get the timeout value for the provider */
|
||||
static inline time_t
|
||||
get_provider_timeout(struct auth_client *auth, uint32_t id)
|
||||
{
|
||||
return auth->data[id].timeout;
|
||||
}
|
||||
|
||||
#endif /* __CHARYBDIS_AUTHD_PROVIDER_H__ */
|
|
@ -1,625 +0,0 @@
|
|||
/*
|
||||
* charybdis: A slightly useful ircd.
|
||||
* blacklist.c: Manages DNS blacklist entries and lookups
|
||||
*
|
||||
* Copyright (C) 2006-2011 charybdis 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.
|
||||
*/
|
||||
|
||||
/* Originally written for charybdis circa 2006 (by nenolod?).
|
||||
* Tweaked for authd. Some functions and structs renamed. Public/private
|
||||
* interfaces have been shifted around. Some code has been cleaned up too.
|
||||
* -- Elizafox 24 March 2016
|
||||
*/
|
||||
|
||||
#include "authd.h"
|
||||
#include "provider.h"
|
||||
#include "notice.h"
|
||||
#include "dns.h"
|
||||
|
||||
using namespace ircd::defaults;
|
||||
|
||||
#define SELF_PID (blacklist_provider.id)
|
||||
|
||||
typedef enum filter_t
|
||||
{
|
||||
FILTER_ALL = 1,
|
||||
FILTER_LAST = 2,
|
||||
} filter_t;
|
||||
|
||||
/* Blacklist accepted IP types */
|
||||
#define IPTYPE_IPV4 1
|
||||
#define IPTYPE_IPV6 2
|
||||
|
||||
/* A configured DNSBL */
|
||||
struct blacklist
|
||||
{
|
||||
char host[IRCD_RES_HOSTLEN + 1];
|
||||
char reason[BUFSIZE]; /* Reason template (ircd fills in the blanks) */
|
||||
uint8_t iptype; /* IP types supported */
|
||||
rb_dlink_list filters; /* Filters for queries */
|
||||
|
||||
bool delete_; /* If true delete when no clients */
|
||||
int refcount; /* When 0 and delete is set, remove this blacklist */
|
||||
unsigned int hits;
|
||||
|
||||
time_t lastwarning; /* Last warning about garbage replies sent */
|
||||
};
|
||||
|
||||
/* A lookup in progress for a particular DNSBL for a particular client */
|
||||
struct blacklist_lookup
|
||||
{
|
||||
struct blacklist *bl; /* Blacklist we're checking */
|
||||
struct auth_client *auth; /* Client */
|
||||
struct dns_query *query; /* DNS query pointer */
|
||||
|
||||
rb_dlink_node node;
|
||||
};
|
||||
|
||||
/* A blacklist filter */
|
||||
struct blacklist_filter
|
||||
{
|
||||
filter_t type; /* Type of filter */
|
||||
char filter[HOSTIPLEN]; /* The filter itself */
|
||||
|
||||
rb_dlink_node node;
|
||||
};
|
||||
|
||||
/* Blacklist user data attached to auth_client instance */
|
||||
struct blacklist_user
|
||||
{
|
||||
rb_dlink_list queries; /* Blacklist queries in flight */
|
||||
};
|
||||
|
||||
/* public interfaces */
|
||||
static void blacklists_destroy(void);
|
||||
|
||||
static bool blacklists_start(struct auth_client *);
|
||||
static inline void blacklists_generic_cancel(struct auth_client *, const char *);
|
||||
static void blacklists_timeout(struct auth_client *);
|
||||
static void blacklists_cancel(struct auth_client *);
|
||||
static void blacklists_cancel_none(struct auth_client *);
|
||||
|
||||
/* private interfaces */
|
||||
static void unref_blacklist(struct blacklist *);
|
||||
static struct blacklist *new_blacklist(const char *, const char *, uint8_t, rb_dlink_list *);
|
||||
static struct blacklist *find_blacklist(const char *);
|
||||
static bool blacklist_check_reply(struct blacklist_lookup *, const char *);
|
||||
static void blacklist_dns_callback(const char *, bool, query_type, void *);
|
||||
static void initiate_blacklist_dnsquery(struct blacklist *, struct auth_client *);
|
||||
|
||||
/* Variables */
|
||||
static rb_dlink_list blacklist_list = { NULL, NULL, 0 };
|
||||
static int blacklist_timeout = BLACKLIST_TIMEOUT_DEFAULT;
|
||||
|
||||
/* private interfaces */
|
||||
|
||||
static void
|
||||
unref_blacklist(struct blacklist *bl)
|
||||
{
|
||||
rb_dlink_node *ptr, *nptr;
|
||||
|
||||
bl->refcount--;
|
||||
if (bl->delete_ && bl->refcount <= 0)
|
||||
{
|
||||
RB_DLINK_FOREACH_SAFE(ptr, nptr, bl->filters.head)
|
||||
{
|
||||
rb_dlinkDelete(ptr, &bl->filters);
|
||||
rb_free(ptr);
|
||||
}
|
||||
|
||||
rb_dlinkFindDestroy(bl, &blacklist_list);
|
||||
rb_free(bl);
|
||||
}
|
||||
}
|
||||
|
||||
static struct blacklist *
|
||||
new_blacklist(const char *name, const char *reason, uint8_t iptype, rb_dlink_list *filters)
|
||||
{
|
||||
struct blacklist *bl;
|
||||
|
||||
if (name == NULL || reason == NULL || iptype == 0)
|
||||
return NULL;
|
||||
|
||||
if((bl = find_blacklist(name)) == NULL)
|
||||
{
|
||||
bl = (blacklist *)rb_malloc(sizeof(struct blacklist));
|
||||
rb_dlinkAddAlloc(bl, &blacklist_list);
|
||||
}
|
||||
else
|
||||
bl->delete_ = false;
|
||||
|
||||
rb_strlcpy(bl->host, name, IRCD_RES_HOSTLEN + 1);
|
||||
rb_strlcpy(bl->reason, reason, BUFSIZE);
|
||||
bl->iptype = iptype;
|
||||
|
||||
rb_dlinkMoveList(filters, &bl->filters);
|
||||
|
||||
bl->lastwarning = 0;
|
||||
|
||||
return bl;
|
||||
}
|
||||
|
||||
static struct blacklist *
|
||||
find_blacklist(const char *name)
|
||||
{
|
||||
rb_dlink_node *ptr;
|
||||
|
||||
RB_DLINK_FOREACH(ptr, blacklist_list.head)
|
||||
{
|
||||
struct blacklist *bl = (struct blacklist *)ptr->data;
|
||||
|
||||
if (!strcasecmp(bl->host, name))
|
||||
return bl;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
blacklist_check_reply(struct blacklist_lookup *bllookup, const char *ipaddr)
|
||||
{
|
||||
struct blacklist *bl = bllookup->bl;
|
||||
const char *lastoctet;
|
||||
rb_dlink_node *ptr;
|
||||
|
||||
/* No filters and entry found - thus positive match */
|
||||
if (!rb_dlink_list_length(&bl->filters))
|
||||
return true;
|
||||
|
||||
/* Below will prolly have to change if IPv6 address replies are sent back */
|
||||
if ((lastoctet = strrchr(ipaddr, '.')) == NULL || *(++lastoctet) == '\0')
|
||||
goto blwarn;
|
||||
|
||||
RB_DLINK_FOREACH(ptr, bl->filters.head)
|
||||
{
|
||||
struct blacklist_filter *filter = (blacklist_filter *)ptr->data;
|
||||
const char *cmpstr;
|
||||
|
||||
if (filter->type == FILTER_ALL)
|
||||
cmpstr = ipaddr;
|
||||
else if (filter->type == FILTER_LAST)
|
||||
cmpstr = lastoctet;
|
||||
else
|
||||
{
|
||||
warn_opers(L_CRIT, "Blacklist: Unknown blacklist filter type (host %s): %d",
|
||||
bl->host, filter->type);
|
||||
exit(EX_PROVIDER_ERROR);
|
||||
}
|
||||
|
||||
if (strcmp(cmpstr, filter->filter) == 0)
|
||||
/* Match! */
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
blwarn:
|
||||
if (bl->lastwarning + 3600 < rb_current_time())
|
||||
{
|
||||
warn_opers(L_WARN, "Garbage/undecipherable reply received from blacklist %s (reply %s)",
|
||||
bl->host, ipaddr);
|
||||
bl->lastwarning = rb_current_time();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
blacklist_dns_callback(const char *result, bool status, query_type type, void *data)
|
||||
{
|
||||
struct blacklist_lookup *bllookup = (struct blacklist_lookup *)data;
|
||||
struct blacklist_user *bluser;
|
||||
struct blacklist *bl;
|
||||
struct auth_client *auth;
|
||||
|
||||
lrb_assert(bllookup != NULL);
|
||||
lrb_assert(bllookup->auth != NULL);
|
||||
|
||||
bl = bllookup->bl;
|
||||
auth = bllookup->auth;
|
||||
|
||||
if((bluser = (blacklist_user *)get_provider_data(auth, SELF_PID)) == NULL)
|
||||
return;
|
||||
|
||||
if (result != NULL && status && blacklist_check_reply(bllookup, result))
|
||||
{
|
||||
/* Match found, so proceed no further */
|
||||
bl->hits++;
|
||||
reject_client(auth, SELF_PID, bl->host, bl->reason);
|
||||
blacklists_cancel(auth);
|
||||
return;
|
||||
}
|
||||
|
||||
unref_blacklist(bl);
|
||||
cancel_query(bllookup->query); /* Ignore future responses */
|
||||
rb_dlinkDelete(&bllookup->node, &bluser->queries);
|
||||
rb_free(bllookup);
|
||||
|
||||
if(!rb_dlink_list_length(&bluser->queries))
|
||||
{
|
||||
/* Done here */
|
||||
notice_client(auth->cid, "*** IP not found in DNS blacklist%s",
|
||||
rb_dlink_list_length(&blacklist_list) > 1 ? "s" : "");
|
||||
rb_free(bluser);
|
||||
set_provider_data(auth, SELF_PID, NULL);
|
||||
set_provider_timeout_absolute(auth, SELF_PID, 0);
|
||||
provider_done(auth, SELF_PID);
|
||||
|
||||
auth_client_unref(auth);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
initiate_blacklist_dnsquery(struct blacklist *bl, struct auth_client *auth)
|
||||
{
|
||||
struct blacklist_lookup *bllookup = (blacklist_lookup *)rb_malloc(sizeof(struct blacklist_lookup));
|
||||
struct blacklist_user *bluser = (blacklist_user *)get_provider_data(auth, SELF_PID);
|
||||
char buf[IRCD_RES_HOSTLEN + 1];
|
||||
int aftype;
|
||||
|
||||
bllookup->bl = bl;
|
||||
bllookup->auth = auth;
|
||||
|
||||
aftype = GET_SS_FAMILY(&auth->c_addr);
|
||||
if((aftype == AF_INET && (bl->iptype & IPTYPE_IPV4) == 0) ||
|
||||
(aftype == AF_INET6 && (bl->iptype & IPTYPE_IPV6) == 0))
|
||||
/* Incorrect blacklist type for this IP... */
|
||||
{
|
||||
rb_free(bllookup);
|
||||
return;
|
||||
}
|
||||
|
||||
build_rdns(buf, sizeof(buf), &auth->c_addr, bl->host);
|
||||
bllookup->query = lookup_ip(buf, AF_INET, blacklist_dns_callback, bllookup);
|
||||
|
||||
rb_dlinkAdd(bllookup, &bllookup->node, &bluser->queries);
|
||||
bl->refcount++;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
lookup_all_blacklists(struct auth_client *auth)
|
||||
{
|
||||
struct blacklist_user *bluser = (blacklist_user *)get_provider_data(auth, SELF_PID);
|
||||
rb_dlink_node *ptr;
|
||||
int iptype;
|
||||
|
||||
if(GET_SS_FAMILY(&auth->c_addr) == AF_INET)
|
||||
iptype = IPTYPE_IPV4;
|
||||
#ifdef RB_IPV6
|
||||
else if(GET_SS_FAMILY(&auth->c_addr) == AF_INET6)
|
||||
iptype = IPTYPE_IPV6;
|
||||
#endif
|
||||
else
|
||||
return false;
|
||||
|
||||
|
||||
notice_client(auth->cid, "*** Checking your IP against DNS blacklist%s",
|
||||
rb_dlink_list_length(&blacklist_list) > 1 ? "s" : "");
|
||||
|
||||
RB_DLINK_FOREACH(ptr, blacklist_list.head)
|
||||
{
|
||||
struct blacklist *bl = (struct blacklist *)ptr->data;
|
||||
|
||||
if (!bl->delete_ && (bl->iptype & iptype))
|
||||
initiate_blacklist_dnsquery(bl, auth);
|
||||
}
|
||||
|
||||
if(!rb_dlink_list_length(&bluser->queries))
|
||||
/* None checked. */
|
||||
return false;
|
||||
|
||||
set_provider_timeout_relative(auth, SELF_PID, blacklist_timeout);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void
|
||||
delete_blacklist(struct blacklist *bl)
|
||||
{
|
||||
if (bl->refcount > 0)
|
||||
bl->delete_ = true;
|
||||
else
|
||||
{
|
||||
rb_dlinkFindDestroy(bl, &blacklist_list);
|
||||
rb_free(bl);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
delete_all_blacklists(void)
|
||||
{
|
||||
rb_dlink_node *ptr, *nptr;
|
||||
|
||||
RB_DLINK_FOREACH_SAFE(ptr, nptr, blacklist_list.head)
|
||||
{
|
||||
delete_blacklist((blacklist *)ptr->data);
|
||||
}
|
||||
}
|
||||
|
||||
/* public interfaces */
|
||||
static bool
|
||||
blacklists_start(struct auth_client *auth)
|
||||
{
|
||||
uint32_t rdns_pid, ident_pid;
|
||||
|
||||
lrb_assert(get_provider_data(auth, SELF_PID) == NULL);
|
||||
|
||||
if(!rb_dlink_list_length(&blacklist_list))
|
||||
/* Nothing to do... */
|
||||
return true;
|
||||
|
||||
auth_client_ref(auth);
|
||||
|
||||
set_provider_data(auth, SELF_PID, rb_malloc(sizeof(struct blacklist_user)));
|
||||
|
||||
if((!get_provider_id("rdns", &rdns_pid) || is_provider_done(auth, rdns_pid)) &&
|
||||
(!get_provider_id("ident", &ident_pid) || is_provider_done(auth, ident_pid)))
|
||||
{
|
||||
/* Start the lookup if ident and rdns are finished, or not loaded. */
|
||||
if(!lookup_all_blacklists(auth))
|
||||
{
|
||||
blacklists_cancel_none(auth);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
set_provider_running(auth, SELF_PID);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* This is called every time a provider is completed as long as we are marked not done */
|
||||
static void
|
||||
blacklists_initiate(struct auth_client *auth, uint32_t provider)
|
||||
{
|
||||
struct blacklist_user *bluser = (blacklist_user *)get_provider_data(auth, SELF_PID);
|
||||
uint32_t rdns_pid, ident_pid;
|
||||
|
||||
lrb_assert(provider != SELF_PID);
|
||||
lrb_assert(!is_provider_done(auth, SELF_PID));
|
||||
lrb_assert(rb_dlink_list_length(&blacklist_list) > 0);
|
||||
|
||||
if(bluser == NULL || rb_dlink_list_length(&bluser->queries))
|
||||
/* Nothing to do */
|
||||
return;
|
||||
else if((!get_provider_id("rdns", &rdns_pid) || is_provider_done(auth, rdns_pid)) &&
|
||||
(!get_provider_id("ident", &ident_pid) || is_provider_done(auth, ident_pid)))
|
||||
{
|
||||
/* Don't start until ident and rdns are finished (or not loaded) */
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!lookup_all_blacklists(auth))
|
||||
blacklists_cancel_none(auth);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
blacklists_generic_cancel(struct auth_client *auth, const char *message)
|
||||
{
|
||||
rb_dlink_node *ptr, *nptr;
|
||||
struct blacklist_user *bluser = (blacklist_user *)get_provider_data(auth, SELF_PID);
|
||||
|
||||
if(bluser == NULL)
|
||||
return;
|
||||
|
||||
if(rb_dlink_list_length(&bluser->queries))
|
||||
{
|
||||
notice_client(auth->cid, message);
|
||||
|
||||
RB_DLINK_FOREACH_SAFE(ptr, nptr, bluser->queries.head)
|
||||
{
|
||||
struct blacklist_lookup *bllookup = (blacklist_lookup *)ptr->data;
|
||||
|
||||
cancel_query(bllookup->query);
|
||||
unref_blacklist(bllookup->bl);
|
||||
|
||||
rb_dlinkDelete(&bllookup->node, &bluser->queries);
|
||||
rb_free(bllookup);
|
||||
}
|
||||
}
|
||||
|
||||
rb_free(bluser);
|
||||
set_provider_data(auth, SELF_PID, NULL);
|
||||
set_provider_timeout_absolute(auth, SELF_PID, 0);
|
||||
provider_done(auth, SELF_PID);
|
||||
|
||||
auth_client_unref(auth);
|
||||
}
|
||||
|
||||
static void
|
||||
blacklists_timeout(struct auth_client *auth)
|
||||
{
|
||||
blacklists_generic_cancel(auth, "*** No response from DNS blacklists");
|
||||
}
|
||||
|
||||
static void
|
||||
blacklists_cancel(struct auth_client *auth)
|
||||
{
|
||||
blacklists_generic_cancel(auth, "*** Aborting DNS blacklist checks");
|
||||
}
|
||||
|
||||
static void
|
||||
blacklists_cancel_none(struct auth_client *auth)
|
||||
{
|
||||
blacklists_generic_cancel(auth, "*** Could not check DNS blacklists");
|
||||
}
|
||||
|
||||
static void
|
||||
blacklists_destroy(void)
|
||||
{
|
||||
rb_dictionary_iter iter;
|
||||
struct auth_client *auth;
|
||||
|
||||
void *elem;
|
||||
RB_DICTIONARY_FOREACH(elem, &iter, auth_clients)
|
||||
{
|
||||
auth = (auth_client *)elem;
|
||||
blacklists_cancel(auth);
|
||||
/* auth is now invalid as we have no reference */
|
||||
}
|
||||
|
||||
delete_all_blacklists();
|
||||
}
|
||||
|
||||
static void
|
||||
add_conf_blacklist(const char *key, int parc, const char **parv)
|
||||
{
|
||||
rb_dlink_list filters = { NULL, NULL, 0 };
|
||||
char *tmp, *elemlist = rb_strdup(parv[2]);
|
||||
uint8_t iptype;
|
||||
|
||||
if(*elemlist == '*')
|
||||
goto end;
|
||||
|
||||
for(char *elem = rb_strtok_r(elemlist, ",", &tmp); elem; elem = rb_strtok_r(NULL, ",", &tmp))
|
||||
{
|
||||
struct blacklist_filter *filter = (blacklist_filter *)rb_malloc(sizeof(struct blacklist_filter));
|
||||
int dot_c = 0;
|
||||
filter_t type = FILTER_LAST;
|
||||
|
||||
/* Check blacklist filter type and for validity */
|
||||
for(char *c = elem; *c != '\0'; c++)
|
||||
{
|
||||
if(*c == '.')
|
||||
{
|
||||
if(++dot_c > 3)
|
||||
{
|
||||
warn_opers(L_CRIT, "Blacklist: addr_conf_blacklist got a bad filter (too many octets)");
|
||||
exit(EX_PROVIDER_ERROR);
|
||||
}
|
||||
|
||||
type = FILTER_ALL;
|
||||
}
|
||||
else if(!isdigit(*c))
|
||||
{
|
||||
warn_opers(L_CRIT, "Blacklist: addr_conf_blacklist got a bad filter (invalid character in blacklist filter: %c)",
|
||||
*c);
|
||||
exit(EX_PROVIDER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
if(dot_c > 0 && dot_c < 3)
|
||||
{
|
||||
warn_opers(L_CRIT, "Blacklist: addr_conf_blacklist got a bad filter (insufficient octets)");
|
||||
exit(EX_PROVIDER_ERROR);
|
||||
}
|
||||
|
||||
filter->type = type;
|
||||
rb_strlcpy(filter->filter, elem, sizeof(filter->filter));
|
||||
rb_dlinkAdd(filter, &filter->node, &filters);
|
||||
}
|
||||
|
||||
end:
|
||||
rb_free(elemlist);
|
||||
|
||||
iptype = atoi(parv[1]) & 0x3;
|
||||
if(new_blacklist(parv[0], parv[3], iptype, &filters) == NULL)
|
||||
{
|
||||
warn_opers(L_CRIT, "Blacklist: addr_conf_blacklist got a malformed blacklist");
|
||||
exit(EX_PROVIDER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
del_conf_blacklist(const char *key, int parc, const char **parv)
|
||||
{
|
||||
struct blacklist *bl = find_blacklist(parv[0]);
|
||||
if(bl == NULL)
|
||||
{
|
||||
/* Not fatal for now... */
|
||||
warn_opers(L_WARN, "Blacklist: tried to remove nonexistent blacklist %s", parv[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
delete_blacklist(bl);
|
||||
}
|
||||
|
||||
static void
|
||||
del_conf_blacklist_all(const char *key, int parc, const char **parv)
|
||||
{
|
||||
delete_all_blacklists();
|
||||
}
|
||||
|
||||
static void
|
||||
add_conf_blacklist_timeout(const char *key, int parc, const char **parv)
|
||||
{
|
||||
int timeout = atoi(parv[0]);
|
||||
|
||||
if(timeout < 0)
|
||||
{
|
||||
warn_opers(L_CRIT, "Blacklist: blacklist timeout < 0 (value: %d)", timeout);
|
||||
exit(EX_PROVIDER_ERROR);
|
||||
}
|
||||
|
||||
blacklist_timeout = timeout;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
blacklist_stats(uint32_t rid, char letter)
|
||||
{
|
||||
rb_dlink_node *ptr;
|
||||
|
||||
RB_DLINK_FOREACH(ptr, blacklist_list.head)
|
||||
{
|
||||
struct blacklist *bl = (blacklist *)ptr->data;
|
||||
|
||||
if(bl->delete)
|
||||
continue;
|
||||
|
||||
stats_result(rid, letter, "%s %hhu %u", bl->host, bl->iptype, bl->hits);
|
||||
}
|
||||
|
||||
stats_done(rid, letter);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct auth_opts_handler blacklist_options[] =
|
||||
{
|
||||
{ "rbl", 4, add_conf_blacklist },
|
||||
{ "rbl_del", 1, del_conf_blacklist },
|
||||
{ "rbl_del_all", 0, del_conf_blacklist_all },
|
||||
{ "rbl_timeout", 1, add_conf_blacklist_timeout },
|
||||
{ NULL, 0, NULL },
|
||||
};
|
||||
|
||||
struct auth_provider blacklist_provider =
|
||||
[]{
|
||||
auth_provider ret {0};
|
||||
ret.name = "blacklist";
|
||||
ret.letter = 'B';
|
||||
ret.destroy = blacklists_destroy;
|
||||
ret.start = blacklists_start;
|
||||
ret.cancel = blacklists_cancel;
|
||||
ret.timeout = blacklists_timeout;
|
||||
ret.completed = blacklists_initiate;
|
||||
ret.opt_handlers = blacklist_options;
|
||||
/* .stats_handler = { 'B', blacklist_stats }, */
|
||||
return ret;
|
||||
}();
|
|
@ -1,391 +0,0 @@
|
|||
/* authd/providers/ident.c - ident lookup provider for authd
|
||||
* Copyright (c) 2016 Elizabeth Myers <elizabeth@interlinked.me>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Largely adapted from old s_auth.c, but reworked for authd. rDNS code
|
||||
* moved to its own provider.
|
||||
*
|
||||
* --Elizafox 13 March 2016
|
||||
*/
|
||||
|
||||
#include "authd.h"
|
||||
#include "notice.h"
|
||||
#include "provider.h"
|
||||
#include "res.h"
|
||||
|
||||
using namespace ircd::defaults;
|
||||
|
||||
#define SELF_PID (ident_provider.id)
|
||||
|
||||
#define IDENT_BUFSIZE 128
|
||||
|
||||
struct ident_query
|
||||
{
|
||||
rb_fde_t *F; /* Our FD */
|
||||
};
|
||||
|
||||
/* Goinked from old s_auth.c --Elizafox */
|
||||
static const char *messages[] =
|
||||
{
|
||||
"*** Checking Ident",
|
||||
"*** Got Ident response",
|
||||
"*** No Ident response",
|
||||
"*** Cannot verify ident validity, ignoring ident",
|
||||
"*** Ident disabled, not checking ident",
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
REPORT_LOOKUP,
|
||||
REPORT_FOUND,
|
||||
REPORT_FAIL,
|
||||
REPORT_INVALID,
|
||||
REPORT_DISABLED,
|
||||
} ident_message;
|
||||
|
||||
static CNCB ident_connected;
|
||||
static PF read_ident_reply;
|
||||
|
||||
static void client_fail(struct auth_client *auth, ident_message message);
|
||||
static void client_success(struct auth_client *auth);
|
||||
static char * get_valid_ident(char *buf);
|
||||
|
||||
static int ident_timeout = IDENT_TIMEOUT_DEFAULT;
|
||||
static bool ident_enable = true;
|
||||
|
||||
|
||||
/*
|
||||
* ident_connected() - deal with the result of rb_connect_tcp()
|
||||
*
|
||||
* If the connection failed, we simply close the auth fd and report
|
||||
* a failure. If the connection suceeded send the ident server a query
|
||||
* giving "theirport , ourport". The write is only attempted *once* so
|
||||
* it is deemed to be a fail if the entire write doesn't write all the
|
||||
* data given. This shouldnt be a problem since the socket should have
|
||||
* a write buffer far greater than this message to store it in should
|
||||
* problems arise. -avalon
|
||||
*/
|
||||
static void
|
||||
ident_connected(rb_fde_t *F, int error, void *data)
|
||||
{
|
||||
struct auth_client *auth = (auth_client *)data;
|
||||
struct ident_query *query;
|
||||
char authbuf[32];
|
||||
int authlen;
|
||||
|
||||
lrb_assert(auth != NULL);
|
||||
query = (ident_query *)get_provider_data(auth, SELF_PID);
|
||||
lrb_assert(query != NULL);
|
||||
|
||||
/* Check the error */
|
||||
if(error != RB_OK)
|
||||
{
|
||||
/* We had an error during connection :( */
|
||||
client_fail(auth, REPORT_FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(authbuf, sizeof(authbuf), "%u , %u\r\n",
|
||||
auth->c_port, auth->l_port);
|
||||
authlen = strlen(authbuf);
|
||||
|
||||
if(rb_write(query->F, authbuf, authlen) != authlen)
|
||||
{
|
||||
client_fail(auth, REPORT_FAIL);
|
||||
return;
|
||||
}
|
||||
|
||||
read_ident_reply(query->F, auth);
|
||||
}
|
||||
|
||||
static void
|
||||
read_ident_reply(rb_fde_t *F, void *data)
|
||||
{
|
||||
struct auth_client *auth = (auth_client *)data;
|
||||
struct ident_query *query;
|
||||
char buf[IDENT_BUFSIZE + 1]; /* buffer to read auth reply into */
|
||||
ident_message message = REPORT_FAIL;
|
||||
char *s = NULL;
|
||||
char *t = NULL;
|
||||
ssize_t len;
|
||||
int count;
|
||||
|
||||
lrb_assert(auth != NULL);
|
||||
query = (ident_query *)get_provider_data(auth, SELF_PID);
|
||||
lrb_assert(query != NULL);
|
||||
|
||||
len = rb_read(F, buf, IDENT_BUFSIZE);
|
||||
if(len < 0 && rb_ignore_errno(errno))
|
||||
{
|
||||
rb_setselect(F, RB_SELECT_READ, read_ident_reply, auth);
|
||||
return;
|
||||
}
|
||||
|
||||
if(len > 0)
|
||||
{
|
||||
if((s = get_valid_ident(buf)) != NULL)
|
||||
{
|
||||
t = auth->username;
|
||||
|
||||
while (*s == '~' || *s == '^')
|
||||
s++;
|
||||
|
||||
for (count = USERLEN; *s && count; s++)
|
||||
{
|
||||
if(*s == '@' || *s == '\r' || *s == '\n')
|
||||
break;
|
||||
|
||||
if(*s != ' ' && *s != ':' && *s != '[')
|
||||
{
|
||||
*t++ = *s;
|
||||
count--;
|
||||
}
|
||||
}
|
||||
*t = '\0';
|
||||
}
|
||||
else
|
||||
message = REPORT_INVALID;
|
||||
}
|
||||
|
||||
if(s == NULL)
|
||||
client_fail(auth, message);
|
||||
else
|
||||
client_success(auth);
|
||||
}
|
||||
|
||||
static void
|
||||
client_fail(struct auth_client *auth, ident_message report)
|
||||
{
|
||||
struct ident_query *query = (ident_query *)get_provider_data(auth, SELF_PID);
|
||||
|
||||
lrb_assert(query != NULL);
|
||||
|
||||
rb_strlcpy(auth->username, "*", sizeof(auth->username));
|
||||
|
||||
if(query->F != NULL)
|
||||
rb_close(query->F);
|
||||
|
||||
rb_free(query);
|
||||
set_provider_data(auth, SELF_PID, NULL);
|
||||
set_provider_timeout_absolute(auth, SELF_PID, 0);
|
||||
|
||||
notice_client(auth->cid, messages[report]);
|
||||
provider_done(auth, SELF_PID);
|
||||
|
||||
auth_client_unref(auth);
|
||||
}
|
||||
|
||||
static void
|
||||
client_success(struct auth_client *auth)
|
||||
{
|
||||
struct ident_query *query = (ident_query *)get_provider_data(auth, SELF_PID);
|
||||
|
||||
lrb_assert(query != NULL);
|
||||
|
||||
if(query->F != NULL)
|
||||
rb_close(query->F);
|
||||
|
||||
rb_free(query);
|
||||
set_provider_data(auth, SELF_PID, NULL);
|
||||
set_provider_timeout_absolute(auth, SELF_PID, 0);
|
||||
|
||||
notice_client(auth->cid, messages[REPORT_FOUND]);
|
||||
provider_done(auth, SELF_PID);
|
||||
|
||||
auth_client_unref(auth);
|
||||
}
|
||||
|
||||
/* get_valid_ident
|
||||
* parse ident query reply from identd server
|
||||
*
|
||||
* Taken from old s_auth.c --Elizafox
|
||||
*
|
||||
* Inputs - pointer to ident buf
|
||||
* Outputs - NULL if no valid ident found, otherwise pointer to name
|
||||
* Side effects - None
|
||||
*/
|
||||
static char *
|
||||
get_valid_ident(char *buf)
|
||||
{
|
||||
int remp = 0;
|
||||
int locp = 0;
|
||||
char *colon1Ptr;
|
||||
char *colon2Ptr;
|
||||
char *colon3Ptr;
|
||||
char *commaPtr;
|
||||
char *remotePortString;
|
||||
|
||||
/* All this to get rid of a sscanf() fun. */
|
||||
remotePortString = buf;
|
||||
|
||||
colon1Ptr = strchr(remotePortString, ':');
|
||||
if(!colon1Ptr)
|
||||
return NULL;
|
||||
|
||||
*colon1Ptr = '\0';
|
||||
colon1Ptr++;
|
||||
colon2Ptr = strchr(colon1Ptr, ':');
|
||||
if(!colon2Ptr)
|
||||
return NULL;
|
||||
|
||||
*colon2Ptr = '\0';
|
||||
colon2Ptr++;
|
||||
commaPtr = strchr(remotePortString, ',');
|
||||
|
||||
if(!commaPtr)
|
||||
return NULL;
|
||||
|
||||
*commaPtr = '\0';
|
||||
commaPtr++;
|
||||
|
||||
remp = atoi(remotePortString);
|
||||
if(!remp)
|
||||
return NULL;
|
||||
|
||||
locp = atoi(commaPtr);
|
||||
if(!locp)
|
||||
return NULL;
|
||||
|
||||
/* look for USERID bordered by first pair of colons */
|
||||
if(!strstr(colon1Ptr, "USERID"))
|
||||
return NULL;
|
||||
|
||||
colon3Ptr = strchr(colon2Ptr, ':');
|
||||
if(!colon3Ptr)
|
||||
return NULL;
|
||||
|
||||
*colon3Ptr = '\0';
|
||||
colon3Ptr++;
|
||||
return (colon3Ptr);
|
||||
}
|
||||
|
||||
static void
|
||||
ident_destroy(void)
|
||||
{
|
||||
struct auth_client *auth;
|
||||
rb_dictionary_iter iter;
|
||||
|
||||
/* Nuke all ident queries */
|
||||
void *elem;
|
||||
RB_DICTIONARY_FOREACH(elem, &iter, auth_clients)
|
||||
{
|
||||
auth = (auth_client *)elem;
|
||||
if(get_provider_data(auth, SELF_PID) != NULL)
|
||||
client_fail(auth, REPORT_FAIL);
|
||||
/* auth is now invalid as we have no reference */
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
ident_start(struct auth_client *auth)
|
||||
{
|
||||
struct ident_query *query = (ident_query *)rb_malloc(sizeof(struct ident_query));
|
||||
struct rb_sockaddr_storage l_addr, c_addr;
|
||||
int family = GET_SS_FAMILY(&auth->c_addr);
|
||||
|
||||
lrb_assert(get_provider_data(auth, SELF_PID) == NULL);
|
||||
|
||||
if(!ident_enable)
|
||||
{
|
||||
rb_free(query);
|
||||
notice_client(auth->cid, messages[REPORT_DISABLED]);
|
||||
set_provider_done(auth, SELF_PID);
|
||||
return true;
|
||||
}
|
||||
|
||||
auth_client_ref(auth);
|
||||
|
||||
notice_client(auth->cid, messages[REPORT_LOOKUP]);
|
||||
|
||||
set_provider_data(auth, SELF_PID, query);
|
||||
set_provider_timeout_relative(auth, SELF_PID, ident_timeout);
|
||||
|
||||
if((query->F = rb_socket(family, SOCK_STREAM, 0, "ident")) == NULL)
|
||||
{
|
||||
warn_opers(L_DEBUG, "Could not create ident socket: %s", strerror(errno));
|
||||
client_fail(auth, REPORT_FAIL);
|
||||
return true; /* Not a fatal error */
|
||||
}
|
||||
|
||||
/* Build sockaddr_storages for rb_connect_tcp below */
|
||||
l_addr = auth->l_addr;
|
||||
c_addr = auth->c_addr;
|
||||
|
||||
SET_SS_PORT(&l_addr, 0);
|
||||
SET_SS_PORT(&c_addr, htons(113));
|
||||
|
||||
rb_connect_tcp(query->F, (struct sockaddr *)&c_addr,
|
||||
(struct sockaddr *)&l_addr,
|
||||
ident_connected,
|
||||
auth, ident_timeout);
|
||||
|
||||
set_provider_running(auth, SELF_PID);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
ident_cancel(struct auth_client *auth)
|
||||
{
|
||||
struct ident_query *query = (ident_query *)get_provider_data(auth, SELF_PID);
|
||||
|
||||
if(query != NULL)
|
||||
client_fail(auth, REPORT_FAIL);
|
||||
}
|
||||
|
||||
static void
|
||||
add_conf_ident_timeout(const char *key, int parc, const char **parv)
|
||||
{
|
||||
int timeout = atoi(parv[0]);
|
||||
|
||||
if(timeout < 0)
|
||||
{
|
||||
warn_opers(L_CRIT, "Ident: ident timeout < 0 (value: %d)", timeout);
|
||||
exit(EX_PROVIDER_ERROR);
|
||||
}
|
||||
|
||||
ident_timeout = timeout;
|
||||
}
|
||||
|
||||
static void
|
||||
set_ident_enabled(const char *key, int parc, const char **parv)
|
||||
{
|
||||
ident_enable = (*parv[0] == '1');
|
||||
}
|
||||
|
||||
struct auth_opts_handler ident_options[] =
|
||||
{
|
||||
{ "ident_timeout", 1, add_conf_ident_timeout },
|
||||
{ "ident_enabled", 1, set_ident_enabled },
|
||||
{ NULL, 0, NULL },
|
||||
};
|
||||
|
||||
|
||||
struct auth_provider ident_provider =
|
||||
[]{
|
||||
auth_provider ap {0};
|
||||
ap.name = "ident";
|
||||
ap.letter = 'I';
|
||||
ap.start = ident_start;
|
||||
ap.destroy = ident_destroy;
|
||||
ap.cancel = ident_cancel;
|
||||
ap.timeout = ident_cancel;
|
||||
ap.opt_handlers = ident_options;
|
||||
return ap;
|
||||
}();
|
|
@ -1,957 +0,0 @@
|
|||
/* authd/providers/opm.c - small open proxy monitor
|
||||
* Copyright (c) 2016 Elizabeth Myers <elizabeth@interlinked.me>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "authd.h"
|
||||
#include "notice.h"
|
||||
#include "provider.h"
|
||||
|
||||
using namespace ircd::defaults;
|
||||
|
||||
#define SELF_PID (opm_provider.id)
|
||||
|
||||
#define OPM_READSIZE 128
|
||||
|
||||
typedef enum protocol_t
|
||||
{
|
||||
PROTO_NONE,
|
||||
PROTO_SOCKS4,
|
||||
PROTO_SOCKS5,
|
||||
PROTO_HTTP_CONNECT,
|
||||
PROTO_HTTPS_CONNECT,
|
||||
} protocol_t;
|
||||
|
||||
/* Lookup data associated with auth client */
|
||||
struct opm_lookup
|
||||
{
|
||||
rb_dlink_list scans; /* List of scans */
|
||||
bool in_progress;
|
||||
};
|
||||
|
||||
struct opm_scan;
|
||||
typedef void (*opm_callback_t)(struct opm_scan *);
|
||||
|
||||
/* A proxy scanner */
|
||||
struct opm_proxy
|
||||
{
|
||||
char note[16];
|
||||
protocol_t proto;
|
||||
uint16_t port;
|
||||
bool ssl; /* Connect to proxy with SSL */
|
||||
bool ipv6; /* Proxy supports IPv6 */
|
||||
|
||||
opm_callback_t callback;
|
||||
|
||||
rb_dlink_node node;
|
||||
};
|
||||
|
||||
/* A listener for proxy replies */
|
||||
struct opm_listener
|
||||
{
|
||||
char ip[HOSTIPLEN];
|
||||
uint16_t port;
|
||||
struct rb_sockaddr_storage addr;
|
||||
rb_fde_t *F;
|
||||
};
|
||||
|
||||
/* An individual proxy scan */
|
||||
struct opm_scan
|
||||
{
|
||||
struct auth_client *auth;
|
||||
rb_fde_t *F; /* fd for scan */
|
||||
|
||||
struct opm_proxy *proxy; /* Associated proxy */
|
||||
struct opm_listener *listener; /* Associated listener */
|
||||
|
||||
rb_dlink_node node;
|
||||
};
|
||||
|
||||
/* Proxies that we scan for */
|
||||
static rb_dlink_list proxy_scanners;
|
||||
|
||||
static ACCB accept_opm;
|
||||
static PF read_opm_reply;
|
||||
|
||||
static CNCB opm_connected;
|
||||
|
||||
static void opm_cancel(struct auth_client *auth);
|
||||
static bool create_listener(const char *ip, uint16_t port);
|
||||
|
||||
static int opm_timeout = OPM_TIMEOUT_DEFAULT;
|
||||
static bool opm_enable = false;
|
||||
|
||||
enum
|
||||
{
|
||||
LISTEN_IPV4,
|
||||
LISTEN_IPV6,
|
||||
LISTEN_LAST,
|
||||
};
|
||||
|
||||
/* IPv4 and IPv6 */
|
||||
static struct opm_listener listeners[LISTEN_LAST];
|
||||
|
||||
static inline protocol_t
|
||||
get_protocol_from_string(const char *str)
|
||||
{
|
||||
if(strcasecmp(str, "socks4") == 0)
|
||||
return PROTO_SOCKS4;
|
||||
else if(strcasecmp(str, "socks5") == 0)
|
||||
return PROTO_SOCKS5;
|
||||
else if(strcasecmp(str, "httpconnect") == 0)
|
||||
return PROTO_HTTP_CONNECT;
|
||||
else if(strcasecmp(str, "httpsconnect") == 0)
|
||||
return PROTO_HTTPS_CONNECT;
|
||||
else
|
||||
return PROTO_NONE;
|
||||
}
|
||||
|
||||
static inline struct opm_proxy *
|
||||
find_proxy_scanner(protocol_t proto, uint16_t port)
|
||||
{
|
||||
rb_dlink_node *ptr;
|
||||
|
||||
RB_DLINK_FOREACH(ptr, proxy_scanners.head)
|
||||
{
|
||||
struct opm_proxy *proxy = (opm_proxy *)ptr->data;
|
||||
|
||||
if(proxy->proto == proto && proxy->port == port)
|
||||
return proxy;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* This is called when an open proxy connects to us */
|
||||
static void
|
||||
read_opm_reply(rb_fde_t *F, void *data)
|
||||
{
|
||||
rb_dlink_node *ptr;
|
||||
struct auth_client *auth = (auth_client *)data;
|
||||
struct opm_lookup *lookup;
|
||||
char readbuf[OPM_READSIZE];
|
||||
ssize_t len;
|
||||
|
||||
lrb_assert(auth != NULL);
|
||||
lookup = (opm_lookup *)get_provider_data(auth, SELF_PID);
|
||||
lrb_assert(lookup != NULL);
|
||||
|
||||
if((len = rb_read(F, readbuf, sizeof(readbuf))) < 0 && rb_ignore_errno(errno))
|
||||
{
|
||||
rb_setselect(F, RB_SELECT_READ, read_opm_reply, auth);
|
||||
return;
|
||||
}
|
||||
else if(len <= 0)
|
||||
{
|
||||
/* Dead */
|
||||
rb_close(F);
|
||||
return;
|
||||
}
|
||||
|
||||
RB_DLINK_FOREACH(ptr, proxy_scanners.head)
|
||||
{
|
||||
struct opm_proxy *proxy = (opm_proxy *)ptr->data;
|
||||
|
||||
if(strncmp(proxy->note, readbuf, strlen(proxy->note)) == 0)
|
||||
{
|
||||
rb_dlink_node *ptr, *nptr;
|
||||
|
||||
/* Cancel outstanding lookups */
|
||||
RB_DLINK_FOREACH_SAFE(ptr, nptr, lookup->scans.head)
|
||||
{
|
||||
struct opm_scan *scan = (opm_scan *)ptr->data;
|
||||
|
||||
rb_close(scan->F);
|
||||
rb_free(scan);
|
||||
}
|
||||
|
||||
/* No longer needed, client is going away */
|
||||
rb_free(lookup);
|
||||
|
||||
reject_client(auth, SELF_PID, readbuf, "Open proxy detected");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rb_close(F);
|
||||
}
|
||||
|
||||
static void
|
||||
accept_opm(rb_fde_t *F, int status, struct sockaddr *addr, rb_socklen_t len, void *data)
|
||||
{
|
||||
struct auth_client *auth = NULL;
|
||||
struct opm_listener *listener = (opm_listener *)data;
|
||||
struct rb_sockaddr_storage localaddr;
|
||||
rb_socklen_t llen = sizeof(struct rb_sockaddr_storage);
|
||||
rb_dictionary_iter iter;
|
||||
|
||||
if(status != 0 || listener == NULL)
|
||||
{
|
||||
rb_close(F);
|
||||
return;
|
||||
}
|
||||
|
||||
if(getsockname(rb_get_fd(F), (struct sockaddr *)&localaddr, &llen))
|
||||
{
|
||||
/* This can happen if the client goes away after accept */
|
||||
rb_close(F);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Correlate connection with client(s) */
|
||||
void *elem;
|
||||
RB_DICTIONARY_FOREACH(elem, &iter, auth_clients)
|
||||
{
|
||||
auth = (auth_client *)elem;
|
||||
if(GET_SS_FAMILY(&auth->c_addr) != GET_SS_FAMILY(&localaddr))
|
||||
continue;
|
||||
|
||||
/* Compare the addresses */
|
||||
switch(GET_SS_FAMILY(&localaddr))
|
||||
{
|
||||
case AF_INET:
|
||||
{
|
||||
struct sockaddr_in *s = (struct sockaddr_in *)&localaddr, *c = (struct sockaddr_in *)&auth->c_addr;
|
||||
|
||||
if(s->sin_addr.s_addr == c->sin_addr.s_addr)
|
||||
{
|
||||
/* Match... check if it's real */
|
||||
rb_setselect(F, RB_SELECT_READ, read_opm_reply, auth);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#ifdef RB_IPV6
|
||||
case AF_INET6:
|
||||
{
|
||||
struct sockaddr_in6 *s = (struct sockaddr_in6 *)&localaddr, *c = (struct sockaddr_in6 *)&auth->c_addr;
|
||||
|
||||
if(IN6_ARE_ADDR_EQUAL(&s->sin6_addr, &c->sin6_addr))
|
||||
{
|
||||
rb_setselect(F, RB_SELECT_READ, read_opm_reply, auth);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
warn_opers(L_CRIT, "OPM: unknown address type in listen function");
|
||||
exit(EX_PROVIDER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/* We don't care about the socket if we get here */
|
||||
rb_close(F);
|
||||
}
|
||||
|
||||
/* Scanners */
|
||||
|
||||
static void
|
||||
opm_connected(rb_fde_t *F, int error, void *data)
|
||||
{
|
||||
struct opm_scan *scan = (opm_scan *)data;
|
||||
struct opm_proxy *proxy = scan->proxy;
|
||||
struct auth_client *auth = scan->auth;
|
||||
struct opm_lookup *lookup = (opm_lookup *)get_provider_data(auth, SELF_PID);
|
||||
|
||||
if(error || !opm_enable)
|
||||
{
|
||||
//notice_client(scan->auth->cid, "*** Scan not connected: %s", proxy->note);
|
||||
goto end;
|
||||
}
|
||||
|
||||
switch(GET_SS_FAMILY(&auth->c_addr))
|
||||
{
|
||||
case AF_INET:
|
||||
if(listeners[LISTEN_IPV4].F == NULL)
|
||||
/* They cannot respond to us */
|
||||
goto end;
|
||||
|
||||
break;
|
||||
#ifdef RB_IPV6
|
||||
case AF_INET6:
|
||||
if(!proxy->ipv6)
|
||||
/* Welp, too bad */
|
||||
goto end;
|
||||
|
||||
if(listeners[LISTEN_IPV6].F == NULL)
|
||||
/* They cannot respond to us */
|
||||
goto end;
|
||||
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
goto end;
|
||||
}
|
||||
|
||||
proxy->callback(scan);
|
||||
|
||||
end:
|
||||
rb_close(scan->F);
|
||||
rb_dlinkDelete(&scan->node, &lookup->scans);
|
||||
rb_free(scan);
|
||||
}
|
||||
|
||||
static void
|
||||
socks4_connected(struct opm_scan *scan)
|
||||
{
|
||||
struct auth_client *auth = scan->auth;
|
||||
struct opm_lookup *lookup = (opm_lookup *)get_provider_data(auth, SELF_PID);
|
||||
uint8_t sendbuf[9]; /* Size we're building */
|
||||
uint8_t *c = sendbuf;
|
||||
|
||||
memcpy(c, "\x04\x01", 2); c += 2; /* Socks version 4, connect command */
|
||||
memcpy(c, &(((struct sockaddr_in *)&scan->listener->addr)->sin_port), 2); c += 2; /* Port */
|
||||
memcpy(c, &(((struct sockaddr_in *)&scan->listener->addr)->sin_addr.s_addr), 4); c += 4; /* Address */
|
||||
*c = '\x00'; /* No userid */
|
||||
|
||||
/* Send header */
|
||||
if(rb_write(scan->F, sendbuf, sizeof(sendbuf)) < 0)
|
||||
return;
|
||||
|
||||
/* Send note */
|
||||
if(rb_write(scan->F, scan->proxy->note, strlen(scan->proxy->note) + 1) < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
socks5_connected(struct opm_scan *scan)
|
||||
{
|
||||
struct auth_client *auth = scan->auth;
|
||||
struct opm_lookup *lookup = (opm_lookup *)get_provider_data(auth, SELF_PID);
|
||||
uint8_t sendbuf[25]; /* Size we're building */
|
||||
uint8_t *c = sendbuf;
|
||||
|
||||
auth = scan->auth;
|
||||
lookup = (opm_lookup *)get_provider_data(auth, SELF_PID);
|
||||
|
||||
/* Build the version header and socks request
|
||||
* version header (3 bytes): version, number of auth methods, auth type (0 for none)
|
||||
* connect req (3 bytes): version, command (1 = connect), reserved (0)
|
||||
*/
|
||||
memcpy(c, "\x05\x01\x00\x05\x01\x00", 6); c += 6;
|
||||
|
||||
switch(GET_SS_FAMILY(&auth->c_addr))
|
||||
{
|
||||
case AF_INET:
|
||||
*(c++) = '\x01'; /* Address type (1 = IPv4) */
|
||||
memcpy(c, &(((struct sockaddr_in *)&scan->listener->addr)->sin_addr.s_addr), 4); c += 4; /* Address */
|
||||
memcpy(c, &(((struct sockaddr_in *)&scan->listener->addr)->sin_port), 2); c += 2; /* Port */
|
||||
break;
|
||||
#ifdef RB_IPV6
|
||||
case AF_INET6:
|
||||
*(c++) = '\x04'; /* Address type (4 = IPv6) */
|
||||
memcpy(c, ((struct sockaddr_in6 *)&scan->listener->addr)->sin6_addr.s6_addr, 16); c += 16; /* Address */
|
||||
memcpy(c, &(((struct sockaddr_in6 *)&scan->listener->addr)->sin6_port), 2); c += 2; /* Port */
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
/* Send header */
|
||||
if(rb_write(scan->F, sendbuf, (size_t)(sendbuf - c)) <= 0)
|
||||
return;
|
||||
|
||||
/* Now the note in a separate write */
|
||||
if(rb_write(scan->F, scan->proxy->note, strlen(scan->proxy->note) + 1) <= 0)
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
http_connect_connected(struct opm_scan *scan)
|
||||
{
|
||||
struct auth_client *auth = scan->auth;
|
||||
struct opm_lookup *lookup = (opm_lookup *)get_provider_data(auth, SELF_PID);
|
||||
char sendbuf[128]; /* A bit bigger than we need but better safe than sorry */
|
||||
char *c = sendbuf;
|
||||
|
||||
/* Simple enough to build */
|
||||
snprintf(sendbuf, sizeof(sendbuf), "CONNECT %s:%hu HTTP/1.0\r\n\r\n", scan->listener->ip, scan->listener->port);
|
||||
|
||||
/* Send request */
|
||||
if(rb_write(scan->F, sendbuf, strlen(sendbuf)) <= 0)
|
||||
return;
|
||||
|
||||
/* Now the note in a separate write */
|
||||
if(rb_write(scan->F, scan->proxy->note, strlen(scan->proxy->note) + 1) <= 0)
|
||||
return;
|
||||
|
||||
/* MiroTik needs this, and as a separate write */
|
||||
if(rb_write(scan->F, "\r\n", 2) <= 0)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Establish connections */
|
||||
static inline void
|
||||
establish_connection(struct auth_client *auth, struct opm_proxy *proxy)
|
||||
{
|
||||
struct opm_lookup *lookup = (opm_lookup *)get_provider_data(auth, SELF_PID);
|
||||
struct opm_scan *scan = (opm_scan *)rb_malloc(sizeof(struct opm_scan));
|
||||
struct opm_listener *listener;
|
||||
struct rb_sockaddr_storage c_a, l_a;
|
||||
int opt = 1;
|
||||
|
||||
lrb_assert(lookup != NULL);
|
||||
|
||||
#ifdef RB_IPV6
|
||||
if(GET_SS_FAMILY(&auth->c_addr) == AF_INET6)
|
||||
{
|
||||
if(proxy->proto == PROTO_SOCKS4)
|
||||
{
|
||||
/* SOCKS4 doesn't support IPv6 */
|
||||
rb_free(scan);
|
||||
return;
|
||||
}
|
||||
listener = &listeners[LISTEN_IPV6];
|
||||
}
|
||||
else
|
||||
#endif
|
||||
listener = &listeners[LISTEN_IPV4];
|
||||
|
||||
if(listener->F == NULL)
|
||||
{
|
||||
/* We can't respond */
|
||||
rb_free(scan);
|
||||
return;
|
||||
}
|
||||
|
||||
c_a = auth->c_addr; /* Client */
|
||||
l_a = listener->addr; /* Listener (connect using its IP) */
|
||||
|
||||
scan->auth = auth;
|
||||
scan->proxy = proxy;
|
||||
scan->listener = listener;
|
||||
if((scan->F = rb_socket(GET_SS_FAMILY(&auth->c_addr), SOCK_STREAM, 0, proxy->note)) == NULL)
|
||||
{
|
||||
warn_opers(L_WARN, "OPM: could not create OPM socket (proto %s): %s", proxy->note, strerror(errno));
|
||||
rb_free(scan);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Disable Nagle's algorithim - buffering could affect scans */
|
||||
(void)setsockopt(rb_get_fd(scan->F), IPPROTO_TCP, TCP_NODELAY, (char *)&opt, sizeof(opt));
|
||||
|
||||
SET_SS_PORT(&l_a, 0);
|
||||
SET_SS_PORT(&c_a, htons(proxy->port));
|
||||
|
||||
rb_dlinkAdd(scan, &scan->node, &lookup->scans);
|
||||
|
||||
if(!proxy->ssl)
|
||||
rb_connect_tcp(scan->F,
|
||||
(struct sockaddr *)&c_a,
|
||||
(struct sockaddr *)&l_a,
|
||||
opm_connected, scan, opm_timeout);
|
||||
else
|
||||
rb_connect_tcp_ssl(scan->F,
|
||||
(struct sockaddr *)&c_a,
|
||||
(struct sockaddr *)&l_a,
|
||||
opm_connected, scan, opm_timeout);
|
||||
}
|
||||
|
||||
static bool
|
||||
create_listener(const char *ip, uint16_t port)
|
||||
{
|
||||
struct auth_client *auth;
|
||||
struct opm_listener *listener;
|
||||
struct rb_sockaddr_storage addr;
|
||||
rb_dictionary_iter iter;
|
||||
rb_fde_t *F;
|
||||
int opt = 1;
|
||||
|
||||
if(!rb_inet_pton_sock(ip, (struct sockaddr *)&addr))
|
||||
{
|
||||
warn_opers(L_CRIT, "OPM: got a bad listener: %s:%hu", ip, port);
|
||||
exit(EX_PROVIDER_ERROR);
|
||||
}
|
||||
|
||||
SET_SS_PORT(&addr, htons(port));
|
||||
|
||||
#ifdef RB_IPV6
|
||||
if(GET_SS_FAMILY(&addr) == AF_INET6)
|
||||
{
|
||||
struct sockaddr_in6 *a1, *a2;
|
||||
|
||||
listener = &listeners[LISTEN_IPV6];
|
||||
|
||||
a1 = (struct sockaddr_in6 *)&addr;
|
||||
a2 = (struct sockaddr_in6 *)&listener->addr;
|
||||
|
||||
if(IN6_ARE_ADDR_EQUAL(&a1->sin6_addr, &a2->sin6_addr) &&
|
||||
GET_SS_PORT(&addr) == GET_SS_PORT(&listener->addr) &&
|
||||
listener->F != NULL)
|
||||
{
|
||||
/* Listener already exists */
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
struct sockaddr_in *a1, *a2;
|
||||
|
||||
listener = &listeners[LISTEN_IPV4];
|
||||
|
||||
a1 = (struct sockaddr_in *)&addr;
|
||||
a2 = (struct sockaddr_in *)&listener->addr;
|
||||
|
||||
if(a1->sin_addr.s_addr == a2->sin_addr.s_addr &&
|
||||
GET_SS_PORT(&addr) == GET_SS_PORT(&listener->addr) &&
|
||||
listener->F != NULL)
|
||||
{
|
||||
/* Listener already exists */
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if((F = rb_socket(GET_SS_FAMILY(&addr), SOCK_STREAM, 0, "OPM listener socket")) == NULL)
|
||||
{
|
||||
/* This shouldn't fail, or we have big problems... */
|
||||
warn_opers(L_CRIT, "OPM: cannot create socket: %s", strerror(errno));
|
||||
exit(EX_PROVIDER_ERROR);
|
||||
}
|
||||
|
||||
if(setsockopt(rb_get_fd(F), SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)))
|
||||
{
|
||||
/* This shouldn't fail either... */
|
||||
warn_opers(L_CRIT, "OPM: cannot set options on socket: %s", strerror(errno));
|
||||
exit(EX_PROVIDER_ERROR);
|
||||
}
|
||||
|
||||
if(bind(rb_get_fd(F), (struct sockaddr *)&addr, GET_SS_LEN(&addr)))
|
||||
{
|
||||
/* Shit happens, let's not cripple authd over /this/ since it could be user error */
|
||||
warn_opers(L_WARN, "OPM: cannot bind on socket: %s", strerror(errno));
|
||||
rb_close(F);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(rb_listen(F, SOMAXCONN, false)) /* deferred accept could interfere with detection */
|
||||
{
|
||||
/* Again, could be user error */
|
||||
warn_opers(L_WARN, "OPM: cannot listen on socket: %s", strerror(errno));
|
||||
rb_close(F);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* From this point forward we assume we have a listener */
|
||||
|
||||
if(listener->F != NULL)
|
||||
/* Close old listener */
|
||||
rb_close(listener->F);
|
||||
|
||||
listener->F = F;
|
||||
|
||||
/* Cancel clients that may be on old listener
|
||||
* XXX - should rescan clients that need it
|
||||
*/
|
||||
void *elem;
|
||||
RB_DICTIONARY_FOREACH(elem, &iter, auth_clients)
|
||||
{
|
||||
auth = (auth_client *)elem;
|
||||
opm_cancel(auth);
|
||||
/* auth is now invalid as we have no reference */
|
||||
}
|
||||
|
||||
/* Copy data */
|
||||
rb_strlcpy(listener->ip, ip, sizeof(listener->ip));
|
||||
listener->port = port;
|
||||
listener->addr = addr;
|
||||
|
||||
opm_enable = true; /* Implicitly set this to true for now if we have a listener */
|
||||
rb_accept_tcp(listener->F, NULL, accept_opm, listener);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
opm_scan(struct auth_client *auth)
|
||||
{
|
||||
rb_dlink_node *ptr;
|
||||
struct opm_lookup *lookup;
|
||||
|
||||
lrb_assert(auth != NULL);
|
||||
|
||||
lookup = (opm_lookup *)get_provider_data(auth, SELF_PID);
|
||||
set_provider_timeout_relative(auth, SELF_PID, opm_timeout);
|
||||
|
||||
lookup->in_progress = true;
|
||||
|
||||
RB_DLINK_FOREACH(ptr, proxy_scanners.head)
|
||||
{
|
||||
struct opm_proxy *proxy = (opm_proxy *)ptr->data;
|
||||
//notice_client(auth->cid, "*** Scanning for proxy type %s", proxy->note);
|
||||
establish_connection(auth, proxy);
|
||||
}
|
||||
|
||||
notice_client(auth->cid, "*** Scanning for open proxies...");
|
||||
}
|
||||
|
||||
/* This is called every time a provider is completed as long as we are marked not done */
|
||||
static void
|
||||
opm_initiate(struct auth_client *auth, uint32_t provider)
|
||||
{
|
||||
struct opm_lookup *lookup = (opm_lookup *)get_provider_data(auth, SELF_PID);
|
||||
uint32_t rdns_pid, ident_pid;
|
||||
|
||||
lrb_assert(provider != SELF_PID);
|
||||
lrb_assert(!is_provider_done(auth, SELF_PID));
|
||||
lrb_assert(rb_dlink_list_length(&proxy_scanners) > 0);
|
||||
|
||||
if(lookup == NULL || lookup->in_progress)
|
||||
/* Nothing to do */
|
||||
return;
|
||||
else if((!get_provider_id("rdns", &rdns_pid) || is_provider_done(auth, rdns_pid)) &&
|
||||
(!get_provider_id("ident", &ident_pid) || is_provider_done(auth, ident_pid)))
|
||||
/* Don't start until ident and rdns are finished (or not loaded) */
|
||||
return;
|
||||
else
|
||||
opm_scan(auth);
|
||||
}
|
||||
|
||||
static bool
|
||||
opm_start(struct auth_client *auth)
|
||||
{
|
||||
uint32_t rdns_pid, ident_pid;
|
||||
|
||||
lrb_assert(get_provider_data(auth, SELF_PID) == NULL);
|
||||
|
||||
if(!opm_enable || rb_dlink_list_length(&proxy_scanners) == 0)
|
||||
/* Nothing to do... */
|
||||
return true;
|
||||
|
||||
auth_client_ref(auth);
|
||||
|
||||
set_provider_data(auth, SELF_PID, rb_malloc(sizeof(struct opm_lookup)));
|
||||
|
||||
if((!get_provider_id("rdns", &rdns_pid) || is_provider_done(auth, rdns_pid)) &&
|
||||
(!get_provider_id("ident", &ident_pid) || is_provider_done(auth, ident_pid)))
|
||||
{
|
||||
/* Don't start until ident and rdns are finished (or not loaded) */
|
||||
opm_scan(auth);
|
||||
}
|
||||
|
||||
set_provider_running(auth, SELF_PID);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
opm_cancel(struct auth_client *auth)
|
||||
{
|
||||
struct opm_lookup *lookup = (opm_lookup *)get_provider_data(auth, SELF_PID);
|
||||
|
||||
if(lookup != NULL)
|
||||
{
|
||||
rb_dlink_node *ptr, *nptr;
|
||||
|
||||
notice_client(auth->cid, "*** Did not detect open proxies");
|
||||
|
||||
RB_DLINK_FOREACH_SAFE(ptr, nptr, lookup->scans.head)
|
||||
{
|
||||
struct opm_scan *scan = (struct opm_scan *)ptr->data;
|
||||
|
||||
rb_close(scan->F);
|
||||
rb_free(scan);
|
||||
}
|
||||
|
||||
rb_free(lookup);
|
||||
|
||||
set_provider_data(auth, SELF_PID, NULL);
|
||||
set_provider_timeout_absolute(auth, SELF_PID, 0);
|
||||
provider_done(auth, SELF_PID);
|
||||
|
||||
auth_client_unref(auth);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
opm_destroy(void)
|
||||
{
|
||||
struct auth_client *auth;
|
||||
rb_dictionary_iter iter;
|
||||
|
||||
/* Nuke all opm lookups */
|
||||
void *elem;
|
||||
RB_DICTIONARY_FOREACH(elem, &iter, auth_clients)
|
||||
{
|
||||
auth = (auth_client *)elem;
|
||||
opm_cancel(auth);
|
||||
/* auth is now invalid as we have no reference */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
add_conf_opm_timeout(const char *key, int parc, const char **parv)
|
||||
{
|
||||
int timeout = atoi(parv[0]);
|
||||
|
||||
if(timeout < 0)
|
||||
{
|
||||
warn_opers(L_CRIT, "opm: opm timeout < 0 (value: %d)", timeout);
|
||||
return;
|
||||
}
|
||||
|
||||
opm_timeout = timeout;
|
||||
}
|
||||
|
||||
static void
|
||||
set_opm_enabled(const char *key, int parc, const char **parv)
|
||||
{
|
||||
bool enable = (*parv[0] == '1');
|
||||
|
||||
if(!enable)
|
||||
{
|
||||
if(listeners[LISTEN_IPV4].F != NULL || listeners[LISTEN_IPV6].F != NULL)
|
||||
{
|
||||
struct auth_client *auth;
|
||||
rb_dictionary_iter iter;
|
||||
|
||||
/* Close the listening socket */
|
||||
if(listeners[LISTEN_IPV4].F != NULL)
|
||||
rb_close(listeners[LISTEN_IPV4].F);
|
||||
|
||||
if(listeners[LISTEN_IPV6].F != NULL)
|
||||
rb_close(listeners[LISTEN_IPV6].F);
|
||||
|
||||
listeners[LISTEN_IPV4].F = listeners[LISTEN_IPV6].F = NULL;
|
||||
|
||||
void *elem;
|
||||
RB_DICTIONARY_FOREACH(elem, &iter, auth_clients)
|
||||
{
|
||||
auth = (auth_client *)elem;
|
||||
opm_cancel(auth);
|
||||
/* auth is now invalid as we have no reference */
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(listeners[LISTEN_IPV4].ip[0] != '\0' && listeners[LISTEN_IPV4].port != 0)
|
||||
{
|
||||
if(listeners[LISTEN_IPV4].F == NULL)
|
||||
/* Pre-configured IP/port, just re-establish */
|
||||
create_listener(listeners[LISTEN_IPV4].ip, listeners[LISTEN_IPV4].port);
|
||||
}
|
||||
|
||||
if(listeners[LISTEN_IPV6].ip[0] != '\0' && listeners[LISTEN_IPV6].port != 0)
|
||||
{
|
||||
if(listeners[LISTEN_IPV6].F == NULL)
|
||||
/* Pre-configured IP/port, just re-establish */
|
||||
create_listener(listeners[LISTEN_IPV6].ip, listeners[LISTEN_IPV6].port);
|
||||
}
|
||||
}
|
||||
|
||||
opm_enable = enable;
|
||||
}
|
||||
|
||||
static void
|
||||
set_opm_listener(const char *key, int parc, const char **parv)
|
||||
{
|
||||
const char *ip = parv[0];
|
||||
int iport = atoi(parv[1]);
|
||||
|
||||
if(iport > 65535 || iport <= 0)
|
||||
{
|
||||
warn_opers(L_CRIT, "OPM: got a bad listener: %s:%s", parv[0], parv[1]);
|
||||
exit(EX_PROVIDER_ERROR);
|
||||
}
|
||||
|
||||
create_listener(ip, (uint16_t)iport);
|
||||
}
|
||||
|
||||
static void
|
||||
create_opm_scanner(const char *key, int parc, const char **parv)
|
||||
{
|
||||
int iport = atoi(parv[1]);
|
||||
struct opm_proxy *proxy = (opm_proxy *)rb_malloc(sizeof(struct opm_proxy));
|
||||
|
||||
if(iport <= 0 || iport > 65535)
|
||||
{
|
||||
warn_opers(L_CRIT, "OPM: got a bad scanner: %s (port %s)", parv[0], parv[1]);
|
||||
exit(EX_PROVIDER_ERROR);
|
||||
}
|
||||
|
||||
proxy->port = (uint16_t)iport;
|
||||
|
||||
switch((proxy->proto = get_protocol_from_string(parv[0])))
|
||||
{
|
||||
case PROTO_SOCKS4:
|
||||
snprintf(proxy->note, sizeof(proxy->note), "socks4:%hu", proxy->port);
|
||||
proxy->ssl = false;
|
||||
proxy->callback = socks4_connected;
|
||||
break;
|
||||
case PROTO_SOCKS5:
|
||||
snprintf(proxy->note, sizeof(proxy->note), "socks5:%hu", proxy->port);
|
||||
proxy->ssl = false;
|
||||
proxy->callback = socks5_connected;
|
||||
break;
|
||||
case PROTO_HTTP_CONNECT:
|
||||
snprintf(proxy->note, sizeof(proxy->note), "httpconnect:%hu", proxy->port);
|
||||
proxy->ssl = false;
|
||||
proxy->callback = http_connect_connected;
|
||||
break;
|
||||
case PROTO_HTTPS_CONNECT:
|
||||
snprintf(proxy->note, sizeof(proxy->note), "httpsconnect:%hu", proxy->port);
|
||||
proxy->callback = http_connect_connected;
|
||||
proxy->ssl = true;
|
||||
break;
|
||||
default:
|
||||
warn_opers(L_CRIT, "OPM: got an unknown proxy type: %s (port %hu)", parv[0], proxy->port);
|
||||
exit(EX_PROVIDER_ERROR);
|
||||
}
|
||||
|
||||
if(find_proxy_scanner(proxy->proto, proxy->port) != NULL)
|
||||
{
|
||||
warn_opers(L_CRIT, "OPM: got a duplicate scanner: %s (port %hu)", parv[0], proxy->port);
|
||||
exit(EX_PROVIDER_ERROR);
|
||||
}
|
||||
|
||||
rb_dlinkAdd(proxy, &proxy->node, &proxy_scanners);
|
||||
}
|
||||
|
||||
static void
|
||||
delete_opm_scanner(const char *key, int parc, const char **parv)
|
||||
{
|
||||
struct auth_client *auth;
|
||||
struct opm_proxy *proxy;
|
||||
protocol_t proto = get_protocol_from_string(parv[0]);
|
||||
int iport = atoi(parv[1]);
|
||||
rb_dictionary_iter iter;
|
||||
|
||||
if(iport <= 0 || iport > 65535)
|
||||
{
|
||||
warn_opers(L_CRIT, "OPM: got a bad scanner to delete: %s (port %s)", parv[0], parv[1]);
|
||||
exit(EX_PROVIDER_ERROR);
|
||||
}
|
||||
|
||||
if(proto == PROTO_NONE)
|
||||
{
|
||||
warn_opers(L_CRIT, "OPM: got an unknown proxy type to delete: %s (port %d)", parv[0], iport);
|
||||
exit(EX_PROVIDER_ERROR);
|
||||
}
|
||||
|
||||
if((proxy = find_proxy_scanner(proto, (uint16_t)iport)) == NULL)
|
||||
{
|
||||
warn_opers(L_CRIT, "OPM: cannot find proxy to delete: %s (port %d)", parv[0], iport);
|
||||
exit(EX_PROVIDER_ERROR);
|
||||
}
|
||||
|
||||
/* Abort remaining clients on this scanner */
|
||||
void *elem;
|
||||
RB_DICTIONARY_FOREACH(elem, &iter, auth_clients)
|
||||
{
|
||||
rb_dlink_node *ptr;
|
||||
auth = (auth_client *)elem;
|
||||
struct opm_lookup *lookup = (opm_lookup *)get_provider_data(auth, SELF_PID);
|
||||
|
||||
if(lookup == NULL)
|
||||
continue;
|
||||
|
||||
auth_client_ref(auth);
|
||||
|
||||
RB_DLINK_FOREACH(ptr, lookup->scans.head)
|
||||
{
|
||||
struct opm_scan *scan = (struct opm_scan *)ptr->data;
|
||||
|
||||
if(scan->proxy->port == proxy->port && scan->proxy->proto == proxy->proto)
|
||||
{
|
||||
/* Match */
|
||||
rb_dlinkDelete(&scan->node, &lookup->scans);
|
||||
rb_free(scan);
|
||||
|
||||
if(rb_dlink_list_length(&lookup->scans) == 0)
|
||||
opm_cancel(auth);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auth_client_unref(auth);
|
||||
}
|
||||
|
||||
rb_dlinkDelete(&proxy->node, &proxy_scanners);
|
||||
rb_free(proxy);
|
||||
|
||||
if(rb_dlink_list_length(&proxy_scanners) == 0)
|
||||
opm_enable = false;
|
||||
}
|
||||
|
||||
static void
|
||||
delete_opm_scanner_all(const char *key, int parc, const char **parv)
|
||||
{
|
||||
struct auth_client *auth;
|
||||
rb_dlink_node *ptr, *nptr;
|
||||
rb_dictionary_iter iter;
|
||||
|
||||
RB_DLINK_FOREACH_SAFE(ptr, nptr, proxy_scanners.head)
|
||||
{
|
||||
rb_free(ptr->data);
|
||||
rb_dlinkDelete(ptr, &proxy_scanners);
|
||||
}
|
||||
|
||||
void *elem;
|
||||
RB_DICTIONARY_FOREACH(elem, &iter, auth_clients)
|
||||
{
|
||||
auth = (auth_client *)elem;
|
||||
opm_cancel(auth);
|
||||
/* auth is now invalid as we have no reference */
|
||||
}
|
||||
|
||||
opm_enable = false;
|
||||
}
|
||||
|
||||
static void
|
||||
delete_opm_listener_all(const char *key, int parc, const char **parv)
|
||||
{
|
||||
if(listeners[LISTEN_IPV4].F != NULL)
|
||||
rb_close(listeners[LISTEN_IPV4].F);
|
||||
|
||||
#ifdef RB_IPV6
|
||||
if(listeners[LISTEN_IPV6].F != NULL)
|
||||
rb_close(listeners[LISTEN_IPV6].F);
|
||||
#endif
|
||||
|
||||
memset(&listeners, 0, sizeof(listeners));
|
||||
}
|
||||
|
||||
|
||||
struct auth_opts_handler opm_options[] =
|
||||
{
|
||||
{ "opm_timeout", 1, add_conf_opm_timeout },
|
||||
{ "opm_enabled", 1, set_opm_enabled },
|
||||
{ "opm_listener", 2, set_opm_listener },
|
||||
{ "opm_listener_del_all", 0, delete_opm_listener_all },
|
||||
{ "opm_scanner", 2, create_opm_scanner },
|
||||
{ "opm_scanner_del", 2, delete_opm_scanner },
|
||||
{ "opm_scanner_del_all", 0, delete_opm_scanner_all },
|
||||
{ NULL, 0, NULL },
|
||||
};
|
||||
|
||||
struct auth_provider opm_provider =
|
||||
[]{
|
||||
auth_provider ap {0};
|
||||
ap.name = "opm";
|
||||
ap.letter = 'O';
|
||||
ap.destroy = opm_destroy;
|
||||
ap.start = opm_start;
|
||||
ap.cancel = opm_cancel;
|
||||
ap.timeout = opm_cancel;
|
||||
ap.completed = opm_initiate;
|
||||
ap.opt_handlers = opm_options;
|
||||
return ap;
|
||||
}();
|
|
@ -1,189 +0,0 @@
|
|||
/* authd/providers/rdns.c - rDNS lookup provider for authd
|
||||
* Copyright (c) 2016 Elizabeth Myers <elizabeth@interlinked.me>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "authd.h"
|
||||
#include "provider.h"
|
||||
#include "notice.h"
|
||||
#include "res.h"
|
||||
#include "dns.h"
|
||||
|
||||
using namespace ircd::defaults;
|
||||
|
||||
#define SELF_PID (rdns_provider.id)
|
||||
|
||||
struct user_query
|
||||
{
|
||||
struct dns_query *query; /* Pending DNS query */
|
||||
};
|
||||
|
||||
/* Goinked from old s_auth.c --Elizabeth */
|
||||
static const char *messages[] =
|
||||
{
|
||||
"*** Looking up your hostname...",
|
||||
"*** Couldn't look up your hostname",
|
||||
"*** Your hostname is too long, ignoring hostname",
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
REPORT_LOOKUP,
|
||||
REPORT_FAIL,
|
||||
REPORT_TOOLONG,
|
||||
} dns_message;
|
||||
|
||||
static void client_fail(struct auth_client *auth, dns_message message);
|
||||
static void client_success(struct auth_client *auth);
|
||||
static void dns_answer_callback(const char *res, bool status, query_type type, void *data);
|
||||
|
||||
static int rdns_timeout = RDNS_TIMEOUT_DEFAULT;
|
||||
|
||||
static void
|
||||
dns_answer_callback(const char *res, bool status, query_type type, void *data)
|
||||
{
|
||||
struct auth_client *auth = (auth_client *)data;
|
||||
struct user_query *query = (user_query *)get_provider_data(auth, SELF_PID);
|
||||
|
||||
lrb_assert(query != NULL);
|
||||
|
||||
if(res == NULL || status == false)
|
||||
client_fail(auth, REPORT_FAIL);
|
||||
else if(strlen(res) > HOSTLEN)
|
||||
client_fail(auth, REPORT_TOOLONG);
|
||||
else
|
||||
{
|
||||
rb_strlcpy(auth->hostname, res, HOSTLEN + 1);
|
||||
client_success(auth);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
client_fail(struct auth_client *auth, dns_message report)
|
||||
{
|
||||
struct user_query *query = (user_query *)get_provider_data(auth, SELF_PID);
|
||||
|
||||
lrb_assert(query != NULL);
|
||||
|
||||
rb_strlcpy(auth->hostname, "*", sizeof(auth->hostname));
|
||||
|
||||
notice_client(auth->cid, messages[report]);
|
||||
cancel_query(query->query);
|
||||
|
||||
rb_free(query);
|
||||
|
||||
set_provider_data(auth, SELF_PID, NULL);
|
||||
set_provider_timeout_absolute(auth, SELF_PID, 0);
|
||||
provider_done(auth, SELF_PID);
|
||||
|
||||
auth_client_unref(auth);
|
||||
}
|
||||
|
||||
static void
|
||||
client_success(struct auth_client *auth)
|
||||
{
|
||||
struct user_query *query = (user_query *)get_provider_data(auth, SELF_PID);
|
||||
|
||||
lrb_assert(query != NULL);
|
||||
|
||||
notice_client(auth->cid, "*** Found your hostname: %s", auth->hostname);
|
||||
cancel_query(query->query);
|
||||
|
||||
rb_free(query);
|
||||
|
||||
set_provider_data(auth, SELF_PID, NULL);
|
||||
set_provider_timeout_absolute(auth, SELF_PID, 0);
|
||||
provider_done(auth, SELF_PID);
|
||||
|
||||
auth_client_unref(auth);
|
||||
}
|
||||
|
||||
static void
|
||||
rdns_destroy(void)
|
||||
{
|
||||
struct auth_client *auth;
|
||||
rb_dictionary_iter iter;
|
||||
|
||||
void *elem;
|
||||
RB_DICTIONARY_FOREACH(elem, &iter, auth_clients)
|
||||
{
|
||||
auth = (auth_client *)elem;
|
||||
if(get_provider_data(auth, SELF_PID) != NULL)
|
||||
client_fail(auth, REPORT_FAIL);
|
||||
/* auth is now invalid as we have no reference */
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
rdns_start(struct auth_client *auth)
|
||||
{
|
||||
struct user_query *query = (user_query *)rb_malloc(sizeof(struct user_query));
|
||||
|
||||
auth_client_ref(auth);
|
||||
|
||||
set_provider_data(auth, SELF_PID, query);
|
||||
set_provider_timeout_relative(auth, SELF_PID, rdns_timeout);
|
||||
|
||||
query->query = lookup_hostname(auth->c_ip, dns_answer_callback, auth);
|
||||
|
||||
notice_client(auth->cid, messages[REPORT_LOOKUP]);
|
||||
set_provider_running(auth, SELF_PID);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
rdns_cancel(struct auth_client *auth)
|
||||
{
|
||||
struct user_query *query = (user_query *)get_provider_data(auth, SELF_PID);
|
||||
|
||||
if(query != NULL)
|
||||
client_fail(auth, REPORT_FAIL);
|
||||
}
|
||||
|
||||
static void
|
||||
add_conf_dns_timeout(const char *key, int parc, const char **parv)
|
||||
{
|
||||
int timeout = atoi(parv[0]);
|
||||
|
||||
if(timeout < 0)
|
||||
{
|
||||
warn_opers(L_CRIT, "rDNS: DNS timeout < 0 (value: %d)", timeout);
|
||||
exit(EX_PROVIDER_ERROR);
|
||||
}
|
||||
|
||||
rdns_timeout = timeout;
|
||||
}
|
||||
|
||||
struct auth_opts_handler rdns_options[] =
|
||||
{
|
||||
{ "rdns_timeout", 1, add_conf_dns_timeout },
|
||||
{ NULL, 0, NULL },
|
||||
};
|
||||
|
||||
struct auth_provider rdns_provider =
|
||||
[]{
|
||||
auth_provider ap {0};
|
||||
ap.name = "rdns";
|
||||
ap.letter = 'R';
|
||||
ap.destroy = rdns_destroy;
|
||||
ap.start = rdns_start;
|
||||
ap.cancel = rdns_cancel;
|
||||
ap.timeout = rdns_cancel;
|
||||
ap.opt_handlers = rdns_options;
|
||||
return ap;
|
||||
}();
|
907
authd/res.cc
907
authd/res.cc
|
@ -1,907 +0,0 @@
|
|||
/*
|
||||
* A rewrite of Darren Reeds original res.c As there is nothing
|
||||
* left of Darrens original code, this is now licensed by the hybrid group.
|
||||
* (Well, some of the function names are the same, and bits of the structs..)
|
||||
* You can use it where it is useful, free even. Buy us a beer and stuff.
|
||||
*
|
||||
* The authors takes no responsibility for any damage or loss
|
||||
* of property which results from the use of this software.
|
||||
*
|
||||
* July 1999 - Rewrote a bunch of stuff here. Change hostent builder code,
|
||||
* added callbacks and reference counting of returned hostents.
|
||||
* --Bleep (Thomas Helvey <tomh@inxpress.net>)
|
||||
*
|
||||
* This was all needlessly complicated for irc. Simplified. No more hostent
|
||||
* All we really care about is the IP -> hostname mappings. Thats all.
|
||||
*
|
||||
* Apr 28, 2003 --cryogen and Dianora
|
||||
*
|
||||
* DNS server flooding lessened, AAAA-or-A lookup removed, ip6.int support
|
||||
* removed, various robustness fixes
|
||||
*
|
||||
* 2006 --jilles and nenolod
|
||||
*
|
||||
* Resend queries to other servers if the DNS server replies with an error or
|
||||
* an invalid response. Also, avoid servers that return errors or invalid
|
||||
* responses.
|
||||
*
|
||||
* October 2012 --mr_flea
|
||||
*
|
||||
* ircd-ratbox changes for random IDs merged back in.
|
||||
*
|
||||
* January 2016 --kaniini
|
||||
*/
|
||||
|
||||
#include <rb/rb.h>
|
||||
#include "res.h"
|
||||
#include "reslib.h"
|
||||
|
||||
#if (CHAR_BIT != 8)
|
||||
#error this code needs to be able to address individual octets
|
||||
#endif
|
||||
|
||||
static PF res_readreply;
|
||||
|
||||
#define MAXPACKET 1024 /* rfc sez 512 but we expand names so ... */
|
||||
#define AR_TTL 600 /* TTL in seconds for dns cache entries */
|
||||
|
||||
/* RFC 1104/1105 wasn't very helpful about what these fields
|
||||
* should be named, so for now, we'll just name them this way.
|
||||
* we probably should look at what named calls them or something.
|
||||
*/
|
||||
#define TYPE_SIZE (size_t)2
|
||||
#define CLASS_SIZE (size_t)2
|
||||
#define TTL_SIZE (size_t)4
|
||||
#define RDLENGTH_SIZE (size_t)2
|
||||
#define ANSWER_FIXED_SIZE (TYPE_SIZE + CLASS_SIZE + TTL_SIZE + RDLENGTH_SIZE)
|
||||
|
||||
#ifdef RB_IPV6
|
||||
struct in6_addr ipv6_addr;
|
||||
#endif
|
||||
struct in_addr ipv4_addr;
|
||||
|
||||
struct reslist
|
||||
{
|
||||
rb_dlink_node node;
|
||||
int id;
|
||||
time_t ttl;
|
||||
char type;
|
||||
char queryname[IRCD_RES_HOSTLEN + 1]; /* name currently being queried */
|
||||
char retries; /* retry counter */
|
||||
char sends; /* number of sends (>1 means resent) */
|
||||
time_t sentat;
|
||||
time_t timeout;
|
||||
int lastns; /* index of last server sent to */
|
||||
struct rb_sockaddr_storage addr;
|
||||
char *name;
|
||||
struct DNSQuery *query; /* query callback for this request */
|
||||
};
|
||||
|
||||
static rb_fde_t *res_fd;
|
||||
static rb_dlink_list request_list = { NULL, NULL, 0 };
|
||||
static int ns_failure_count[IRCD_MAXNS]; /* timeouts and invalid/failed replies */
|
||||
|
||||
static void rem_request(struct reslist *request);
|
||||
static struct reslist *make_request(struct DNSQuery *query);
|
||||
static void gethost_byname_type_fqdn(const char *name, struct DNSQuery *query,
|
||||
int type);
|
||||
static void do_query_name(struct DNSQuery *query, const char *name, struct reslist *request, int);
|
||||
static void do_query_number(struct DNSQuery *query, const struct rb_sockaddr_storage *,
|
||||
struct reslist *request);
|
||||
static void query_name(struct reslist *request);
|
||||
static int send_res_msg(const char *buf, int len, int count);
|
||||
static void resend_query(struct reslist *request);
|
||||
static int check_question(struct reslist *request, HEADER * header, char *buf, char *eob);
|
||||
static int proc_answer(struct reslist *request, HEADER * header, char *, char *);
|
||||
static struct reslist *find_id(int id);
|
||||
static struct DNSReply *make_dnsreply(struct reslist *request);
|
||||
static uint16_t generate_random_id(void);
|
||||
|
||||
/*
|
||||
* int
|
||||
* res_ourserver(inp)
|
||||
* looks up "inp" in irc_nsaddr_list[]
|
||||
* returns:
|
||||
* server ID or -1 for not found
|
||||
* author:
|
||||
* paul vixie, 29may94
|
||||
* revised for ircd, cryogen(stu) may03
|
||||
* slightly modified for charybdis, mr_flea oct12
|
||||
*/
|
||||
static int
|
||||
res_ourserver(const struct rb_sockaddr_storage *inp)
|
||||
{
|
||||
#ifdef RB_IPV6
|
||||
const struct sockaddr_in6 *v6;
|
||||
const struct sockaddr_in6 *v6in = (const struct sockaddr_in6 *)inp;
|
||||
#endif
|
||||
const struct sockaddr_in *v4;
|
||||
const struct sockaddr_in *v4in = (const struct sockaddr_in *)inp;
|
||||
int ns;
|
||||
|
||||
for(ns = 0; ns < irc_nscount; ns++)
|
||||
{
|
||||
const struct rb_sockaddr_storage *srv = &irc_nsaddr_list[ns];
|
||||
#ifdef RB_IPV6
|
||||
v6 = (const struct sockaddr_in6 *)srv;
|
||||
#endif
|
||||
v4 = (const struct sockaddr_in *)srv;
|
||||
|
||||
/* could probably just memcmp(srv, inp, srv.ss_len) here
|
||||
* but we'll air on the side of caution - stu
|
||||
*/
|
||||
switch (GET_SS_FAMILY(srv))
|
||||
{
|
||||
#ifdef RB_IPV6
|
||||
case AF_INET6:
|
||||
if(GET_SS_FAMILY(srv) == GET_SS_FAMILY(inp))
|
||||
if(v6->sin6_port == v6in->sin6_port)
|
||||
if((memcmp(&v6->sin6_addr.s6_addr, &v6in->sin6_addr.s6_addr,
|
||||
sizeof(struct in6_addr)) == 0) ||
|
||||
(memcmp(&v6->sin6_addr.s6_addr, &in6addr_any,
|
||||
sizeof(struct in6_addr)) == 0))
|
||||
return 1;
|
||||
break;
|
||||
#endif
|
||||
case AF_INET:
|
||||
if(GET_SS_FAMILY(srv) == GET_SS_FAMILY(inp))
|
||||
if(v4->sin_port == v4in->sin_port)
|
||||
if((v4->sin_addr.s_addr == INADDR_ANY)
|
||||
|| (v4->sin_addr.s_addr == v4in->sin_addr.s_addr))
|
||||
return 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* timeout_query_list - Remove queries from the list which have been
|
||||
* there too long without being resolved.
|
||||
*/
|
||||
static time_t timeout_query_list(time_t now)
|
||||
{
|
||||
rb_dlink_node *ptr;
|
||||
rb_dlink_node *next_ptr;
|
||||
struct reslist *request;
|
||||
time_t next_time = 0;
|
||||
time_t timeout = 0;
|
||||
|
||||
RB_DLINK_FOREACH_SAFE(ptr, next_ptr, request_list.head)
|
||||
{
|
||||
request = (reslist *)ptr->data;
|
||||
timeout = request->sentat + request->timeout;
|
||||
|
||||
if (now >= timeout)
|
||||
{
|
||||
ns_failure_count[request->lastns]++;
|
||||
request->sentat = now;
|
||||
request->timeout += request->timeout;
|
||||
resend_query(request);
|
||||
}
|
||||
|
||||
if ((next_time == 0) || timeout < next_time)
|
||||
{
|
||||
next_time = timeout;
|
||||
}
|
||||
}
|
||||
|
||||
return (next_time > now) ? next_time : (now + AR_TTL);
|
||||
}
|
||||
|
||||
/*
|
||||
* timeout_resolver - check request list
|
||||
*/
|
||||
static void timeout_resolver(void *notused)
|
||||
{
|
||||
timeout_query_list(rb_current_time());
|
||||
}
|
||||
|
||||
static struct ev_entry *timeout_resolver_ev = NULL;
|
||||
|
||||
/*
|
||||
* start_resolver - do everything we need to read the resolv.conf file
|
||||
* and initialize the resolver file descriptor if needed
|
||||
*/
|
||||
static void start_resolver(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
irc_res_init();
|
||||
for (i = 0; i < irc_nscount; i++)
|
||||
ns_failure_count[i] = 0;
|
||||
|
||||
if (res_fd == NULL)
|
||||
{
|
||||
if ((res_fd = rb_socket(GET_SS_FAMILY(&irc_nsaddr_list[0]), SOCK_DGRAM, 0,
|
||||
"UDP resolver socket")) == NULL)
|
||||
return;
|
||||
|
||||
/* At the moment, the resolver FD data is global .. */
|
||||
rb_setselect(res_fd, RB_SELECT_READ, res_readreply, NULL);
|
||||
timeout_resolver_ev = rb_event_add("timeout_resolver", timeout_resolver, NULL, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* init_resolver - initialize resolver and resolver library
|
||||
*/
|
||||
void init_resolver(void)
|
||||
{
|
||||
#ifdef HAVE_SRAND48
|
||||
srand48(rb_current_time());
|
||||
#endif
|
||||
start_resolver();
|
||||
}
|
||||
|
||||
/*
|
||||
* restart_resolver - reread resolv.conf, reopen socket
|
||||
*/
|
||||
void restart_resolver(void)
|
||||
{
|
||||
rb_close(res_fd);
|
||||
res_fd = NULL;
|
||||
rb_event_delete(timeout_resolver_ev); /* -ddosen */
|
||||
start_resolver();
|
||||
}
|
||||
|
||||
/*
|
||||
* add_local_domain - Add the domain to hostname, if it is missing
|
||||
* (as suggested by eps@TOASTER.SFSU.EDU)
|
||||
*/
|
||||
static void add_local_domain(char *hname, size_t size)
|
||||
{
|
||||
/* try to fix up unqualified names */
|
||||
if (strchr(hname, '.') == NULL)
|
||||
{
|
||||
if (irc_domain[0])
|
||||
{
|
||||
size_t len = strlen(hname);
|
||||
|
||||
if ((strlen(irc_domain) + len + 2) < size)
|
||||
{
|
||||
hname[len++] = '.';
|
||||
strcpy(hname + len, irc_domain);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* rem_request - remove a request from the list.
|
||||
* This must also free any memory that has been allocated for
|
||||
* temporary storage of DNS results.
|
||||
*/
|
||||
static void rem_request(struct reslist *request)
|
||||
{
|
||||
rb_dlinkDelete(&request->node, &request_list);
|
||||
rb_free(request->name);
|
||||
rb_free(request);
|
||||
}
|
||||
|
||||
/*
|
||||
* make_request - Create a DNS request record for the server.
|
||||
*/
|
||||
static struct reslist *make_request(struct DNSQuery *query)
|
||||
{
|
||||
struct reslist *request = (reslist *)rb_malloc(sizeof(struct reslist));
|
||||
|
||||
request->sentat = rb_current_time();
|
||||
request->retries = 3;
|
||||
request->timeout = 4; /* start at 4 and exponential inc. */
|
||||
request->query = query;
|
||||
|
||||
/*
|
||||
* generate a unique id
|
||||
* NOTE: we don't have to worry about converting this to and from
|
||||
* network byte order, the nameserver does not interpret this value
|
||||
* and returns it unchanged
|
||||
*
|
||||
* we generate an id per request now (instead of per send) to allow
|
||||
* late replies to be used.
|
||||
*/
|
||||
request->id = generate_random_id();
|
||||
|
||||
rb_dlinkAdd(request, &request->node, &request_list);
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
/*
|
||||
* retryfreq - determine how many queries to wait before resending
|
||||
* if there have been that many consecutive timeouts
|
||||
*
|
||||
* This is a cubic backoff btw, if anyone didn't pick up on it. --Elizafox
|
||||
*/
|
||||
static int retryfreq(int timeouts)
|
||||
{
|
||||
switch (timeouts)
|
||||
{
|
||||
case 1:
|
||||
return 3;
|
||||
case 2:
|
||||
return 9;
|
||||
case 3:
|
||||
return 27;
|
||||
case 4:
|
||||
return 81;
|
||||
default:
|
||||
return 243;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* send_res_msg - sends msg to a nameserver.
|
||||
* This should reflect /etc/resolv.conf.
|
||||
* Returns number of nameserver successfully sent to
|
||||
* or -1 if no successful sends.
|
||||
*/
|
||||
static int send_res_msg(const char *msg, int len, int rcount)
|
||||
{
|
||||
int i;
|
||||
int ns;
|
||||
static int retrycnt;
|
||||
|
||||
retrycnt++;
|
||||
/* First try a nameserver that seems to work.
|
||||
* Every once in a while, try a possibly broken one to check
|
||||
* if it is working again.
|
||||
*/
|
||||
for (i = 0; i < irc_nscount; i++)
|
||||
{
|
||||
ns = (i + rcount - 1) % irc_nscount;
|
||||
if (ns_failure_count[ns] && retrycnt % retryfreq(ns_failure_count[ns]))
|
||||
continue;
|
||||
if (sendto(rb_get_fd(res_fd), msg, len, 0,
|
||||
(struct sockaddr *)&(irc_nsaddr_list[ns]),
|
||||
GET_SS_LEN(&irc_nsaddr_list[ns])) == len)
|
||||
return ns;
|
||||
}
|
||||
|
||||
/* No known working nameservers, try some broken one. */
|
||||
for (i = 0; i < irc_nscount; i++)
|
||||
{
|
||||
ns = (i + rcount - 1) % irc_nscount;
|
||||
if (!ns_failure_count[ns])
|
||||
continue;
|
||||
if (sendto(rb_get_fd(res_fd), msg, len, 0,
|
||||
(struct sockaddr *)&(irc_nsaddr_list[ns]),
|
||||
GET_SS_LEN(&irc_nsaddr_list[ns])) == len)
|
||||
return ns;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* find_id - find a dns request id (id is determined by dn_mkquery)
|
||||
*/
|
||||
static struct reslist *find_id(int id)
|
||||
{
|
||||
rb_dlink_node *ptr;
|
||||
struct reslist *request;
|
||||
|
||||
RB_DLINK_FOREACH(ptr, request_list.head)
|
||||
{
|
||||
request = (reslist *)ptr->data;
|
||||
|
||||
if (request->id == id)
|
||||
return (request);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
generate_random_id(void)
|
||||
{
|
||||
uint16_t id;
|
||||
|
||||
do
|
||||
{
|
||||
rb_get_random(&id, sizeof(id));
|
||||
if(id == 0xffff)
|
||||
continue;
|
||||
}
|
||||
while(find_id(id));
|
||||
return id;
|
||||
}
|
||||
|
||||
/*
|
||||
* gethost_byname_type - get host address from name, adding domain if needed
|
||||
*/
|
||||
void gethost_byname_type(const char *name, struct DNSQuery *query, int type)
|
||||
{
|
||||
char fqdn[IRCD_RES_HOSTLEN + 1];
|
||||
assert(name != 0);
|
||||
|
||||
rb_strlcpy(fqdn, name, sizeof fqdn);
|
||||
add_local_domain(fqdn, IRCD_RES_HOSTLEN);
|
||||
gethost_byname_type_fqdn(fqdn, query, type);
|
||||
}
|
||||
|
||||
/*
|
||||
* gethost_byname_type_fqdn - get host address from fqdn
|
||||
*/
|
||||
static void gethost_byname_type_fqdn(const char *name, struct DNSQuery *query,
|
||||
int type)
|
||||
{
|
||||
assert(name != 0);
|
||||
do_query_name(query, name, NULL, type);
|
||||
}
|
||||
|
||||
/*
|
||||
* gethost_byaddr - get host name from address
|
||||
*/
|
||||
void gethost_byaddr(const struct rb_sockaddr_storage *addr, struct DNSQuery *query)
|
||||
{
|
||||
do_query_number(query, addr, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* do_query_name - nameserver lookup name
|
||||
*/
|
||||
static void do_query_name(struct DNSQuery *query, const char *name, struct reslist *request,
|
||||
int type)
|
||||
{
|
||||
if (request == NULL)
|
||||
{
|
||||
request = make_request(query);
|
||||
request->name = rb_strdup(name);
|
||||
}
|
||||
|
||||
rb_strlcpy(request->queryname, name, sizeof(request->queryname));
|
||||
request->type = type;
|
||||
query_name(request);
|
||||
}
|
||||
|
||||
/* Build an rDNS style query - if suffix is NULL, use the appropriate .arpa zone */
|
||||
void build_rdns(char *buf, size_t size, const struct rb_sockaddr_storage *addr, const char *suffix)
|
||||
{
|
||||
const unsigned char *cp;
|
||||
|
||||
if (GET_SS_FAMILY(addr) == AF_INET)
|
||||
{
|
||||
const struct sockaddr_in *v4 = (const struct sockaddr_in *)addr;
|
||||
cp = (const unsigned char *)&v4->sin_addr.s_addr;
|
||||
|
||||
(void) snprintf(buf, size, "%u.%u.%u.%u.%s",
|
||||
(unsigned int)(cp[3]),
|
||||
(unsigned int)(cp[2]),
|
||||
(unsigned int)(cp[1]),
|
||||
(unsigned int)(cp[0]),
|
||||
suffix == NULL ? "in-addr.arpa" : suffix);
|
||||
}
|
||||
#ifdef RB_IPV6
|
||||
else if (GET_SS_FAMILY(addr) == AF_INET6)
|
||||
{
|
||||
const struct sockaddr_in6 *v6 = (const struct sockaddr_in6 *)addr;
|
||||
cp = (const unsigned char *)&v6->sin6_addr.s6_addr;
|
||||
|
||||
#define HI_NIBBLE(x) (unsigned int)((x) >> 4)
|
||||
#define LO_NIBBLE(x) (unsigned int)((x) & 0xf)
|
||||
|
||||
(void) snprintf(buf, size,
|
||||
"%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%s",
|
||||
LO_NIBBLE(cp[15]), HI_NIBBLE(cp[15]),
|
||||
LO_NIBBLE(cp[14]), HI_NIBBLE(cp[14]),
|
||||
LO_NIBBLE(cp[13]), HI_NIBBLE(cp[13]),
|
||||
LO_NIBBLE(cp[12]), HI_NIBBLE(cp[12]),
|
||||
LO_NIBBLE(cp[11]), HI_NIBBLE(cp[11]),
|
||||
LO_NIBBLE(cp[10]), HI_NIBBLE(cp[10]),
|
||||
LO_NIBBLE(cp[9]), HI_NIBBLE(cp[9]),
|
||||
LO_NIBBLE(cp[8]), HI_NIBBLE(cp[8]),
|
||||
LO_NIBBLE(cp[7]), HI_NIBBLE(cp[7]),
|
||||
LO_NIBBLE(cp[6]), HI_NIBBLE(cp[6]),
|
||||
LO_NIBBLE(cp[5]), HI_NIBBLE(cp[5]),
|
||||
LO_NIBBLE(cp[4]), HI_NIBBLE(cp[4]),
|
||||
LO_NIBBLE(cp[3]), HI_NIBBLE(cp[3]),
|
||||
LO_NIBBLE(cp[2]), HI_NIBBLE(cp[2]),
|
||||
LO_NIBBLE(cp[1]), HI_NIBBLE(cp[1]),
|
||||
LO_NIBBLE(cp[0]), HI_NIBBLE(cp[0]),
|
||||
suffix == NULL ? "ip6.arpa" : suffix);
|
||||
}
|
||||
|
||||
#undef HI_NIBBLE
|
||||
#undef LO_NIBBLE
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* do_query_number - Use this to do reverse IP# lookups.
|
||||
*/
|
||||
static void do_query_number(struct DNSQuery *query, const struct rb_sockaddr_storage *addr,
|
||||
struct reslist *request)
|
||||
{
|
||||
if (request == NULL)
|
||||
{
|
||||
request = make_request(query);
|
||||
memcpy(&request->addr, addr, sizeof(struct rb_sockaddr_storage));
|
||||
request->name = (char *)rb_malloc(IRCD_RES_HOSTLEN + 1);
|
||||
}
|
||||
|
||||
build_rdns(request->queryname, IRCD_RES_HOSTLEN + 1, addr, NULL);
|
||||
|
||||
request->type = T_PTR;
|
||||
query_name(request);
|
||||
}
|
||||
|
||||
/*
|
||||
* query_name - generate a query based on class, type and name.
|
||||
*/
|
||||
static void query_name(struct reslist *request)
|
||||
{
|
||||
char buf[MAXPACKET];
|
||||
int request_len = 0;
|
||||
int ns;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
if ((request_len =
|
||||
irc_res_mkquery(request->queryname, C_IN, request->type, (unsigned char *)buf, sizeof(buf))) > 0)
|
||||
{
|
||||
HEADER *header = (HEADER *)(void *)buf;
|
||||
header->id = request->id;
|
||||
++request->sends;
|
||||
|
||||
ns = send_res_msg(buf, request_len, request->sends);
|
||||
if (ns != -1)
|
||||
request->lastns = ns;
|
||||
}
|
||||
}
|
||||
|
||||
static void resend_query(struct reslist *request)
|
||||
{
|
||||
if (--request->retries <= 0)
|
||||
{
|
||||
(*request->query->callback) (request->query->ptr, NULL);
|
||||
rem_request(request);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (request->type)
|
||||
{
|
||||
case T_PTR:
|
||||
do_query_number(NULL, &request->addr, request);
|
||||
break;
|
||||
case T_A:
|
||||
#ifdef RB_IPV6
|
||||
case T_AAAA:
|
||||
#endif
|
||||
do_query_name(NULL, request->name, request, request->type);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* check_question - check if the reply really belongs to the
|
||||
* name we queried (to guard against late replies from previous
|
||||
* queries with the same id).
|
||||
*/
|
||||
static int check_question(struct reslist *request, HEADER * header, char *buf, char *eob)
|
||||
{
|
||||
char hostbuf[IRCD_RES_HOSTLEN + 1]; /* working buffer */
|
||||
unsigned char *current; /* current position in buf */
|
||||
int n; /* temp count */
|
||||
|
||||
current = (unsigned char *)buf + sizeof(HEADER);
|
||||
if (header->qdcount != 1)
|
||||
return 0;
|
||||
n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob, current, hostbuf,
|
||||
sizeof(hostbuf));
|
||||
if (n <= 0)
|
||||
return 0;
|
||||
if (rb_strcasecmp(hostbuf, request->queryname))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* proc_answer - process name server reply
|
||||
*/
|
||||
static int proc_answer(struct reslist *request, HEADER * header, char *buf, char *eob)
|
||||
{
|
||||
char hostbuf[IRCD_RES_HOSTLEN + 100]; /* working buffer */
|
||||
unsigned char *current; /* current position in buf */
|
||||
int type; /* answer type */
|
||||
int n; /* temp count */
|
||||
int rd_length;
|
||||
struct sockaddr_in *v4; /* conversion */
|
||||
#ifdef RB_IPV6
|
||||
struct sockaddr_in6 *v6;
|
||||
#endif
|
||||
current = (unsigned char *)buf + sizeof(HEADER);
|
||||
|
||||
for (; header->qdcount > 0; --header->qdcount)
|
||||
{
|
||||
if ((n = irc_dn_skipname(current, (unsigned char *)eob)) < 0)
|
||||
return 0;
|
||||
|
||||
current += (size_t) n + QFIXEDSZ;
|
||||
}
|
||||
|
||||
/*
|
||||
* process each answer sent to us blech.
|
||||
*/
|
||||
while (header->ancount > 0 && (char *)current < eob)
|
||||
{
|
||||
header->ancount--;
|
||||
|
||||
n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob, current, hostbuf,
|
||||
sizeof(hostbuf));
|
||||
|
||||
if (n < 0)
|
||||
{
|
||||
/*
|
||||
* broken message
|
||||
*/
|
||||
return (0);
|
||||
}
|
||||
else if (n == 0)
|
||||
{
|
||||
/*
|
||||
* no more answers left
|
||||
*/
|
||||
return (0);
|
||||
}
|
||||
|
||||
hostbuf[IRCD_RES_HOSTLEN] = '\0';
|
||||
|
||||
/* With Address arithmetic you have to be very anal
|
||||
* this code was not working on alpha due to that
|
||||
* (spotted by rodder/jailbird/dianora)
|
||||
*/
|
||||
current += (size_t) n;
|
||||
|
||||
if (!(((char *)current + ANSWER_FIXED_SIZE) < eob))
|
||||
break;
|
||||
|
||||
type = irc_ns_get16(current);
|
||||
current += TYPE_SIZE;
|
||||
|
||||
(void) irc_ns_get16(current);
|
||||
current += CLASS_SIZE;
|
||||
|
||||
request->ttl = irc_ns_get32(current);
|
||||
current += TTL_SIZE;
|
||||
|
||||
rd_length = irc_ns_get16(current);
|
||||
current += RDLENGTH_SIZE;
|
||||
|
||||
/*
|
||||
* Wait to set request->type until we verify this structure
|
||||
*/
|
||||
switch (type)
|
||||
{
|
||||
case T_A:
|
||||
if (request->type != T_A)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* check for invalid rd_length or too many addresses
|
||||
*/
|
||||
if (rd_length != sizeof(struct in_addr))
|
||||
return (0);
|
||||
v4 = (struct sockaddr_in *)&request->addr;
|
||||
SET_SS_LEN(&request->addr, sizeof(struct sockaddr_in));
|
||||
v4->sin_family = AF_INET;
|
||||
memcpy(&v4->sin_addr, current, sizeof(struct in_addr));
|
||||
return (1);
|
||||
#ifdef RB_IPV6
|
||||
case T_AAAA:
|
||||
if (request->type != T_AAAA)
|
||||
return (0);
|
||||
if (rd_length != sizeof(struct in6_addr))
|
||||
return (0);
|
||||
SET_SS_LEN(&request->addr, sizeof(struct sockaddr_in6));
|
||||
v6 = (struct sockaddr_in6 *)&request->addr;
|
||||
v6->sin6_family = AF_INET6;
|
||||
memcpy(&v6->sin6_addr, current, sizeof(struct in6_addr));
|
||||
return (1);
|
||||
#endif
|
||||
case T_PTR:
|
||||
if (request->type != T_PTR)
|
||||
return (0);
|
||||
n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob, current,
|
||||
hostbuf, sizeof(hostbuf));
|
||||
if (n < 0)
|
||||
return (0); /* broken message */
|
||||
else if (n == 0)
|
||||
return (0); /* no more answers left */
|
||||
|
||||
rb_strlcpy(request->name, hostbuf, IRCD_RES_HOSTLEN + 1);
|
||||
|
||||
return (1);
|
||||
case T_CNAME:
|
||||
/* real answer will follow */
|
||||
current += rd_length;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* res_read_single_reply - read a dns reply from the nameserver and process it.
|
||||
* Return value: 1 if a packet was read, 0 otherwise
|
||||
*/
|
||||
static int res_read_single_reply(rb_fde_t *F, void *data)
|
||||
{
|
||||
char buf[sizeof(HEADER) + MAXPACKET]
|
||||
/* Sparc and alpha need 16bit-alignment for accessing header->id
|
||||
* (which is uint16_t). Because of the header = (HEADER*) buf;
|
||||
* lateron, this is neeeded. --FaUl
|
||||
*/
|
||||
#if defined(__sparc__) || defined(__alpha__)
|
||||
__attribute__ ((aligned(16)))
|
||||
#endif
|
||||
;
|
||||
HEADER *header;
|
||||
struct reslist *request = NULL;
|
||||
struct DNSReply *reply = NULL;
|
||||
int rc;
|
||||
int answer_count;
|
||||
socklen_t len = sizeof(struct rb_sockaddr_storage);
|
||||
struct rb_sockaddr_storage lsin;
|
||||
int ns;
|
||||
|
||||
rc = recvfrom(rb_get_fd(F), buf, sizeof(buf), 0, (struct sockaddr *)&lsin, &len);
|
||||
|
||||
/* No packet */
|
||||
if (rc == 0 || rc == -1)
|
||||
return 0;
|
||||
|
||||
/* Too small */
|
||||
if (rc <= (int)(sizeof(HEADER)))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* convert DNS reply reader from Network byte order to CPU byte order.
|
||||
*/
|
||||
header = (HEADER *)(void *)buf;
|
||||
header->ancount = ntohs(header->ancount);
|
||||
header->qdcount = ntohs(header->qdcount);
|
||||
header->nscount = ntohs(header->nscount);
|
||||
header->arcount = ntohs(header->arcount);
|
||||
|
||||
/*
|
||||
* response for an id which we have already received an answer for
|
||||
* just ignore this response.
|
||||
*/
|
||||
if (0 == (request = find_id(header->id)))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* check against possibly fake replies
|
||||
*/
|
||||
ns = res_ourserver(&lsin);
|
||||
if (ns == -1)
|
||||
return 1;
|
||||
|
||||
if (ns != request->lastns)
|
||||
{
|
||||
/*
|
||||
* We'll accept the late reply, but penalize it a little more to make
|
||||
* sure a laggy server doesn't end up favored.
|
||||
*/
|
||||
ns_failure_count[ns] += 3;
|
||||
}
|
||||
|
||||
|
||||
if (!check_question(request, header, buf, buf + rc))
|
||||
return 1;
|
||||
|
||||
if ((header->rcode != NO_ERRORS) || (header->ancount == 0))
|
||||
{
|
||||
/*
|
||||
* RFC 2136 states that in the event of a server returning SERVFAIL
|
||||
* or NOTIMP, the request should be resent to the next server.
|
||||
* Additionally, if the server refuses our query, resend it as well.
|
||||
* -- mr_flea
|
||||
*/
|
||||
if (SERVFAIL == header->rcode || NOTIMP == header->rcode ||
|
||||
REFUSED == header->rcode)
|
||||
{
|
||||
ns_failure_count[ns]++;
|
||||
resend_query(request);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Either a fatal error was returned or no answer. Cancel the
|
||||
* request.
|
||||
*/
|
||||
if (NXDOMAIN == header->rcode)
|
||||
{
|
||||
/* If the rcode is NXDOMAIN, treat it as a good response. */
|
||||
ns_failure_count[ns] /= 4;
|
||||
}
|
||||
(*request->query->callback) (request->query->ptr, NULL);
|
||||
rem_request(request);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
* If this fails there was an error decoding the received packet.
|
||||
* -- jilles
|
||||
*/
|
||||
answer_count = proc_answer(request, header, buf, buf + rc);
|
||||
|
||||
if (answer_count)
|
||||
{
|
||||
if (request->type == T_PTR)
|
||||
{
|
||||
if (request->name == NULL)
|
||||
{
|
||||
/*
|
||||
* Got a PTR response with no name, something strange is
|
||||
* happening. Try another DNS server.
|
||||
*/
|
||||
ns_failure_count[ns]++;
|
||||
resend_query(request);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Lookup the 'authoritative' name that we were given for the
|
||||
* ip#.
|
||||
*/
|
||||
#ifdef RB_IPV6
|
||||
if (GET_SS_FAMILY(&request->addr) == AF_INET6)
|
||||
gethost_byname_type_fqdn(request->name, request->query, T_AAAA);
|
||||
else
|
||||
#endif
|
||||
gethost_byname_type_fqdn(request->name, request->query, T_A);
|
||||
rem_request(request);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* got a name and address response, client resolved
|
||||
*/
|
||||
reply = make_dnsreply(request);
|
||||
(*request->query->callback) (request->query->ptr, reply);
|
||||
rb_free(reply);
|
||||
rem_request(request);
|
||||
}
|
||||
|
||||
ns_failure_count[ns] /= 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Invalid or corrupt reply - try another resolver. */
|
||||
ns_failure_count[ns]++;
|
||||
resend_query(request);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
res_readreply(rb_fde_t *F, void *data)
|
||||
{
|
||||
while (res_read_single_reply(F, data))
|
||||
;
|
||||
rb_setselect(F, RB_SELECT_READ, res_readreply, NULL);
|
||||
}
|
||||
|
||||
static struct DNSReply *
|
||||
make_dnsreply(struct reslist *request)
|
||||
{
|
||||
struct DNSReply *cp;
|
||||
lrb_assert(request != 0);
|
||||
|
||||
cp = (struct DNSReply *)rb_malloc(sizeof(struct DNSReply));
|
||||
|
||||
cp->h_name = request->name;
|
||||
memcpy(&cp->addr, &request->addr, sizeof(cp->addr));
|
||||
return (cp);
|
||||
}
|
37
authd/res.h
37
authd/res.h
|
@ -1,37 +0,0 @@
|
|||
/*
|
||||
* res.h for referencing functions in res.c, reslib.c
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _CHARYBDIS_RES_H
|
||||
#define _CHARYBDIS_RES_H
|
||||
|
||||
/* Maximum number of nameservers in /etc/resolv.conf we care about
|
||||
* In hybrid, this was 2 -- but in Charybdis, we want to track
|
||||
* a few more than that ;) --nenolod
|
||||
*/
|
||||
#define IRCD_MAXNS 10
|
||||
#define RESOLVER_HOSTLEN 255
|
||||
|
||||
struct DNSReply
|
||||
{
|
||||
char *h_name;
|
||||
struct rb_sockaddr_storage addr;
|
||||
};
|
||||
|
||||
struct DNSQuery
|
||||
{
|
||||
void *ptr; /* pointer used by callback to identify request */
|
||||
void (*callback)(void* vptr, struct DNSReply *reply); /* callback to call */
|
||||
};
|
||||
|
||||
extern struct rb_sockaddr_storage irc_nsaddr_list[];
|
||||
extern int irc_nscount;
|
||||
|
||||
extern void init_resolver(void);
|
||||
extern void restart_resolver(void);
|
||||
extern void gethost_byname_type(const char *, struct DNSQuery *, int);
|
||||
extern void gethost_byaddr(const struct rb_sockaddr_storage *, struct DNSQuery *);
|
||||
extern void build_rdns(char *, size_t, const struct rb_sockaddr_storage *, const char *);
|
||||
|
||||
#endif
|
1218
authd/reslib.cc
1218
authd/reslib.cc
File diff suppressed because it is too large
Load diff
126
authd/reslib.h
126
authd/reslib.h
|
@ -1,126 +0,0 @@
|
|||
/*
|
||||
* include/irc_reslib.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _CHARYBDIS_RESLIB_H
|
||||
#define _CHARYBDIS_RESLIB_H
|
||||
|
||||
/* Longest hostname we're willing to work with.
|
||||
* Due to DNSBLs this is more than HOSTLEN.
|
||||
*/
|
||||
#define IRCD_RES_HOSTLEN 255
|
||||
|
||||
/* Here we define some values lifted from nameser.h */
|
||||
#define NS_NOTIFY_OP 4
|
||||
#define NS_INT16SZ 2
|
||||
#define NS_IN6ADDRSZ 16
|
||||
#define NS_INADDRSZ 4
|
||||
#define NS_INT32SZ 4
|
||||
#define NS_CMPRSFLGS 0xc0
|
||||
#define NS_MAXCDNAME 255
|
||||
#define QUERY 0
|
||||
#define IQUERY 1
|
||||
#define NO_ERRORS 0
|
||||
#define SERVFAIL 2
|
||||
#define NXDOMAIN 3
|
||||
#define NOTIMP 4
|
||||
#define REFUSED 5
|
||||
#define T_A 1
|
||||
#define T_AAAA 28
|
||||
#define T_PTR 12
|
||||
#define T_CNAME 5
|
||||
#define T_NULL 10
|
||||
#define C_IN 1
|
||||
#define QFIXEDSZ 4
|
||||
#define RRFIXEDSZ 10
|
||||
#define HFIXEDSZ 12
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned id :16; /* query identification number */
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
/* fields in third byte */
|
||||
unsigned qr: 1; /* response flag */
|
||||
unsigned opcode: 4; /* purpose of message */
|
||||
unsigned aa: 1; /* authoritive answer */
|
||||
unsigned tc: 1; /* truncated message */
|
||||
unsigned rd: 1; /* recursion desired */
|
||||
/* fields in fourth byte */
|
||||
unsigned ra: 1; /* recursion available */
|
||||
unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */
|
||||
unsigned ad: 1; /* authentic data from named */
|
||||
unsigned cd: 1; /* checking disabled by resolver */
|
||||
unsigned rcode :4; /* response code */
|
||||
#else
|
||||
/* fields in third byte */
|
||||
unsigned rd :1; /* recursion desired */
|
||||
unsigned tc :1; /* truncated message */
|
||||
unsigned aa :1; /* authoritive answer */
|
||||
unsigned opcode :4; /* purpose of message */
|
||||
unsigned qr :1; /* response flag */
|
||||
/* fields in fourth byte */
|
||||
unsigned rcode :4; /* response code */
|
||||
unsigned cd: 1; /* checking disabled by resolver */
|
||||
unsigned ad: 1; /* authentic data from named */
|
||||
unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */
|
||||
unsigned ra :1; /* recursion available */
|
||||
#endif
|
||||
/* remaining bytes */
|
||||
unsigned qdcount :16; /* number of question entries */
|
||||
unsigned ancount :16; /* number of answer entries */
|
||||
unsigned nscount :16; /* number of authority entries */
|
||||
unsigned arcount :16; /* number of resource entries */
|
||||
} HEADER;
|
||||
|
||||
/*
|
||||
* Inline versions of get/put short/long. Pointer is advanced.
|
||||
*/
|
||||
#define IRC_NS_GET16(s, cp) { \
|
||||
const unsigned char *t_cp = (const unsigned char *)(cp); \
|
||||
(s) = ((uint16_t)t_cp[0] << 8) \
|
||||
| ((uint16_t)t_cp[1]) \
|
||||
; \
|
||||
(cp) += NS_INT16SZ; \
|
||||
}
|
||||
|
||||
#define IRC_NS_GET32(l, cp) { \
|
||||
const unsigned char *t_cp = (const unsigned char *)(cp); \
|
||||
(l) = ((uint32_t)t_cp[0] << 24) \
|
||||
| ((uint32_t)t_cp[1] << 16) \
|
||||
| ((uint32_t)t_cp[2] << 8) \
|
||||
| ((uint32_t)t_cp[3]) \
|
||||
; \
|
||||
(cp) += NS_INT32SZ; \
|
||||
}
|
||||
|
||||
#define IRC_NS_PUT16(s, cp) { \
|
||||
uint16_t t_s = (uint16_t)(s); \
|
||||
unsigned char *t_cp = (unsigned char *)(cp); \
|
||||
*t_cp++ = t_s >> 8; \
|
||||
*t_cp = t_s; \
|
||||
(cp) += NS_INT16SZ; \
|
||||
}
|
||||
|
||||
#define IRC_NS_PUT32(l, cp) { \
|
||||
uint32_t t_l = (uint32_t)(l); \
|
||||
unsigned char *t_cp = (unsigned char *)(cp); \
|
||||
*t_cp++ = t_l >> 24; \
|
||||
*t_cp++ = t_l >> 16; \
|
||||
*t_cp++ = t_l >> 8; \
|
||||
*t_cp = t_l; \
|
||||
(cp) += NS_INT32SZ; \
|
||||
}
|
||||
|
||||
extern int irc_res_init(void);
|
||||
extern int irc_dn_expand(const unsigned char *msg, const unsigned char *eom, const unsigned char *src, char *dst, int dstsiz);
|
||||
extern int irc_dn_skipname(const unsigned char *ptr, const unsigned char *eom);
|
||||
extern unsigned int irc_ns_get16(const unsigned char *src);
|
||||
extern unsigned long irc_ns_get32(const unsigned char *src);
|
||||
extern void irc_ns_put16(unsigned int src, unsigned char *dst);
|
||||
extern void irc_ns_put32(unsigned long src, unsigned char *dst);
|
||||
extern int irc_res_mkquery(const char *dname, int class_, int type, unsigned char *buf, int buflen);
|
||||
|
||||
extern char irc_domain[IRCD_RES_HOSTLEN + 1];
|
||||
|
||||
#endif
|
278
authd/reslist.cc
278
authd/reslist.cc
|
@ -1,278 +0,0 @@
|
|||
/*
|
||||
* reslist.c - get nameservers from windows *
|
||||
*
|
||||
* ircd-ratbox related changes are as follows
|
||||
*
|
||||
* Copyright (C) 2008 Aaron Sethman <androsyn@ratbox.org>
|
||||
* Copyright (C) 2008-2012 ircd-ratbox development team
|
||||
*
|
||||
* pretty much all of this was yanked from c-ares ares_init.c here is the original
|
||||
* header from there --
|
||||
*
|
||||
* Id: ares_init.c,v 1.72 2008-05-15 00:00:19 yangtse Exp $
|
||||
* Copyright 1998 by the Massachusetts Institute of Technology.
|
||||
* Copyright (C) 2007-2008 by Daniel Stenberg
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose and without
|
||||
* fee is hereby granted, provided that the above copyright
|
||||
* notice appear in all copies and that both that copyright
|
||||
* notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of M.I.T. not be used in
|
||||
* advertising or publicity pertaining to distribution of the
|
||||
* software without specific, written prior permission.
|
||||
* M.I.T. makes no representations about the suitability of
|
||||
* this software for any purpose. It is provided "as is"
|
||||
* without express or implied warranty.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <rb/rb.h>
|
||||
#include <windows.h>
|
||||
#include <iphlpapi.h>
|
||||
|
||||
const char *get_windows_nameservers(void);
|
||||
|
||||
#ifndef INADDR_NONE
|
||||
#define INADDR_NONE ((unsigned int) 0xffffffff)
|
||||
#endif /* INADDR_NONE */
|
||||
|
||||
#define IS_NT() ((int)GetVersion() > 0)
|
||||
#define WIN_NS_9X "System\\CurrentControlSet\\Services\\VxD\\MSTCP"
|
||||
#define WIN_NS_NT_KEY "System\\CurrentControlSet\\Services\\Tcpip\\Parameters"
|
||||
#define NAMESERVER "NameServer"
|
||||
#define DHCPNAMESERVER "DhcpNameServer"
|
||||
#define DATABASEPATH "DatabasePath"
|
||||
#define WIN_PATH_HOSTS "\\hosts"
|
||||
|
||||
static int
|
||||
get_iphlpapi_dns_info(char *ret_buf, size_t ret_size)
|
||||
{
|
||||
FIXED_INFO *fi = (FIXED_INFO *)alloca(sizeof(*fi));
|
||||
DWORD size = sizeof(*fi);
|
||||
typedef DWORD(WINAPI * get_net_param_func) (FIXED_INFO *, DWORD *);
|
||||
get_net_param_func xxGetNetworkParams; /* available only on Win-98/2000+ */
|
||||
HMODULE handle;
|
||||
IP_ADDR_STRING *ipAddr;
|
||||
int i, count = 0;
|
||||
int debug = 0;
|
||||
size_t ip_size = sizeof("255.255.255.255,") - 1;
|
||||
size_t left = ret_size;
|
||||
char *ret = ret_buf;
|
||||
HRESULT res;
|
||||
|
||||
if(!fi)
|
||||
return (0);
|
||||
|
||||
handle = LoadLibrary("iphlpapi.dll");
|
||||
if(!handle)
|
||||
return (0);
|
||||
|
||||
xxGetNetworkParams = (get_net_param_func) GetProcAddress(handle, "GetNetworkParams");
|
||||
if(!xxGetNetworkParams)
|
||||
goto quit;
|
||||
|
||||
res = (*xxGetNetworkParams) (fi, &size);
|
||||
if((res != ERROR_BUFFER_OVERFLOW) && (res != ERROR_SUCCESS))
|
||||
goto quit;
|
||||
|
||||
fi = (FIXED_INFO *)alloca(size);
|
||||
if(!fi || (*xxGetNetworkParams) (fi, &size) != ERROR_SUCCESS)
|
||||
goto quit;
|
||||
|
||||
if(debug)
|
||||
{
|
||||
printf("Host Name: %s\n", fi->HostName);
|
||||
printf("Domain Name: %s\n", fi->DomainName);
|
||||
printf("DNS Servers:\n" " %s (primary)\n", fi->DnsServerList.IpAddress.String);
|
||||
}
|
||||
if(strlen(fi->DnsServerList.IpAddress.String) > 0 &&
|
||||
inet_addr(fi->DnsServerList.IpAddress.String) != INADDR_NONE && left > ip_size)
|
||||
{
|
||||
ret += sprintf(ret, "%s,", fi->DnsServerList.IpAddress.String);
|
||||
left -= ret - ret_buf;
|
||||
count++;
|
||||
}
|
||||
|
||||
for(i = 0, ipAddr = fi->DnsServerList.Next; ipAddr && left > ip_size;
|
||||
ipAddr = ipAddr->Next, i++)
|
||||
{
|
||||
if(inet_addr(ipAddr->IpAddress.String) != INADDR_NONE)
|
||||
{
|
||||
ret += sprintf(ret, "%s,", ipAddr->IpAddress.String);
|
||||
left -= ret - ret_buf;
|
||||
count++;
|
||||
}
|
||||
if(debug)
|
||||
printf(" %s (secondary %d)\n", ipAddr->IpAddress.String, i + 1);
|
||||
}
|
||||
|
||||
quit:
|
||||
if(handle)
|
||||
FreeLibrary(handle);
|
||||
|
||||
if(debug && left <= ip_size)
|
||||
printf("Too many nameservers. Truncating to %d addressess", count);
|
||||
if(ret > ret_buf)
|
||||
ret[-1] = '\0';
|
||||
return (count);
|
||||
}
|
||||
|
||||
/*
|
||||
* Warning: returns a dynamically allocated buffer, the user MUST
|
||||
* use free() / rb_free() if the function returns 1
|
||||
*/
|
||||
static int
|
||||
get_res_nt(HKEY hKey, const char *subkey, char **obuf)
|
||||
{
|
||||
/* Test for the size we need */
|
||||
DWORD size = 0;
|
||||
int result;
|
||||
|
||||
result = RegQueryValueEx(hKey, subkey, 0, NULL, NULL, &size);
|
||||
if((result != ERROR_SUCCESS && result != ERROR_MORE_DATA) || !size)
|
||||
return 0;
|
||||
*obuf = (char *)rb_malloc(size + 1);
|
||||
if(!*obuf)
|
||||
return 0;
|
||||
|
||||
if(RegQueryValueEx(hKey, subkey, 0, NULL, (LPBYTE) * obuf, &size) != ERROR_SUCCESS)
|
||||
{
|
||||
rb_free(*obuf);
|
||||
return 0;
|
||||
}
|
||||
if(size == 1)
|
||||
{
|
||||
rb_free(*obuf);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
get_res_interfaces_nt(HKEY hKey, const char *subkey, char **obuf)
|
||||
{
|
||||
char enumbuf[39]; /* GUIDs are 38 chars + 1 for NULL */
|
||||
DWORD enum_size = 39;
|
||||
int idx = 0;
|
||||
HKEY hVal;
|
||||
|
||||
while(RegEnumKeyEx(hKey, idx++, enumbuf, &enum_size, 0,
|
||||
NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS)
|
||||
{
|
||||
int rc;
|
||||
|
||||
enum_size = 39;
|
||||
if(RegOpenKeyEx(hKey, enumbuf, 0, KEY_QUERY_VALUE, &hVal) != ERROR_SUCCESS)
|
||||
continue;
|
||||
rc = get_res_nt(hVal, subkey, obuf);
|
||||
RegCloseKey(hVal);
|
||||
if(rc)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *
|
||||
get_windows_nameservers(void)
|
||||
{
|
||||
/*
|
||||
NameServer info via IPHLPAPI (IP helper API):
|
||||
GetNetworkParams() should be the trusted source for this.
|
||||
Available in Win-98/2000 and later. If that fail, fall-back to
|
||||
registry information.
|
||||
|
||||
NameServer Registry:
|
||||
|
||||
On Windows 9X, the DNS server can be found in:
|
||||
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\VxD\MSTCP\NameServer
|
||||
|
||||
On Windows NT/2000/XP/2003:
|
||||
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\NameServer
|
||||
or
|
||||
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\DhcpNameServer
|
||||
or
|
||||
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\{AdapterID}\
|
||||
NameServer
|
||||
or
|
||||
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\{AdapterID}\
|
||||
DhcpNameServer
|
||||
*/
|
||||
static char namelist[512];
|
||||
HKEY mykey;
|
||||
HKEY subkey;
|
||||
DWORD data_type;
|
||||
DWORD bytes;
|
||||
DWORD result;
|
||||
char *line = NULL;
|
||||
memset(&namelist, 0, sizeof(namelist));
|
||||
if(get_iphlpapi_dns_info(namelist, sizeof(namelist)) > 0)
|
||||
{
|
||||
return namelist;
|
||||
}
|
||||
|
||||
if(IS_NT())
|
||||
{
|
||||
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0,
|
||||
KEY_READ, &mykey) == ERROR_SUCCESS)
|
||||
{
|
||||
RegOpenKeyEx(mykey, "Interfaces", 0,
|
||||
KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &subkey);
|
||||
if(get_res_nt(mykey, NAMESERVER, &line))
|
||||
{
|
||||
rb_strlcpy(namelist, line, sizeof(namelist));
|
||||
return namelist;
|
||||
}
|
||||
else if(get_res_nt(mykey, DHCPNAMESERVER, &line))
|
||||
{
|
||||
rb_strlcpy(namelist, line, sizeof(namelist));
|
||||
rb_free(line);
|
||||
}
|
||||
/* Try the interfaces */
|
||||
else if(get_res_interfaces_nt(subkey, NAMESERVER, &line))
|
||||
{
|
||||
rb_strlcpy(namelist, line, sizeof(namelist));
|
||||
rb_free(line);
|
||||
}
|
||||
else if(get_res_interfaces_nt(subkey, DHCPNAMESERVER, &line))
|
||||
{
|
||||
rb_strlcpy(namelist, line, sizeof(namelist));
|
||||
rb_free(line);
|
||||
}
|
||||
RegCloseKey(subkey);
|
||||
RegCloseKey(mykey);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_9X, 0,
|
||||
KEY_READ, &mykey) == ERROR_SUCCESS)
|
||||
{
|
||||
if((result = RegQueryValueEx(mykey, NAMESERVER, NULL, &data_type,
|
||||
NULL, &bytes)) == ERROR_SUCCESS ||
|
||||
result == ERROR_MORE_DATA)
|
||||
{
|
||||
if(bytes)
|
||||
{
|
||||
line = (char *)rb_malloc(bytes + 1);
|
||||
if(RegQueryValueEx(mykey, NAMESERVER, NULL, &data_type,
|
||||
(unsigned char *)line, &bytes) ==
|
||||
ERROR_SUCCESS)
|
||||
{
|
||||
rb_strlcpy(namelist, line, sizeof(namelist));
|
||||
}
|
||||
free(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
RegCloseKey(mykey);
|
||||
}
|
||||
if(strlen(namelist) > 0)
|
||||
return namelist;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -1,62 +0,0 @@
|
|||
AM_CFLAGS = \
|
||||
@SQLITE_CFLAGS@
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-DSQLITE_THREADSAFE=0 \
|
||||
-DSQLITE_OMIT_LOAD_EXTENSION \
|
||||
-I$(top_srcdir)/include \
|
||||
@BOOST_CPPFLAGS@
|
||||
|
||||
AM_LDFLAGS = \
|
||||
-L$(top_srcdir)/ircd \
|
||||
-L$(top_srcdir)/rb \
|
||||
@BOOST_LDFLAGS@
|
||||
|
||||
|
||||
bin_PROGRAMS = bandb
|
||||
|
||||
bandb_DEPENDENCIES = \
|
||||
@SQLITE_OBJ@
|
||||
|
||||
bandb_LDADD = \
|
||||
-lircd \
|
||||
-lrb \
|
||||
@SQLITE_LDFLAGS@ \
|
||||
@SQLITE_OBJ@ \
|
||||
@SQLITE_LIBS@ \
|
||||
@BOOST_LIBS@
|
||||
|
||||
EXTRA_bandb_SOURCES = \
|
||||
sqlite3.c
|
||||
|
||||
bandb_SOURCES = \
|
||||
bandb.cc \
|
||||
rsdb_sqlite3.cc \
|
||||
rsdb_snprintf.c
|
||||
|
||||
|
||||
bin_PROGRAMS += bantool
|
||||
|
||||
bantool_DEPENDENCIES = \
|
||||
@SQLITE_OBJ@
|
||||
|
||||
bantool_LDADD = \
|
||||
-lircd \
|
||||
-lrb \
|
||||
@SQLITE_LDFLAGS@ \
|
||||
@SQLITE_LIBS@ \
|
||||
@SQLITE_OBJ@ \
|
||||
@BOOST_LIBS@
|
||||
|
||||
EXTRA_bantool_SOURCES = \
|
||||
sqlite3.c
|
||||
|
||||
bantool_SOURCES = \
|
||||
bantool.cc \
|
||||
rsdb_sqlite3.cc \
|
||||
rsdb_snprintf.c
|
||||
|
||||
|
||||
sqlite3.o:
|
||||
echo -e "\033[1;36m***\033[0m Compiling sqlite3 may take a moment..."
|
||||
$(COMPILE) -w -c -o sqlite3.o sqlite3.c
|
339
bandb/bandb.cc
339
bandb/bandb.cc
|
@ -1,339 +0,0 @@
|
|||
/* bandb/bandb.c
|
||||
*
|
||||
* Copyright (C) 2006 Lee Hardy <lee -at- leeh.co.uk>
|
||||
* Copyright (C) 2006-2008 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.
|
||||
*/
|
||||
|
||||
#include <ircd/stdinc.h>
|
||||
#include "rsdb.h"
|
||||
|
||||
using namespace ircd::defaults;
|
||||
|
||||
#define MAXPARA 10
|
||||
|
||||
#define COMMIT_INTERVAL 3 /* seconds */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BANDB_KLINE,
|
||||
BANDB_DLINE,
|
||||
BANDB_XLINE,
|
||||
BANDB_RESV,
|
||||
LAST_BANDB_TYPE
|
||||
} bandb_type;
|
||||
|
||||
static char bandb_letter[LAST_BANDB_TYPE] = {
|
||||
'K', 'D', 'X', 'R'
|
||||
};
|
||||
|
||||
static const char *bandb_table[LAST_BANDB_TYPE] = {
|
||||
"kline", "dline", "xline", "resv"
|
||||
};
|
||||
|
||||
|
||||
static rb_helper *bandb_helper;
|
||||
static int in_transaction;
|
||||
|
||||
static void check_schema(void);
|
||||
|
||||
static void
|
||||
bandb_commit(void *unused)
|
||||
{
|
||||
rsdb_transaction(RSDB_TRANS_END);
|
||||
in_transaction = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
parse_ban(bandb_type type, char *parv[], int parc)
|
||||
{
|
||||
const char *mask1 = NULL;
|
||||
const char *mask2 = NULL;
|
||||
const char *oper = NULL;
|
||||
const char *curtime = NULL;
|
||||
const char *reason = NULL;
|
||||
const char *perm = NULL;
|
||||
int para = 1;
|
||||
|
||||
if(type == BANDB_KLINE)
|
||||
{
|
||||
if(parc != 7)
|
||||
return;
|
||||
}
|
||||
else if(parc != 6)
|
||||
return;
|
||||
|
||||
mask1 = parv[para++];
|
||||
|
||||
if(type == BANDB_KLINE)
|
||||
mask2 = parv[para++];
|
||||
|
||||
oper = parv[para++];
|
||||
curtime = parv[para++];
|
||||
perm = parv[para++];
|
||||
reason = parv[para++];
|
||||
|
||||
if(!in_transaction)
|
||||
{
|
||||
rsdb_transaction(RSDB_TRANS_START);
|
||||
in_transaction = 1;
|
||||
rb_event_addonce("bandb_commit", bandb_commit, NULL,
|
||||
COMMIT_INTERVAL);
|
||||
}
|
||||
|
||||
rsdb_exec(NULL,
|
||||
"INSERT INTO %s (mask1, mask2, oper, time, perm, reason) VALUES('%Q', '%Q', '%Q', %s, %s, '%Q')",
|
||||
bandb_table[type], mask1, mask2 ? mask2 : "", oper, curtime, perm, reason);
|
||||
}
|
||||
|
||||
static void
|
||||
parse_unban(bandb_type type, char *parv[], int parc)
|
||||
{
|
||||
const char *mask1 = NULL;
|
||||
const char *mask2 = NULL;
|
||||
|
||||
if(type == BANDB_KLINE)
|
||||
{
|
||||
if(parc != 3)
|
||||
return;
|
||||
}
|
||||
else if(parc != 2)
|
||||
return;
|
||||
|
||||
mask1 = parv[1];
|
||||
|
||||
if(type == BANDB_KLINE)
|
||||
mask2 = parv[2];
|
||||
|
||||
if(!in_transaction)
|
||||
{
|
||||
rsdb_transaction(RSDB_TRANS_START);
|
||||
in_transaction = 1;
|
||||
rb_event_addonce("bandb_commit", bandb_commit, NULL,
|
||||
COMMIT_INTERVAL);
|
||||
}
|
||||
|
||||
rsdb_exec(NULL, "DELETE FROM %s WHERE mask1='%Q' AND mask2='%Q'",
|
||||
bandb_table[type], mask1, mask2 ? mask2 : "");
|
||||
}
|
||||
|
||||
static void
|
||||
list_bans(void)
|
||||
{
|
||||
static char buf[512];
|
||||
struct rsdb_table table;
|
||||
int i, j;
|
||||
|
||||
/* schedule a clear of anything already pending */
|
||||
rb_helper_write_queue(bandb_helper, "C");
|
||||
|
||||
for(i = 0; i < LAST_BANDB_TYPE; i++)
|
||||
{
|
||||
rsdb_exec_fetch(&table, "SELECT mask1,mask2,oper,reason FROM %s WHERE 1",
|
||||
bandb_table[i]);
|
||||
|
||||
for(j = 0; j < table.row_count; j++)
|
||||
{
|
||||
if(i == BANDB_KLINE)
|
||||
snprintf(buf, sizeof(buf), "%c %s %s %s :%s",
|
||||
bandb_letter[i], table.row[j][0],
|
||||
table.row[j][1], table.row[j][2], table.row[j][3]);
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "%c %s %s :%s",
|
||||
bandb_letter[i], table.row[j][0],
|
||||
table.row[j][2], table.row[j][3]);
|
||||
|
||||
rb_helper_write_queue(bandb_helper, "%s", buf);
|
||||
}
|
||||
|
||||
rsdb_exec_fetch_end(&table);
|
||||
}
|
||||
|
||||
rb_helper_write(bandb_helper, "F");
|
||||
}
|
||||
|
||||
static void
|
||||
parse_request(rb_helper *helper)
|
||||
{
|
||||
static char *parv[MAXPARA + 1];
|
||||
static char readbuf[READBUF_SIZE];
|
||||
int parc;
|
||||
int len;
|
||||
|
||||
|
||||
while((len = rb_helper_read(helper, readbuf, sizeof(readbuf))) > 0)
|
||||
{
|
||||
parc = rb_string_to_array(readbuf, parv, MAXPARA);
|
||||
|
||||
if(parc < 1)
|
||||
continue;
|
||||
|
||||
switch (parv[0][0])
|
||||
{
|
||||
case 'K':
|
||||
parse_ban(BANDB_KLINE, parv, parc);
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
parse_ban(BANDB_DLINE, parv, parc);
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
parse_ban(BANDB_XLINE, parv, parc);
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
parse_ban(BANDB_RESV, parv, parc);
|
||||
break;
|
||||
|
||||
case 'k':
|
||||
parse_unban(BANDB_KLINE, parv, parc);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
parse_unban(BANDB_DLINE, parv, parc);
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
parse_unban(BANDB_XLINE, parv, parc);
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
parse_unban(BANDB_RESV, parv, parc);
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
list_bans();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
error_cb(rb_helper *helper) __attribute__((noreturn));
|
||||
|
||||
static void
|
||||
error_cb(rb_helper *helper)
|
||||
{
|
||||
if(in_transaction)
|
||||
rsdb_transaction(RSDB_TRANS_END);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifndef WINDOWS
|
||||
static void
|
||||
dummy_handler(int sig)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
setup_signals(void)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
struct sigaction act;
|
||||
|
||||
act.sa_flags = 0;
|
||||
act.sa_handler = SIG_IGN;
|
||||
sigemptyset(&act.sa_mask);
|
||||
sigaddset(&act.sa_mask, SIGPIPE);
|
||||
sigaddset(&act.sa_mask, SIGALRM);
|
||||
#ifdef SIGTRAP
|
||||
sigaddset(&act.sa_mask, SIGTRAP);
|
||||
#endif
|
||||
|
||||
#ifdef SIGWINCH
|
||||
sigaddset(&act.sa_mask, SIGWINCH);
|
||||
sigaction(SIGWINCH, &act, 0);
|
||||
#endif
|
||||
sigaction(SIGPIPE, &act, 0);
|
||||
#ifdef SIGTRAP
|
||||
sigaction(SIGTRAP, &act, 0);
|
||||
#endif
|
||||
|
||||
act.sa_handler = dummy_handler;
|
||||
sigaction(SIGALRM, &act, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
db_error_cb(const char *errstr) __attribute__((noreturn));
|
||||
|
||||
static void
|
||||
db_error_cb(const char *errstr)
|
||||
{
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof(buf), "! :%s", errstr);
|
||||
rb_helper_write(bandb_helper, "%s", buf);
|
||||
rb_sleep(1 << 30, 0);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
setup_signals();
|
||||
bandb_helper = rb_helper_child(parse_request, error_cb, NULL, NULL, NULL, 256, 256, 256); /* XXX fix me */
|
||||
if(bandb_helper == NULL)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"This is the charybdis bandb for internal ircd use.\n");
|
||||
fprintf(stderr,
|
||||
"You aren't supposed to run me directly (did you want bantool?). Exiting.\n");
|
||||
exit(1);
|
||||
}
|
||||
rsdb_init(db_error_cb);
|
||||
check_schema();
|
||||
rb_helper_loop(bandb_helper, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
check_schema(void)
|
||||
{
|
||||
struct rsdb_table table;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < LAST_BANDB_TYPE; i++)
|
||||
{
|
||||
rsdb_exec_fetch(&table,
|
||||
"SELECT name FROM sqlite_master WHERE type='table' AND name='%s'",
|
||||
bandb_table[i]);
|
||||
|
||||
rsdb_exec_fetch_end(&table);
|
||||
|
||||
if(!table.row_count)
|
||||
rsdb_exec(NULL,
|
||||
"CREATE TABLE %s (mask1 TEXT, mask2 TEXT, oper TEXT, time INTEGER, perm INTEGER, reason TEXT)",
|
||||
bandb_table[i]);
|
||||
}
|
||||
}
|
892
bandb/bantool.cc
892
bandb/bantool.cc
|
@ -1,892 +0,0 @@
|
|||
/**
|
||||
* ircd-ratbox: A slightly useful ircd.
|
||||
* bantool.c: The ircd-ratbox database managment tool.
|
||||
*
|
||||
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
|
||||
* Copyright (C) 1996-2002 Hybrid Development Team
|
||||
* Copyright (C) 2002-2008 ircd-ratbox development team
|
||||
* Copyright (C) 2008 Daniel J Reidy <dubkat@gmail.com>
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*
|
||||
* The following server admins have either contributed various configs to test against,
|
||||
* or helped with debugging and feature requests. Many thanks to them.
|
||||
* stevoo / efnet.port80.se
|
||||
* AndroSyn / irc2.choopa.net, irc.igs.ca
|
||||
* Salvation / irc.blessed.net
|
||||
* JamesOff / efnet.demon.co.uk
|
||||
*
|
||||
* Thanks to AndroSyn for challenging me to learn C on the fly :)
|
||||
* BUGS Direct Question, Bug Reports, and Feature Requests to #ratbox on EFnet.
|
||||
* BUGS Complaints >/dev/null
|
||||
*
|
||||
*/
|
||||
|
||||
#include <ircd/stdinc.h>
|
||||
#include "rsdb.h"
|
||||
|
||||
using namespace ircd::defaults;
|
||||
|
||||
#define BT_VERSION "0.4.1"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BANDB_KLINE,
|
||||
BANDB_KLINE_PERM,
|
||||
BANDB_DLINE,
|
||||
BANDB_DLINE_PERM,
|
||||
BANDB_XLINE,
|
||||
BANDB_XLINE_PERM,
|
||||
BANDB_RESV,
|
||||
BANDB_RESV_PERM,
|
||||
LAST_BANDB_TYPE
|
||||
} bandb_type;
|
||||
|
||||
|
||||
static char bandb_letter[LAST_BANDB_TYPE] = {
|
||||
'K', 'K', 'D', 'D', 'X', 'X', 'R', 'R'
|
||||
};
|
||||
|
||||
static const char *bandb_table[LAST_BANDB_TYPE] = {
|
||||
"kline", "kline", "dline", "dline", "xline", "xline", "resv", "resv"
|
||||
};
|
||||
|
||||
static const char *bandb_suffix[LAST_BANDB_TYPE] = {
|
||||
"", ".perm",
|
||||
"", ".perm",
|
||||
"", ".perm",
|
||||
"", ".perm"
|
||||
};
|
||||
|
||||
static char me[PATH_MAX];
|
||||
|
||||
/* *INDENT-OFF* */
|
||||
/* report counters */
|
||||
struct counter
|
||||
{
|
||||
unsigned int klines;
|
||||
unsigned int dlines;
|
||||
unsigned int xlines;
|
||||
unsigned int resvs;
|
||||
unsigned int error;
|
||||
} count = {0, 0, 0, 0, 0};
|
||||
|
||||
/* flags set by command line options */
|
||||
struct flags
|
||||
{
|
||||
bool none;
|
||||
bool export_;
|
||||
bool import;
|
||||
bool verify;
|
||||
bool vacuum;
|
||||
bool pretend;
|
||||
bool verbose;
|
||||
bool wipe;
|
||||
bool dupes_ok;
|
||||
} flag = {true, false, false, false, false, false, false, false, false};
|
||||
/* *INDENT-ON* */
|
||||
|
||||
static int table_has_rows(const char *table);
|
||||
static int table_exists(const char *table);
|
||||
|
||||
static const char *clean_gecos_field(const char *gecos);
|
||||
static char *bt_smalldate(const char *string);
|
||||
static char *getfield(char *newline);
|
||||
static char *strip_quotes(const char *string);
|
||||
static char *mangle_reason(const char *string);
|
||||
static char *escape_quotes(const char *string);
|
||||
|
||||
static void db_error_cb(const char *errstr);
|
||||
static void db_reclaim_slack(void);
|
||||
static void export_config(const char *conf, int id);
|
||||
static void import_config(const char *conf, int id);
|
||||
static void check_schema(void);
|
||||
static void print_help(int i_exit) __attribute__((noreturn));
|
||||
static void wipe_schema(void);
|
||||
static void drop_dupes(const char *user, const char *host, const char *t);
|
||||
|
||||
/**
|
||||
* swing your pants
|
||||
*/
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
char etc[PATH_MAX];
|
||||
char conf[PATH_MAX];
|
||||
int opt;
|
||||
int i;
|
||||
|
||||
rb_strlcpy(me, argv[0], sizeof(me));
|
||||
|
||||
while((opt = getopt(argc, argv, "hieuspvwd")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'h':
|
||||
print_help(EXIT_SUCCESS);
|
||||
break;
|
||||
case 'i':
|
||||
flag.none = false;
|
||||
flag.import = true;
|
||||
break;
|
||||
case 'e':
|
||||
flag.none = false;
|
||||
flag.export_ = true;
|
||||
break;
|
||||
case 'u':
|
||||
flag.none = false;
|
||||
flag.verify = true;
|
||||
break;
|
||||
case 's':
|
||||
flag.none = false;
|
||||
flag.vacuum = true;
|
||||
break;
|
||||
case 'p':
|
||||
flag.pretend = true;
|
||||
break;
|
||||
case 'v':
|
||||
flag.verbose = true;
|
||||
break;
|
||||
case 'w':
|
||||
flag.wipe = true;
|
||||
break;
|
||||
case 'd':
|
||||
flag.dupes_ok = true;
|
||||
break;
|
||||
default: /* '?' */
|
||||
print_help(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* they should really read the help. */
|
||||
if(flag.none)
|
||||
print_help(EXIT_FAILURE);
|
||||
|
||||
if((flag.import && flag.export_) || (flag.export_ && flag.wipe)
|
||||
|| (flag.verify && flag.pretend) || (flag.export_ && flag.pretend))
|
||||
{
|
||||
fprintf(stderr, "* Error: Conflicting flags.\n");
|
||||
if(flag.export_ && flag.pretend)
|
||||
fprintf(stderr, "* There is nothing to 'pretend' when exporting.\n");
|
||||
|
||||
fprintf(stderr, "* For an explination of commands, run: %s -h\n", me);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if(argv[optind] != NULL)
|
||||
rb_strlcpy(etc, argv[optind], sizeof(etc));
|
||||
else
|
||||
rb_strlcpy(etc, ircd::path::ETCPATH, sizeof(ircd::path::ETCPATH));
|
||||
|
||||
fprintf(stdout,
|
||||
"* charybdis bantool v.%s\n", BT_VERSION);
|
||||
|
||||
if(flag.pretend == false)
|
||||
{
|
||||
if(rsdb_init(db_error_cb) == -1)
|
||||
{
|
||||
fprintf(stderr, "* Error: Unable to open database\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
check_schema();
|
||||
|
||||
if(flag.vacuum)
|
||||
db_reclaim_slack();
|
||||
|
||||
if(flag.import && flag.wipe)
|
||||
{
|
||||
flag.dupes_ok = true; /* dont check for dupes if we are wiping the db clean */
|
||||
for(i = 0; i < 3; i++)
|
||||
fprintf(stdout,
|
||||
"* WARNING: YOU ARE ABOUT TO WIPE YOUR DATABASE!\n");
|
||||
|
||||
fprintf(stdout, "* Press ^C to abort! ");
|
||||
fflush(stdout);
|
||||
rb_sleep(10, 0);
|
||||
fprintf(stdout, "Carrying on...\n");
|
||||
wipe_schema();
|
||||
}
|
||||
}
|
||||
if(flag.verbose && flag.dupes_ok == true)
|
||||
fprintf(stdout, "* Allowing duplicate bans...\n");
|
||||
|
||||
/* checking for our files to import or export */
|
||||
for(i = 0; i < LAST_BANDB_TYPE; i++)
|
||||
{
|
||||
snprintf(conf, sizeof(conf), "%s/%s.conf%s",
|
||||
etc, bandb_table[i], bandb_suffix[i]);
|
||||
|
||||
if(flag.import && flag.pretend == false)
|
||||
rsdb_transaction(RSDB_TRANS_START);
|
||||
|
||||
if(flag.import)
|
||||
import_config(conf, i);
|
||||
|
||||
if(flag.export_)
|
||||
export_config(conf, i);
|
||||
|
||||
if(flag.import && flag.pretend == false)
|
||||
rsdb_transaction(RSDB_TRANS_END);
|
||||
}
|
||||
|
||||
if(flag.import)
|
||||
{
|
||||
if(count.error && flag.verbose)
|
||||
fprintf(stderr, "* I was unable to locate %u config files to import.\n",
|
||||
count.error);
|
||||
|
||||
fprintf(stdout, "* Import Stats: Klines: %u, Dlines: %u, Xlines: %u, Resvs: %u \n",
|
||||
count.klines, count.dlines, count.xlines, count.resvs);
|
||||
|
||||
fprintf(stdout,
|
||||
"*\n* If your IRC server is currently running, newly imported bans \n* will not take effect until you issue the command: /quote rehash bans\n");
|
||||
|
||||
if(flag.pretend)
|
||||
fprintf(stdout,
|
||||
"* Pretend mode engaged. Nothing was actually entered into the database.\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* export the database to old-style flat files
|
||||
*/
|
||||
static void
|
||||
export_config(const char *conf, int id)
|
||||
{
|
||||
struct rsdb_table table;
|
||||
static char sql[BUFSIZE * 2];
|
||||
static char buf[512];
|
||||
FILE *fd = NULL;
|
||||
int j;
|
||||
|
||||
/* for sanity sake */
|
||||
const int mask1 = 0;
|
||||
const int mask2 = 1;
|
||||
const int reason = 2;
|
||||
const int oper = 3;
|
||||
const int ts = 4;
|
||||
/* const int perm = 5; */
|
||||
|
||||
if(!table_has_rows(bandb_table[id]))
|
||||
return;
|
||||
|
||||
if(strstr(conf, ".perm") != 0)
|
||||
snprintf(sql, sizeof(sql),
|
||||
"SELECT DISTINCT mask1,mask2,reason,oper,time FROM %s WHERE perm = 1 ORDER BY time",
|
||||
bandb_table[id]);
|
||||
else
|
||||
snprintf(sql, sizeof(sql),
|
||||
"SELECT DISTINCT mask1,mask2,reason,oper,time FROM %s WHERE perm = 0 ORDER BY time",
|
||||
bandb_table[id]);
|
||||
|
||||
rsdb_exec_fetch(&table, sql);
|
||||
if(table.row_count <= 0)
|
||||
{
|
||||
rsdb_exec_fetch_end(&table);
|
||||
return;
|
||||
}
|
||||
|
||||
if(flag.verbose)
|
||||
fprintf(stdout, "* checking for %s: ", conf); /* debug */
|
||||
|
||||
/* open config for reading, or skip to the next */
|
||||
if(!(fd = fopen(conf, "w")))
|
||||
{
|
||||
if(flag.verbose)
|
||||
fprintf(stdout, "\tmissing.\n");
|
||||
count.error++;
|
||||
return;
|
||||
}
|
||||
|
||||
for(j = 0; j < table.row_count; j++)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case BANDB_DLINE:
|
||||
case BANDB_DLINE_PERM:
|
||||
snprintf(buf, sizeof(buf),
|
||||
"\"%s\",\"%s\",\"\",\"%s\",\"%s\",%s\n",
|
||||
table.row[j][mask1],
|
||||
mangle_reason(table.row[j][reason]),
|
||||
bt_smalldate(table.row[j][ts]),
|
||||
table.row[j][oper], table.row[j][ts]);
|
||||
break;
|
||||
|
||||
case BANDB_XLINE:
|
||||
case BANDB_XLINE_PERM:
|
||||
snprintf(buf, sizeof(buf),
|
||||
"\"%s\",\"0\",\"%s\",\"%s\",%s\n",
|
||||
escape_quotes(table.row[j][mask1]),
|
||||
mangle_reason(table.row[j][reason]),
|
||||
table.row[j][oper], table.row[j][ts]);
|
||||
break;
|
||||
|
||||
case BANDB_RESV:
|
||||
case BANDB_RESV_PERM:
|
||||
snprintf(buf, sizeof(buf),
|
||||
"\"%s\",\"%s\",\"%s\",%s\n",
|
||||
table.row[j][mask1],
|
||||
mangle_reason(table.row[j][reason]),
|
||||
table.row[j][oper], table.row[j][ts]);
|
||||
break;
|
||||
|
||||
|
||||
default: /* Klines */
|
||||
snprintf(buf, sizeof(buf),
|
||||
"\"%s\",\"%s\",\"%s\",\"\",\"%s\",\"%s\",%s\n",
|
||||
table.row[j][mask1], table.row[j][mask2],
|
||||
mangle_reason(table.row[j][reason]),
|
||||
bt_smalldate(table.row[j][ts]), table.row[j][oper],
|
||||
table.row[j][ts]);
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(fd, "%s", buf);
|
||||
}
|
||||
|
||||
rsdb_exec_fetch_end(&table);
|
||||
if(flag.verbose)
|
||||
fprintf(stdout, "\twritten.\n");
|
||||
fclose(fd);
|
||||
}
|
||||
|
||||
/**
|
||||
* attempt to condense the individual conf functions into one
|
||||
*/
|
||||
static void
|
||||
import_config(const char *conf, int id)
|
||||
{
|
||||
FILE *fd;
|
||||
|
||||
char line[BUFSIZE];
|
||||
char *p;
|
||||
int i = 0;
|
||||
|
||||
char f_perm = 0;
|
||||
const char *f_mask1 = NULL;
|
||||
const char *f_mask2 = NULL;
|
||||
const char *f_oper = NULL;
|
||||
const char *f_time = NULL;
|
||||
const char *f_reason = NULL;
|
||||
const char *f_oreason = NULL;
|
||||
char newreason[REASONLEN];
|
||||
|
||||
if(flag.verbose)
|
||||
fprintf(stdout, "* checking for %s: ", conf); /* debug */
|
||||
|
||||
/* open config for reading, or skip to the next */
|
||||
if(!(fd = fopen(conf, "r")))
|
||||
{
|
||||
if(flag.verbose)
|
||||
fprintf(stdout, "%*s", strlen(bandb_suffix[id]) > 0 ? 10 : 15,
|
||||
"missing.\n");
|
||||
count.error++;
|
||||
return;
|
||||
}
|
||||
|
||||
if(strstr(conf, ".perm") != 0)
|
||||
f_perm = 1;
|
||||
|
||||
|
||||
/* xline
|
||||
* "SYSTEM","0","banned","stevoo!stevoo@efnet.port80.se{stevoo}",1111080437
|
||||
* resv
|
||||
* "OseK","banned nickname","stevoo!stevoo@efnet.port80.se{stevoo}",1111031619
|
||||
* dline
|
||||
* "194.158.192.0/19","laptop scammers","","2005/3/17 05.33","stevoo!stevoo@efnet.port80.se{stevoo}",1111033988
|
||||
*/
|
||||
while(fgets(line, sizeof(line), fd))
|
||||
{
|
||||
if((p = strpbrk(line, "\r\n")) != NULL)
|
||||
*p = '\0';
|
||||
|
||||
if((*line == '\0') || (*line == '#'))
|
||||
continue;
|
||||
|
||||
/* mask1 */
|
||||
f_mask1 = getfield(line);
|
||||
|
||||
if(EmptyString(f_mask1))
|
||||
continue;
|
||||
|
||||
/* mask2 */
|
||||
switch (id)
|
||||
{
|
||||
case BANDB_XLINE:
|
||||
case BANDB_XLINE_PERM:
|
||||
f_mask1 = escape_quotes(clean_gecos_field(f_mask1));
|
||||
getfield(NULL); /* empty field */
|
||||
break;
|
||||
|
||||
case BANDB_RESV:
|
||||
case BANDB_RESV_PERM:
|
||||
case BANDB_DLINE:
|
||||
case BANDB_DLINE_PERM:
|
||||
break;
|
||||
|
||||
default:
|
||||
f_mask2 = getfield(NULL);
|
||||
if(EmptyString(f_mask2))
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
/* reason */
|
||||
f_reason = getfield(NULL);
|
||||
if(EmptyString(f_reason))
|
||||
continue;
|
||||
|
||||
/* oper comment */
|
||||
switch (id)
|
||||
{
|
||||
case BANDB_KLINE:
|
||||
case BANDB_KLINE_PERM:
|
||||
case BANDB_DLINE:
|
||||
case BANDB_DLINE_PERM:
|
||||
f_oreason = getfield(NULL);
|
||||
getfield(NULL);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
f_oper = getfield(NULL);
|
||||
f_time = strip_quotes(f_oper + strlen(f_oper) + 2);
|
||||
if(EmptyString(f_oper))
|
||||
f_oper = "unknown";
|
||||
|
||||
/* meh */
|
||||
if(id == BANDB_KLINE || id == BANDB_KLINE_PERM)
|
||||
{
|
||||
if(strstr(f_mask1, "!") != NULL)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"* SKIPPING INVALID KLINE %s@%s set by %s\n",
|
||||
f_mask1, f_mask2, f_oper);
|
||||
fprintf(stderr, " You may wish to re-apply it correctly.\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* append operreason_field to reason_field */
|
||||
if(!EmptyString(f_oreason))
|
||||
snprintf(newreason, sizeof(newreason), "%s | %s", f_reason, f_oreason);
|
||||
else
|
||||
snprintf(newreason, sizeof(newreason), "%s", f_reason);
|
||||
|
||||
if(flag.pretend == false)
|
||||
{
|
||||
if(flag.dupes_ok == false)
|
||||
drop_dupes(f_mask1, f_mask2, bandb_table[id]);
|
||||
|
||||
rsdb_exec(NULL,
|
||||
"INSERT INTO %s (mask1, mask2, oper, time, perm, reason) VALUES('%Q','%Q','%Q','%Q','%d','%Q')",
|
||||
bandb_table[id], f_mask1, f_mask2, f_oper, f_time, f_perm,
|
||||
newreason);
|
||||
}
|
||||
|
||||
if(flag.pretend && flag.verbose)
|
||||
fprintf(stdout,
|
||||
"%s: perm(%d) mask1(%s) mask2(%s) oper(%s) reason(%s) time(%s)\n",
|
||||
bandb_table[id], f_perm, f_mask1, f_mask2, f_oper, newreason,
|
||||
f_time);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
switch (bandb_letter[id])
|
||||
{
|
||||
case 'K':
|
||||
count.klines += i;
|
||||
break;
|
||||
case 'D':
|
||||
count.dlines += i;
|
||||
break;
|
||||
case 'X':
|
||||
count.xlines += i;
|
||||
break;
|
||||
case 'R':
|
||||
count.resvs += i;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(flag.verbose)
|
||||
fprintf(stdout, "%*s\n", strlen(bandb_suffix[id]) > 0 ? 10 : 15, "imported.");
|
||||
|
||||
fclose(fd);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* getfield
|
||||
*
|
||||
* inputs - input buffer
|
||||
* output - next field
|
||||
* side effects - field breakup for ircd.conf file.
|
||||
*/
|
||||
char *
|
||||
getfield(char *newline)
|
||||
{
|
||||
static char *line = NULL;
|
||||
char *end, *field;
|
||||
|
||||
if(newline != NULL)
|
||||
line = newline;
|
||||
|
||||
if(line == NULL)
|
||||
return (NULL);
|
||||
|
||||
field = line;
|
||||
|
||||
/* XXX make this skip to first " if present */
|
||||
if(*field == '"')
|
||||
field++;
|
||||
else
|
||||
return (NULL); /* mal-formed field */
|
||||
|
||||
end = strchr(line, ',');
|
||||
|
||||
while(1)
|
||||
{
|
||||
/* no trailing , - last field */
|
||||
if(end == NULL)
|
||||
{
|
||||
end = line + strlen(line);
|
||||
line = NULL;
|
||||
|
||||
if(*end == '"')
|
||||
{
|
||||
*end = '\0';
|
||||
return field;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* look for a ", to mark the end of a field.. */
|
||||
if(*(end - 1) == '"')
|
||||
{
|
||||
line = end + 1;
|
||||
end--;
|
||||
*end = '\0';
|
||||
return field;
|
||||
}
|
||||
|
||||
/* search for the next ',' */
|
||||
end++;
|
||||
end = strchr(end, ',');
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* strip away "quotes" from around strings
|
||||
*/
|
||||
static char *
|
||||
strip_quotes(const char *string)
|
||||
{
|
||||
static char buf[14]; /* int(11) + 2 + \0 */
|
||||
char *str = buf;
|
||||
|
||||
if(string == NULL)
|
||||
return NULL;
|
||||
|
||||
while(*string)
|
||||
{
|
||||
if(*string != '"')
|
||||
{
|
||||
*str++ = *string;
|
||||
}
|
||||
string++;
|
||||
}
|
||||
*str = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* escape quotes in a string
|
||||
*/
|
||||
static char *
|
||||
escape_quotes(const char *string)
|
||||
{
|
||||
static char buf[BUFSIZE * 2];
|
||||
char *str = buf;
|
||||
|
||||
if(string == NULL)
|
||||
return NULL;
|
||||
|
||||
while(*string)
|
||||
{
|
||||
if(*string == '"')
|
||||
{
|
||||
*str++ = '\\';
|
||||
*str++ = '"';
|
||||
}
|
||||
else
|
||||
{
|
||||
*str++ = *string;
|
||||
}
|
||||
string++;
|
||||
}
|
||||
*str = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
mangle_reason(const char *string)
|
||||
{
|
||||
static char buf[BUFSIZE * 2];
|
||||
char *str = buf;
|
||||
|
||||
if(string == NULL)
|
||||
return NULL;
|
||||
|
||||
while(*string)
|
||||
{
|
||||
switch (*string)
|
||||
{
|
||||
case '"':
|
||||
*str = '\'';
|
||||
break;
|
||||
case ':':
|
||||
*str = ' ';
|
||||
break;
|
||||
default:
|
||||
*str = *string;
|
||||
}
|
||||
string++;
|
||||
str++;
|
||||
|
||||
}
|
||||
*str = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* change spaces to \s in gecos field
|
||||
*/
|
||||
static const char *
|
||||
clean_gecos_field(const char *gecos)
|
||||
{
|
||||
static char buf[BUFSIZE * 2];
|
||||
char *str = buf;
|
||||
|
||||
if(gecos == NULL)
|
||||
return NULL;
|
||||
|
||||
while(*gecos)
|
||||
{
|
||||
if(*gecos == ' ')
|
||||
{
|
||||
*str++ = '\\';
|
||||
*str++ = 's';
|
||||
}
|
||||
else
|
||||
*str++ = *gecos;
|
||||
gecos++;
|
||||
}
|
||||
*str = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* verify the database integrity, and if necessary create apropriate tables
|
||||
*/
|
||||
static void
|
||||
check_schema(void)
|
||||
{
|
||||
int i, j;
|
||||
char type[8]; /* longest string is 'INTEGER\0' */
|
||||
|
||||
if(flag.verify || flag.verbose)
|
||||
fprintf(stdout, "* Verifying database.\n");
|
||||
|
||||
const char *columns[] = {
|
||||
"perm",
|
||||
"mask1",
|
||||
"mask2",
|
||||
"oper",
|
||||
"time",
|
||||
"reason",
|
||||
NULL
|
||||
};
|
||||
|
||||
for(i = 0; i < LAST_BANDB_TYPE; i++)
|
||||
{
|
||||
if(!table_exists(bandb_table[i]))
|
||||
{
|
||||
rsdb_exec(NULL,
|
||||
"CREATE TABLE %s (mask1 TEXT, mask2 TEXT, oper TEXT, time INTEGER, perm INTEGER, reason TEXT)",
|
||||
bandb_table[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* i can't think of any better way to do this, other then attempt to
|
||||
* force the creation of column that may, or may not already exist. --dubkat
|
||||
*/
|
||||
else
|
||||
{
|
||||
for(j = 0; columns[j] != NULL; j++)
|
||||
{
|
||||
if(!strcmp(columns[j], "time") && !strcmp(columns[j], "perm"))
|
||||
rb_strlcpy(type, "INTEGER", sizeof(type));
|
||||
else
|
||||
rb_strlcpy(type, "TEXT", sizeof(type));
|
||||
|
||||
/* attempt to add a column with extreme prejudice, errors are ignored */
|
||||
rsdb_exec(NULL, "ALTER TABLE %s ADD COLUMN %s %s", bandb_table[i],
|
||||
columns[j], type);
|
||||
}
|
||||
}
|
||||
|
||||
i++; /* skip over .perm */
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
db_reclaim_slack(void)
|
||||
{
|
||||
fprintf(stdout, "* Reclaiming free space.\n");
|
||||
rsdb_exec(NULL, "VACUUM");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* check that appropriate tables exist.
|
||||
*/
|
||||
static int
|
||||
table_exists(const char *dbtab)
|
||||
{
|
||||
struct rsdb_table table;
|
||||
rsdb_exec_fetch(&table, "SELECT name FROM sqlite_master WHERE type='table' AND name='%s'",
|
||||
dbtab);
|
||||
rsdb_exec_fetch_end(&table);
|
||||
return table.row_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* check that there are actual entries in a table
|
||||
*/
|
||||
static int
|
||||
table_has_rows(const char *dbtab)
|
||||
{
|
||||
struct rsdb_table table;
|
||||
rsdb_exec_fetch(&table, "SELECT * FROM %s", dbtab);
|
||||
rsdb_exec_fetch_end(&table);
|
||||
return table.row_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* completly wipes out an existing ban.db of all entries.
|
||||
*/
|
||||
static void
|
||||
wipe_schema(void)
|
||||
{
|
||||
int i;
|
||||
rsdb_transaction(RSDB_TRANS_START);
|
||||
for(i = 0; i < LAST_BANDB_TYPE; i++)
|
||||
{
|
||||
rsdb_exec(NULL, "DROP TABLE %s", bandb_table[i]);
|
||||
i++; /* double increment to skip over .perm */
|
||||
}
|
||||
rsdb_transaction(RSDB_TRANS_END);
|
||||
|
||||
check_schema();
|
||||
}
|
||||
|
||||
/**
|
||||
* remove pre-existing duplicate bans from the database.
|
||||
* we favor the new, imported ban over the one in the database
|
||||
*/
|
||||
void
|
||||
drop_dupes(const char *user, const char *host, const char *t)
|
||||
{
|
||||
rsdb_exec(NULL, "DELETE FROM %s WHERE mask1='%Q' AND mask2='%Q'", t, user, host);
|
||||
}
|
||||
|
||||
static void
|
||||
db_error_cb(const char *errstr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* convert unix timestamp to human readable (small) date
|
||||
*/
|
||||
static char *
|
||||
bt_smalldate(const char *string)
|
||||
{
|
||||
static char buf[MAX_DATE_STRING];
|
||||
struct tm *lt;
|
||||
time_t t;
|
||||
t = strtol(string, NULL, 10);
|
||||
lt = gmtime(&t);
|
||||
if(lt == NULL)
|
||||
return NULL;
|
||||
snprintf(buf, sizeof(buf), "%d/%d/%d %02d.%02d",
|
||||
lt->tm_year + 1900, lt->tm_mon + 1, lt->tm_mday, lt->tm_hour, lt->tm_min);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* you are here ->.
|
||||
*/
|
||||
void
|
||||
print_help(int i_exit)
|
||||
{
|
||||
fprintf(stderr, "bantool v.%s - the charybdis database tool.\n", BT_VERSION);
|
||||
fprintf(stderr, "Copyright (C) 2008 Daniel J Reidy <dubkat@gmail.com>\n");
|
||||
fprintf(stderr, "This program is distributed in the hope that it will be useful,\n"
|
||||
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
||||
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
|
||||
"GNU General Public License for more details.\n\n");
|
||||
|
||||
fprintf(stderr, "Usage: %s <-i|-e> [-p] [-v] [-h] [-d] [-w] [path]\n", me);
|
||||
fprintf(stderr, " -h : Display some slightly useful help.\n");
|
||||
fprintf(stderr, " -i : Actually import configs into your database.\n");
|
||||
fprintf(stderr, " -e : Export your database to old-style flat files.\n");
|
||||
fprintf(stderr,
|
||||
" This is suitable for redistrubuting your banlists, or creating backups.\n");
|
||||
fprintf(stderr, " -s : Reclaim empty slack space the database may be taking up.\n");
|
||||
fprintf(stderr, " -u : Update the database tables to support any new features.\n");
|
||||
fprintf(stderr,
|
||||
" This is automaticlly done if you are importing or exporting\n");
|
||||
fprintf(stderr, " but should be run whenever you upgrade the ircd.\n");
|
||||
fprintf(stderr,
|
||||
" -p : pretend, checks for the configs, and parses them, then tells you some data...\n");
|
||||
fprintf(stderr, " but does not touch your database.\n");
|
||||
fprintf(stderr,
|
||||
" -v : Be verbose... and it *is* very verbose! (intended for debugging)\n");
|
||||
fprintf(stderr, " -d : Enable checking for redunant entries.\n");
|
||||
fprintf(stderr, " -w : Completly wipe your database clean. May be used with -i \n");
|
||||
fprintf(stderr,
|
||||
" path : An optional directory containing old ratbox configs for import, or export.\n");
|
||||
fprintf(stderr, " If not specified, it looks in PREFIX/etc.\n");
|
||||
exit(i_exit);
|
||||
}
|
46
bandb/rsdb.h
46
bandb/rsdb.h
|
@ -1,46 +0,0 @@
|
|||
#pragma once
|
||||
#define HAVE_BANDB_RSDB_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* error handler callback */
|
||||
typedef void rsdb_error_cb(const char *);
|
||||
|
||||
typedef int (*rsdb_callback) (int, const char **);
|
||||
|
||||
typedef enum rsdb_transtype
|
||||
{
|
||||
RSDB_TRANS_START,
|
||||
RSDB_TRANS_END
|
||||
}
|
||||
rsdb_transtype;
|
||||
|
||||
struct rsdb_table
|
||||
{
|
||||
char ***row;
|
||||
int row_count;
|
||||
int col_count;
|
||||
void *arg;
|
||||
};
|
||||
|
||||
int rsdb_init(rsdb_error_cb *);
|
||||
void rsdb_shutdown(void);
|
||||
|
||||
const char *rsdb_quote(const char *src);
|
||||
|
||||
void rsdb_exec(rsdb_callback cb, const char *format, ...);
|
||||
|
||||
void rsdb_exec_fetch(struct rsdb_table *data, const char *format, ...);
|
||||
void rsdb_exec_fetch_end(struct rsdb_table *data);
|
||||
|
||||
void rsdb_transaction(rsdb_transtype type);
|
||||
/* rsdb_snprintf.c */
|
||||
|
||||
int rs_vsnprintf(char *dest, const size_t bytes, const char *format, va_list args);
|
||||
int rs_snprintf(char *dest, const size_t bytes, const char *format, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -1,630 +0,0 @@
|
|||
/*
|
||||
* libString, Copyright (C) 1999 Patrick Alken
|
||||
* This library comes with absolutely NO WARRANTY
|
||||
*
|
||||
* Should you choose to use and/or modify this source code, please
|
||||
* do so under the terms of the GNU General Public License under which
|
||||
* this library is distributed.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include "rsdb.h"
|
||||
|
||||
/*
|
||||
* This table is arranged in chronological order from 0-999,
|
||||
* however the numbers are written backwards, so the number 100
|
||||
* is expressed in this table as "001".
|
||||
* It's purpose is to ensure fast conversions from integers to
|
||||
* ASCII strings. When an integer variable is encountered, a
|
||||
* simple hash algorithm is used to determine where to look
|
||||
* in this array for the corresponding string.
|
||||
* This outperforms continually dividing by 10 and using the
|
||||
* digit obtained as a character, because we can now divide by
|
||||
* 1000 and use the remainder directly, thus cutting down on
|
||||
* the number of costly divisions needed. For an integer's worst
|
||||
* case, 2 divisions are needed because it can only go up to
|
||||
* 32767, so after 2 divisions by 1000, and some algebra, we will
|
||||
* be left with 327 which we can get from this table. This is much
|
||||
* better than the 5 divisions by 10 that we would need if we did
|
||||
* it the conventional way. Of course, if we made this table go
|
||||
* from 0-9999, only 1 division would be needed.
|
||||
* Longs and unsigned ints of course, are another matter :-).
|
||||
*
|
||||
* Patrick Alken <wnder@underworld.net>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Set this to the number of indices (numbers) in our table
|
||||
*/
|
||||
#define TABLE_MAX 1000
|
||||
|
||||
static const char *IntTable[] = {
|
||||
"000", "100", "200", "300", "400",
|
||||
"500", "600", "700", "800", "900",
|
||||
"010", "110", "210", "310", "410",
|
||||
"510", "610", "710", "810", "910",
|
||||
"020", "120", "220", "320", "420",
|
||||
"520", "620", "720", "820", "920",
|
||||
"030", "130", "230", "330", "430",
|
||||
"530", "630", "730", "830", "930",
|
||||
"040", "140", "240", "340", "440",
|
||||
"540", "640", "740", "840", "940",
|
||||
"050", "150", "250", "350", "450",
|
||||
"550", "650", "750", "850", "950",
|
||||
"060", "160", "260", "360", "460",
|
||||
"560", "660", "760", "860", "960",
|
||||
"070", "170", "270", "370", "470",
|
||||
"570", "670", "770", "870", "970",
|
||||
"080", "180", "280", "380", "480",
|
||||
"580", "680", "780", "880", "980",
|
||||
"090", "190", "290", "390", "490",
|
||||
"590", "690", "790", "890", "990",
|
||||
"001", "101", "201", "301", "401",
|
||||
"501", "601", "701", "801", "901",
|
||||
"011", "111", "211", "311", "411",
|
||||
"511", "611", "711", "811", "911",
|
||||
"021", "121", "221", "321", "421",
|
||||
"521", "621", "721", "821", "921",
|
||||
"031", "131", "231", "331", "431",
|
||||
"531", "631", "731", "831", "931",
|
||||
"041", "141", "241", "341", "441",
|
||||
"541", "641", "741", "841", "941",
|
||||
"051", "151", "251", "351", "451",
|
||||
"551", "651", "751", "851", "951",
|
||||
"061", "161", "261", "361", "461",
|
||||
"561", "661", "761", "861", "961",
|
||||
"071", "171", "271", "371", "471",
|
||||
"571", "671", "771", "871", "971",
|
||||
"081", "181", "281", "381", "481",
|
||||
"581", "681", "781", "881", "981",
|
||||
"091", "191", "291", "391", "491",
|
||||
"591", "691", "791", "891", "991",
|
||||
"002", "102", "202", "302", "402",
|
||||
"502", "602", "702", "802", "902",
|
||||
"012", "112", "212", "312", "412",
|
||||
"512", "612", "712", "812", "912",
|
||||
"022", "122", "222", "322", "422",
|
||||
"522", "622", "722", "822", "922",
|
||||
"032", "132", "232", "332", "432",
|
||||
"532", "632", "732", "832", "932",
|
||||
"042", "142", "242", "342", "442",
|
||||
"542", "642", "742", "842", "942",
|
||||
"052", "152", "252", "352", "452",
|
||||
"552", "652", "752", "852", "952",
|
||||
"062", "162", "262", "362", "462",
|
||||
"562", "662", "762", "862", "962",
|
||||
"072", "172", "272", "372", "472",
|
||||
"572", "672", "772", "872", "972",
|
||||
"082", "182", "282", "382", "482",
|
||||
"582", "682", "782", "882", "982",
|
||||
"092", "192", "292", "392", "492",
|
||||
"592", "692", "792", "892", "992",
|
||||
"003", "103", "203", "303", "403",
|
||||
"503", "603", "703", "803", "903",
|
||||
"013", "113", "213", "313", "413",
|
||||
"513", "613", "713", "813", "913",
|
||||
"023", "123", "223", "323", "423",
|
||||
"523", "623", "723", "823", "923",
|
||||
"033", "133", "233", "333", "433",
|
||||
"533", "633", "733", "833", "933",
|
||||
"043", "143", "243", "343", "443",
|
||||
"543", "643", "743", "843", "943",
|
||||
"053", "153", "253", "353", "453",
|
||||
"553", "653", "753", "853", "953",
|
||||
"063", "163", "263", "363", "463",
|
||||
"563", "663", "763", "863", "963",
|
||||
"073", "173", "273", "373", "473",
|
||||
"573", "673", "773", "873", "973",
|
||||
"083", "183", "283", "383", "483",
|
||||
"583", "683", "783", "883", "983",
|
||||
"093", "193", "293", "393", "493",
|
||||
"593", "693", "793", "893", "993",
|
||||
"004", "104", "204", "304", "404",
|
||||
"504", "604", "704", "804", "904",
|
||||
"014", "114", "214", "314", "414",
|
||||
"514", "614", "714", "814", "914",
|
||||
"024", "124", "224", "324", "424",
|
||||
"524", "624", "724", "824", "924",
|
||||
"034", "134", "234", "334", "434",
|
||||
"534", "634", "734", "834", "934",
|
||||
"044", "144", "244", "344", "444",
|
||||
"544", "644", "744", "844", "944",
|
||||
"054", "154", "254", "354", "454",
|
||||
"554", "654", "754", "854", "954",
|
||||
"064", "164", "264", "364", "464",
|
||||
"564", "664", "764", "864", "964",
|
||||
"074", "174", "274", "374", "474",
|
||||
"574", "674", "774", "874", "974",
|
||||
"084", "184", "284", "384", "484",
|
||||
"584", "684", "784", "884", "984",
|
||||
"094", "194", "294", "394", "494",
|
||||
"594", "694", "794", "894", "994",
|
||||
"005", "105", "205", "305", "405",
|
||||
"505", "605", "705", "805", "905",
|
||||
"015", "115", "215", "315", "415",
|
||||
"515", "615", "715", "815", "915",
|
||||
"025", "125", "225", "325", "425",
|
||||
"525", "625", "725", "825", "925",
|
||||
"035", "135", "235", "335", "435",
|
||||
"535", "635", "735", "835", "935",
|
||||
"045", "145", "245", "345", "445",
|
||||
"545", "645", "745", "845", "945",
|
||||
"055", "155", "255", "355", "455",
|
||||
"555", "655", "755", "855", "955",
|
||||
"065", "165", "265", "365", "465",
|
||||
"565", "665", "765", "865", "965",
|
||||
"075", "175", "275", "375", "475",
|
||||
"575", "675", "775", "875", "975",
|
||||
"085", "185", "285", "385", "485",
|
||||
"585", "685", "785", "885", "985",
|
||||
"095", "195", "295", "395", "495",
|
||||
"595", "695", "795", "895", "995",
|
||||
"006", "106", "206", "306", "406",
|
||||
"506", "606", "706", "806", "906",
|
||||
"016", "116", "216", "316", "416",
|
||||
"516", "616", "716", "816", "916",
|
||||
"026", "126", "226", "326", "426",
|
||||
"526", "626", "726", "826", "926",
|
||||
"036", "136", "236", "336", "436",
|
||||
"536", "636", "736", "836", "936",
|
||||
"046", "146", "246", "346", "446",
|
||||
"546", "646", "746", "846", "946",
|
||||
"056", "156", "256", "356", "456",
|
||||
"556", "656", "756", "856", "956",
|
||||
"066", "166", "266", "366", "466",
|
||||
"566", "666", "766", "866", "966",
|
||||
"076", "176", "276", "376", "476",
|
||||
"576", "676", "776", "876", "976",
|
||||
"086", "186", "286", "386", "486",
|
||||
"586", "686", "786", "886", "986",
|
||||
"096", "196", "296", "396", "496",
|
||||
"596", "696", "796", "896", "996",
|
||||
"007", "107", "207", "307", "407",
|
||||
"507", "607", "707", "807", "907",
|
||||
"017", "117", "217", "317", "417",
|
||||
"517", "617", "717", "817", "917",
|
||||
"027", "127", "227", "327", "427",
|
||||
"527", "627", "727", "827", "927",
|
||||
"037", "137", "237", "337", "437",
|
||||
"537", "637", "737", "837", "937",
|
||||
"047", "147", "247", "347", "447",
|
||||
"547", "647", "747", "847", "947",
|
||||
"057", "157", "257", "357", "457",
|
||||
"557", "657", "757", "857", "957",
|
||||
"067", "167", "267", "367", "467",
|
||||
"567", "667", "767", "867", "967",
|
||||
"077", "177", "277", "377", "477",
|
||||
"577", "677", "777", "877", "977",
|
||||
"087", "187", "287", "387", "487",
|
||||
"587", "687", "787", "887", "987",
|
||||
"097", "197", "297", "397", "497",
|
||||
"597", "697", "797", "897", "997",
|
||||
"008", "108", "208", "308", "408",
|
||||
"508", "608", "708", "808", "908",
|
||||
"018", "118", "218", "318", "418",
|
||||
"518", "618", "718", "818", "918",
|
||||
"028", "128", "228", "328", "428",
|
||||
"528", "628", "728", "828", "928",
|
||||
"038", "138", "238", "338", "438",
|
||||
"538", "638", "738", "838", "938",
|
||||
"048", "148", "248", "348", "448",
|
||||
"548", "648", "748", "848", "948",
|
||||
"058", "158", "258", "358", "458",
|
||||
"558", "658", "758", "858", "958",
|
||||
"068", "168", "268", "368", "468",
|
||||
"568", "668", "768", "868", "968",
|
||||
"078", "178", "278", "378", "478",
|
||||
"578", "678", "778", "878", "978",
|
||||
"088", "188", "288", "388", "488",
|
||||
"588", "688", "788", "888", "988",
|
||||
"098", "198", "298", "398", "498",
|
||||
"598", "698", "798", "898", "998",
|
||||
"009", "109", "209", "309", "409",
|
||||
"509", "609", "709", "809", "909",
|
||||
"019", "119", "219", "319", "419",
|
||||
"519", "619", "719", "819", "919",
|
||||
"029", "129", "229", "329", "429",
|
||||
"529", "629", "729", "829", "929",
|
||||
"039", "139", "239", "339", "439",
|
||||
"539", "639", "739", "839", "939",
|
||||
"049", "149", "249", "349", "449",
|
||||
"549", "649", "749", "849", "949",
|
||||
"059", "159", "259", "359", "459",
|
||||
"559", "659", "759", "859", "959",
|
||||
"069", "169", "269", "369", "469",
|
||||
"569", "669", "769", "869", "969",
|
||||
"079", "179", "279", "379", "479",
|
||||
"579", "679", "779", "879", "979",
|
||||
"089", "189", "289", "389", "489",
|
||||
"589", "689", "789", "889", "989",
|
||||
"099", "199", "299", "399", "499",
|
||||
"599", "699", "799", "899", "999"
|
||||
};
|
||||
|
||||
/*
|
||||
* Since we calculate the right-most digits for %d %u etc first,
|
||||
* we need a temporary buffer to store them in until we get
|
||||
* to the left-most digits
|
||||
*/
|
||||
|
||||
#define TEMPBUF_MAX 20
|
||||
|
||||
static char TempBuffer[TEMPBUF_MAX];
|
||||
|
||||
/*
|
||||
vSnprintf()
|
||||
Backend to Snprintf() - performs the construction of 'dest'
|
||||
using the string 'format' and the given arguments. Also makes sure
|
||||
not more than 'bytes' characters are copied to 'dest'
|
||||
|
||||
We always allow room for a terminating \0 character, so at most,
|
||||
bytes - 1 characters will be written to dest.
|
||||
|
||||
Return: Number of characters written, NOT including the terminating
|
||||
\0 character which is *always* placed at the end of the string
|
||||
|
||||
NOTE: This function handles the following flags only:
|
||||
%s %d %c %u %ld %lu
|
||||
In addition, this function performs *NO* precision, padding,
|
||||
or width formatting. If it receives an unknown % character,
|
||||
it will call vsprintf() to complete the remainder of the
|
||||
string.
|
||||
*/
|
||||
|
||||
int
|
||||
rs_vsnprintf(char *dest, const size_t bytes, const char *format, va_list args)
|
||||
{
|
||||
char ch;
|
||||
int written = 0; /* bytes written so far */
|
||||
int maxbytes = bytes - 1;
|
||||
|
||||
while((ch = *format++) && (written < maxbytes))
|
||||
{
|
||||
if(ch == '%')
|
||||
{
|
||||
/*
|
||||
* Advance past the %
|
||||
*/
|
||||
ch = *format++;
|
||||
|
||||
/*
|
||||
* Put the most common cases first - %s %d etc
|
||||
*/
|
||||
|
||||
if(ch == 's')
|
||||
{
|
||||
const char *str = va_arg(args, const char *);
|
||||
|
||||
while((*dest = *str))
|
||||
{
|
||||
++dest;
|
||||
++str;
|
||||
|
||||
if(++written >= maxbytes)
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if(ch == 'd')
|
||||
{
|
||||
int num = va_arg(args, int);
|
||||
int quotient;
|
||||
const char *str;
|
||||
char *digitptr = TempBuffer;
|
||||
|
||||
/*
|
||||
* We have to special-case "0" unfortunately
|
||||
*/
|
||||
if(num == 0)
|
||||
{
|
||||
*dest++ = '0';
|
||||
++written;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(num < 0)
|
||||
{
|
||||
*dest++ = '-';
|
||||
if(++written >= maxbytes)
|
||||
continue;
|
||||
|
||||
num = -num;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
quotient = num / TABLE_MAX;
|
||||
|
||||
/*
|
||||
* We'll start with the right-most digits of 'num'.
|
||||
* Dividing by TABLE_MAX cuts off all but the X
|
||||
* right-most digits, where X is such that:
|
||||
*
|
||||
* 10^X = TABLE_MAX
|
||||
*
|
||||
* For example, if num = 1200, and TABLE_MAX = 1000,
|
||||
* quotient will be 1. Multiplying this by 1000 and
|
||||
* subtracting from 1200 gives: 1200 - (1 * 1000) = 200.
|
||||
* We then go right to slot 200 in our array and behold!
|
||||
* The string "002" (200 backwards) is conveniently
|
||||
* waiting for us. Then repeat the process with the
|
||||
* digits left.
|
||||
*
|
||||
* The reason we need to have the integers written
|
||||
* backwards, is because we don't know how many digits
|
||||
* there are. If we want to express the number 12130
|
||||
* for example, our first pass would leave us with 130,
|
||||
* whose slot in the array yields "031", which we
|
||||
* plug into our TempBuffer[]. The next pass gives us
|
||||
* 12, whose slot yields "21" which we append to
|
||||
* TempBuffer[], leaving us with "03121". This is the
|
||||
* exact number we want, only backwards, so it is
|
||||
* a simple matter to reverse the string. If we used
|
||||
* straightfoward numbers, we would have a TempBuffer
|
||||
* looking like this: "13012" which would be a nightmare
|
||||
* to deal with.
|
||||
*/
|
||||
|
||||
str = IntTable[num - (quotient * TABLE_MAX)];
|
||||
|
||||
while((*digitptr = *str))
|
||||
{
|
||||
++digitptr;
|
||||
++str;
|
||||
}
|
||||
}
|
||||
while((num = quotient) != 0);
|
||||
|
||||
/*
|
||||
* If the last quotient was a 1 or 2 digit number, there
|
||||
* will be one or more leading zeroes in TempBuffer[] -
|
||||
* get rid of them.
|
||||
*/
|
||||
while(*(digitptr - 1) == '0')
|
||||
--digitptr;
|
||||
|
||||
while(digitptr != TempBuffer)
|
||||
{
|
||||
*dest++ = *--digitptr;
|
||||
if(++written >= maxbytes)
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
} /* if (ch == 'd') */
|
||||
|
||||
if(ch == 'c')
|
||||
{
|
||||
*dest++ = va_arg(args, int);
|
||||
|
||||
++written;
|
||||
|
||||
continue;
|
||||
} /* if (ch == 'c') */
|
||||
|
||||
if(ch == 'u')
|
||||
{
|
||||
unsigned int num = va_arg(args, unsigned int);
|
||||
unsigned int quotient;
|
||||
const char *str;
|
||||
char *digitptr = TempBuffer;
|
||||
|
||||
if(num == 0)
|
||||
{
|
||||
*dest++ = '0';
|
||||
++written;
|
||||
continue;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
quotient = num / TABLE_MAX;
|
||||
|
||||
/*
|
||||
* Very similar to case 'd'
|
||||
*/
|
||||
|
||||
str = IntTable[num - (quotient * TABLE_MAX)];
|
||||
|
||||
while((*digitptr = *str))
|
||||
{
|
||||
++digitptr;
|
||||
++str;
|
||||
}
|
||||
}
|
||||
while((num = quotient) != 0);
|
||||
|
||||
while(*(digitptr - 1) == '0')
|
||||
--digitptr;
|
||||
|
||||
while(digitptr != TempBuffer)
|
||||
{
|
||||
*dest++ = *--digitptr;
|
||||
if(++written >= maxbytes)
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
} /* if (ch == 'u') */
|
||||
|
||||
if(ch == 'Q')
|
||||
{
|
||||
const char *arg = va_arg(args, const char *);
|
||||
|
||||
if(arg == NULL)
|
||||
continue;
|
||||
|
||||
const char *str = rsdb_quote(arg);
|
||||
|
||||
while((*dest = *str))
|
||||
{
|
||||
++dest;
|
||||
++str;
|
||||
|
||||
if(++written >= maxbytes)
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if(ch == 'l')
|
||||
{
|
||||
if(*format == 'u')
|
||||
{
|
||||
unsigned long num = va_arg(args, unsigned long);
|
||||
unsigned long quotient;
|
||||
const char *str;
|
||||
char *digitptr = TempBuffer;
|
||||
|
||||
++format;
|
||||
|
||||
if(num == 0)
|
||||
{
|
||||
*dest++ = '0';
|
||||
++written;
|
||||
continue;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
quotient = num / TABLE_MAX;
|
||||
|
||||
/*
|
||||
* Very similar to case 'u'
|
||||
*/
|
||||
|
||||
str = IntTable[num - (quotient * TABLE_MAX)];
|
||||
|
||||
while((*digitptr = *str))
|
||||
{
|
||||
++digitptr;
|
||||
++str;
|
||||
}
|
||||
}
|
||||
while((num = quotient) != 0);
|
||||
|
||||
while(*(digitptr - 1) == '0')
|
||||
--digitptr;
|
||||
|
||||
while(digitptr != TempBuffer)
|
||||
{
|
||||
*dest++ = *--digitptr;
|
||||
if(++written >= maxbytes)
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
else
|
||||
/* if (*format == 'u') */ if(*format == 'd')
|
||||
{
|
||||
long num = va_arg(args, long);
|
||||
long quotient;
|
||||
const char *str;
|
||||
char *digitptr = TempBuffer;
|
||||
|
||||
++format;
|
||||
|
||||
if(num == 0)
|
||||
{
|
||||
*dest++ = '0';
|
||||
++written;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(num < 0)
|
||||
{
|
||||
*dest++ = '-';
|
||||
if(++written >= maxbytes)
|
||||
continue;
|
||||
|
||||
num = -num;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
quotient = num / TABLE_MAX;
|
||||
|
||||
str = IntTable[num - (quotient * TABLE_MAX)];
|
||||
|
||||
while((*digitptr = *str))
|
||||
{
|
||||
++digitptr;
|
||||
++str;
|
||||
}
|
||||
}
|
||||
while((num = quotient) != 0);
|
||||
|
||||
while(*(digitptr - 1) == '0')
|
||||
--digitptr;
|
||||
|
||||
while(digitptr != TempBuffer)
|
||||
{
|
||||
*dest++ = *--digitptr;
|
||||
if(++written >= maxbytes)
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
else /* if (*format == 'd') */
|
||||
{
|
||||
/* XXX error */
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
} /* if (ch == 'l') */
|
||||
|
||||
if(ch != '%')
|
||||
{
|
||||
/* XXX error */
|
||||
exit(1);
|
||||
} /* if (ch != '%') */
|
||||
} /* if (ch == '%') */
|
||||
|
||||
*dest++ = ch;
|
||||
++written;
|
||||
} /* while ((ch = *format++) && (written < maxbytes)) */
|
||||
|
||||
/*
|
||||
* Terminate the destination buffer with a \0
|
||||
*/
|
||||
*dest = '\0';
|
||||
|
||||
return (written);
|
||||
} /* vSnprintf() */
|
||||
|
||||
/*
|
||||
rs_snprintf()
|
||||
Optimized version of snprintf().
|
||||
|
||||
Inputs: dest - destination string
|
||||
bytes - number of bytes to copy
|
||||
format - formatted string
|
||||
args - args to 'format'
|
||||
|
||||
Return: number of characters copied, NOT including the terminating
|
||||
NULL which is always placed at the end of the string
|
||||
*/
|
||||
|
||||
int
|
||||
rs_snprintf(char *dest, const size_t bytes, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int count;
|
||||
|
||||
va_start(args, format);
|
||||
|
||||
count = rs_vsnprintf(dest, bytes, format, args);
|
||||
|
||||
va_end(args);
|
||||
|
||||
return (count);
|
||||
} /* Snprintf() */
|
|
@ -1,265 +0,0 @@
|
|||
/* src/rsdb_sqlite.h
|
||||
* Contains the code for the sqlite database backend.
|
||||
*
|
||||
* Copyright (C) 2003-2006 Lee Hardy <leeh@leeh.co.uk>
|
||||
* Copyright (C) 2003-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.
|
||||
*/
|
||||
#include <sqlite3.h>
|
||||
#include <ircd/stdinc.h>
|
||||
#include "rsdb.h"
|
||||
|
||||
using namespace ircd::defaults;
|
||||
|
||||
struct sqlite3 *rb_bandb;
|
||||
|
||||
rsdb_error_cb *error_cb;
|
||||
|
||||
static void mlog(const char *errstr, ...) AFP(1, 2);
|
||||
static void mlog(const char *errstr, ...)
|
||||
{
|
||||
if(error_cb != NULL)
|
||||
{
|
||||
char buf[256];
|
||||
va_list ap;
|
||||
va_start(ap, errstr);
|
||||
vsnprintf(buf, sizeof(buf), errstr, ap);
|
||||
va_end(ap);
|
||||
error_cb(buf);
|
||||
}
|
||||
else
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
rsdb_init(rsdb_error_cb * ecb)
|
||||
{
|
||||
const char *bandb_dbpath_env;
|
||||
char dbpath[PATH_MAX];
|
||||
char errbuf[1024];
|
||||
error_cb = ecb;
|
||||
|
||||
/* try a path from the environment first, useful for basedir overrides */
|
||||
bandb_dbpath_env = getenv("BANDB_DBPATH");
|
||||
|
||||
if(bandb_dbpath_env != NULL)
|
||||
rb_strlcpy(dbpath, bandb_dbpath_env, sizeof(dbpath));
|
||||
else
|
||||
rb_strlcpy(dbpath, ircd::path::BDBPATH, sizeof(dbpath));
|
||||
|
||||
if(sqlite3_open(dbpath, &rb_bandb) != SQLITE_OK)
|
||||
{
|
||||
snprintf(errbuf, sizeof(errbuf), "Unable to open sqlite database ('%s'): %s",
|
||||
dbpath, sqlite3_errmsg(rb_bandb));
|
||||
mlog(errbuf);
|
||||
return -1;
|
||||
}
|
||||
if(access(dbpath, W_OK))
|
||||
{
|
||||
snprintf(errbuf, sizeof(errbuf), "Unable to open sqlite database ('%s') for write: %s",
|
||||
dbpath, strerror(errno));
|
||||
mlog(errbuf);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
rsdb_shutdown(void)
|
||||
{
|
||||
if(rb_bandb)
|
||||
sqlite3_close(rb_bandb);
|
||||
}
|
||||
|
||||
const char *
|
||||
rsdb_quote(const char *src)
|
||||
{
|
||||
static char buf[BUFSIZE * 4];
|
||||
char *p = buf;
|
||||
|
||||
/* cheap and dirty length check.. */
|
||||
if(strlen(src) >= (sizeof(buf) / 2))
|
||||
return NULL;
|
||||
|
||||
while(*src)
|
||||
{
|
||||
if(*src == '\'')
|
||||
*p++ = '\'';
|
||||
|
||||
*p++ = *src++;
|
||||
}
|
||||
|
||||
*p = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int
|
||||
rsdb_callback_func(void *cbfunc, int argc, char **argv, char **colnames)
|
||||
{
|
||||
rsdb_callback cb = (rsdb_callback)((uintptr_t)cbfunc);
|
||||
(cb) (argc, (const char **)(void *)argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
rsdb_exec(rsdb_callback cb, const char *format, ...)
|
||||
{
|
||||
static char buf[BUFSIZE * 4];
|
||||
va_list args;
|
||||
char *errmsg;
|
||||
unsigned int i;
|
||||
int j;
|
||||
|
||||
va_start(args, format);
|
||||
i = rs_vsnprintf(buf, sizeof(buf), format, args);
|
||||
va_end(args);
|
||||
|
||||
if(i >= sizeof(buf))
|
||||
{
|
||||
mlog("fatal error: length problem with compiling sql");
|
||||
}
|
||||
|
||||
if((i = sqlite3_exec(rb_bandb, buf, (cb ? rsdb_callback_func : NULL), (void *)((uintptr_t)cb), &errmsg)))
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case SQLITE_BUSY:
|
||||
for(j = 0; j < 5; j++)
|
||||
{
|
||||
rb_sleep(0, 500000);
|
||||
if(!sqlite3_exec
|
||||
(rb_bandb, buf, (cb ? rsdb_callback_func : NULL), (void *)((uintptr_t)cb), &errmsg))
|
||||
return;
|
||||
}
|
||||
|
||||
/* failed, fall through to default */
|
||||
mlog("fatal error: problem with db file: %s", errmsg);
|
||||
break;
|
||||
|
||||
default:
|
||||
mlog("fatal error: problem with db file: %s", errmsg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rsdb_exec_fetch(struct rsdb_table *table, const char *format, ...)
|
||||
{
|
||||
static char buf[BUFSIZE * 4];
|
||||
va_list args;
|
||||
char *errmsg;
|
||||
char **data;
|
||||
int pos;
|
||||
unsigned int retval;
|
||||
int i, j;
|
||||
|
||||
va_start(args, format);
|
||||
retval = rs_vsnprintf(buf, sizeof(buf), format, args);
|
||||
va_end(args);
|
||||
|
||||
if(retval >= sizeof(buf))
|
||||
{
|
||||
mlog("fatal error: length problem with compiling sql");
|
||||
}
|
||||
|
||||
if((retval =
|
||||
sqlite3_get_table(rb_bandb, buf, &data, &table->row_count, &table->col_count, &errmsg)))
|
||||
{
|
||||
int success = 0;
|
||||
|
||||
switch (retval)
|
||||
{
|
||||
case SQLITE_BUSY:
|
||||
for(i = 0; i < 5; i++)
|
||||
{
|
||||
rb_sleep(0, 500000);
|
||||
if(!sqlite3_get_table
|
||||
(rb_bandb, buf, &data, &table->row_count, &table->col_count,
|
||||
&errmsg))
|
||||
{
|
||||
success++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(success)
|
||||
break;
|
||||
|
||||
mlog("fatal error: problem with db file: %s", errmsg);
|
||||
break;
|
||||
|
||||
default:
|
||||
mlog("fatal error: problem with db file: %s", errmsg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* we need to be able to free data afterward */
|
||||
table->arg = data;
|
||||
|
||||
if(table->row_count == 0)
|
||||
{
|
||||
table->row = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* sqlite puts the column names as the first row */
|
||||
pos = table->col_count;
|
||||
table->row = (char ***)rb_malloc(sizeof(char **) * table->row_count);
|
||||
for(i = 0; i < table->row_count; i++)
|
||||
{
|
||||
table->row[i] = (char **)rb_malloc(sizeof(char *) * table->col_count);
|
||||
|
||||
for(j = 0; j < table->col_count; j++)
|
||||
{
|
||||
table->row[i][j] = data[pos++];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rsdb_exec_fetch_end(struct rsdb_table *table)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < table->row_count; i++)
|
||||
{
|
||||
rb_free(table->row[i]);
|
||||
}
|
||||
rb_free(table->row);
|
||||
|
||||
sqlite3_free_table((char **)table->arg);
|
||||
}
|
||||
|
||||
void
|
||||
rsdb_transaction(rsdb_transtype type)
|
||||
{
|
||||
if(type == RSDB_TRANS_START)
|
||||
rsdb_exec(NULL, "BEGIN TRANSACTION");
|
||||
else if(type == RSDB_TRANS_END)
|
||||
rsdb_exec(NULL, "COMMIT TRANSACTION");
|
||||
}
|
189270
bandb/sqlite3.c
189270
bandb/sqlite3.c
File diff suppressed because it is too large
Load diff
8733
bandb/sqlite3.h
8733
bandb/sqlite3.h
File diff suppressed because it is too large
Load diff
|
@ -10,11 +10,11 @@ AM_LDFLAGS = \
|
|||
-dlopen self \
|
||||
-Wl,-fuse-ld=gold \
|
||||
-Wl,--no-undefined \
|
||||
-Wl,--no-gnu-unique
|
||||
-Wl,--no-gnu-unique \
|
||||
$(PLATFORM_LDFLAGS)
|
||||
|
||||
AM_LDFLAGS += \
|
||||
-L$(top_srcdir)/ircd \
|
||||
-L$(top_srcdir)/rb \
|
||||
@ROCKSDB_LDFLAGS@ \
|
||||
@JS_LDFLAGS@ \
|
||||
@BOOST_LDFLAGS@
|
||||
|
@ -28,7 +28,8 @@ charybdis_SOURCES = \
|
|||
|
||||
charybdis_LDADD = \
|
||||
-lircd \
|
||||
-lrb \
|
||||
@ROCKSDB_LIBS@ \
|
||||
@JS_LIBS@ \
|
||||
@BOOST_LIBS@
|
||||
@BOOST_LIBS@ \
|
||||
-lcrypto \
|
||||
-lssl
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#include <ircd/ircd.h>
|
||||
#include <boost/asio.hpp>
|
||||
#include <ircd/ctx/ctx.h>
|
||||
#include <ircd/ctx/continuation.h>
|
||||
#include "lgetopt.h"
|
||||
|
||||
namespace path = ircd::path;
|
||||
|
@ -119,7 +119,7 @@ try
|
|||
|
||||
ios->run(); // Blocks until a clean exit or an exception comes out of it.
|
||||
}
|
||||
catch(const ircd::conf::newconf::syntax_error &e)
|
||||
catch(const ircd::user_error &e)
|
||||
{
|
||||
if(ircd::debugmode)
|
||||
throw;
|
||||
|
@ -156,7 +156,7 @@ void print_version()
|
|||
PACKAGE_VERSION);
|
||||
#endif
|
||||
|
||||
printf("VERSION :%s\n", rb_lib_version());
|
||||
printf("VERSION :boost %d\n", BOOST_VERSION);
|
||||
}
|
||||
|
||||
bool startup_checks()
|
||||
|
@ -347,8 +347,8 @@ console_spawn()
|
|||
return;
|
||||
|
||||
// The console function is executed asynchronously.
|
||||
// The SELF_DESTRUCT indicates it will clean itself up.
|
||||
ircd::context(std::bind(&console), ircd::ctx::SELF_DESTRUCT);
|
||||
// The DETACH indicates it will clean itself up.
|
||||
ircd::context(std::bind(&console), ircd::context::DETACH);
|
||||
}
|
||||
|
||||
const char *const console_message
|
||||
|
@ -398,7 +398,7 @@ try
|
|||
if(!line.empty())
|
||||
handle_line(line);
|
||||
}
|
||||
catch(const ircd::cmds::not_found &e)
|
||||
catch(const ircd::resource::not_found &e)
|
||||
{
|
||||
std::cerr << e.what() << std::endl;
|
||||
}
|
||||
|
@ -431,8 +431,9 @@ handle_line(const std::string &line)
|
|||
if(line == "EXIT")
|
||||
exit(0);
|
||||
|
||||
if(unlikely(!ircd::me))
|
||||
throw ircd::error("IRCd `me' not available to execute on");
|
||||
//if(unlikely(!ircd::me))
|
||||
// throw ircd::error("IRCd `me' not available to execute on");
|
||||
|
||||
ircd::execute(*ircd::me, line);
|
||||
//ircd::execute(*ircd::me, line);
|
||||
ircd::test(line);
|
||||
}
|
||||
|
|
249
configure.ac
249
configure.ac
|
@ -31,7 +31,7 @@ AC_PROG_CC_C_O
|
|||
AC_PROG_CXX
|
||||
AC_PROG_CXX_C_O
|
||||
AC_LANG(C++)
|
||||
AC_CONFIG_HEADER(include/rb/config.h)
|
||||
AC_CONFIG_HEADER(include/ircd/config.h)
|
||||
AX_CXX_COMPILE_STDCXX([14], [gnu], [mandatory], 201300)
|
||||
|
||||
AC_PROG_YACC
|
||||
|
@ -53,21 +53,14 @@ dnl
|
|||
|
||||
AC_CONFIG_FILES(\
|
||||
Makefile \
|
||||
include/rb/Makefile \
|
||||
include/ircd/Makefile \
|
||||
rb/Makefile \
|
||||
authd/Makefile \
|
||||
charybdis/Makefile \
|
||||
ircd/Makefile \
|
||||
bandb/Makefile \
|
||||
doc/Makefile \
|
||||
extensions/Makefile \
|
||||
help/Makefile \
|
||||
modules/Makefile \
|
||||
ssld/Makefile \
|
||||
tools/Makefile \
|
||||
tools/genssl \
|
||||
wsockd/Makefile \
|
||||
tools/genssl
|
||||
)
|
||||
|
||||
AM_INIT_AUTOMAKE([subdir-objects])
|
||||
|
@ -267,59 +260,21 @@ AC_DEFUN([RB_CHK_SYSHEADER],
|
|||
|
||||
AC_HEADER_STDBOOL
|
||||
dnl AC_HEADER_STDC
|
||||
RB_CHK_SYSHEADER([errno.h], [ERRNO_H])
|
||||
RB_CHK_SYSHEADER([assert.h], [ASSERT_H])
|
||||
RB_CHK_SYSHEADER([stddef.h], [STDDEF_H])
|
||||
RB_CHK_SYSHEADER([stdarg.h], [STDARG_H])
|
||||
RB_CHK_SYSHEADER([stdint.h], [STDINT_H])
|
||||
RB_CHK_SYSHEADER([inttypes.h], [INTTYPES_H])
|
||||
RB_CHK_SYSHEADER([ctype.h], [CTYPE_H])
|
||||
RB_CHK_SYSHEADER([limits.h], [LIMITS_H])
|
||||
RB_CHK_SYSHEADER([stdlib.h], [STDLIB_H])
|
||||
RB_CHK_SYSHEADER([unistd.h], [UNISTD_H])
|
||||
RB_CHK_SYSHEADER([time.h], [TIME_H])
|
||||
RB_CHK_SYSHEADER([fcntl.h], [FCNTL_H])
|
||||
RB_CHK_SYSHEADER([signal.h], [SIGNAL_H])
|
||||
RB_CHK_SYSHEADER([dirent.h], [DIRENT_H])
|
||||
RB_CHK_SYSHEADER([sys/types.h], [SYS_TYPES_H])
|
||||
RB_CHK_SYSHEADER([sys/time.h], [SYS_TIME_H])
|
||||
RB_CHK_SYSHEADER([sys/stat.h], [SYS_STAT_H])
|
||||
RB_CHK_SYSHEADER([sys/file.h], [SYS_FILE_H])
|
||||
RB_CHK_SYSHEADER([sys/param.h], [SYS_PARAM_H])
|
||||
RB_CHK_SYSHEADER([sys/resource.h], [SYS_RESOURCE_H])
|
||||
RB_CHK_SYSHEADER([sys/socket.h], [SYS_SOCKET_H])
|
||||
RB_CHK_SYSHEADER([sys/syslog.h], [SYS_SYSLOG_H])
|
||||
RB_CHK_SYSHEADER([sys/wait.h], [SYS_WAIT_H])
|
||||
RB_CHK_SYSHEADER([wait.h], [WAIT_H])
|
||||
RB_CHK_SYSHEADER([arpa/inet.h], [ARPA_INET_H])
|
||||
RB_CHK_SYSHEADER([netinet/in.h], [NETINET_IN_H])
|
||||
RB_CHK_SYSHEADER([netinet/tcp.h], [NETINET_TCP_H])
|
||||
RB_CHK_SYSHEADER([string.h], [STRING_H])
|
||||
RB_CHK_SYSHEADER([strings.h], [STRINGS_H])
|
||||
RB_CHK_SYSHEADER([stdio.h], [STDIO_H])
|
||||
RB_CHK_SYSHEADER([crypt.h], [CRYPT_H])
|
||||
RB_CHK_SYSHEADER([sys/uio.h], [SYS_UIO_H])
|
||||
RB_CHK_SYSHEADER([spawn.h], [SPAWN_H])
|
||||
RB_CHK_SYSHEADER([sys/poll.h], [SYS_POLL_H])
|
||||
RB_CHK_SYSHEADER([sys/epoll.h], [SYS_EPOLL_H])
|
||||
RB_CHK_SYSHEADER([sys/select.h], [SYS_SELECT_H])
|
||||
RB_CHK_SYSHEADER([sys/devpoll.h], [SYS_DEVPOLL_H])
|
||||
RB_CHK_SYSHEADER([sys/event.h], [SYS_EVENT_H])
|
||||
RB_CHK_SYSHEADER([port.h], [PORT_H])
|
||||
RB_CHK_SYSHEADER([sys/signalfd.h], [SYS_SIGNALFD_H])
|
||||
RB_CHK_SYSHEADER([sys/timerfd.h], [SYS_TIMERFD_H])
|
||||
RB_CHK_SYSHEADER([execinfo.h], [EXECINFO_H])
|
||||
RB_CHK_SYSHEADER([machine/endian.h], [MACHINE_ENDIAN_H])
|
||||
|
||||
RB_CHK_SYSHEADER([cstddef], [CSTDDEF])
|
||||
RB_CHK_SYSHEADER([cstdint], [CSTDINT])
|
||||
RB_CHK_SYSHEADER([limits], [LIMITS])
|
||||
RB_CHK_SYSHEADER([type_traits], [TYPE_TRAITS])
|
||||
RB_CHK_SYSHEADER([typeindex], [TYPEINDEX])
|
||||
RB_CHK_SYSHEADER([variant], [VARIANT])
|
||||
RB_CHK_SYSHEADER([utility], [UTILITY])
|
||||
RB_CHK_SYSHEADER([functional], [FUNCTIONAL])
|
||||
RB_CHK_SYSHEADER([algorithm], [ALGORITHM])
|
||||
RB_CHK_SYSHEADER([numeric], [NUMERIC])
|
||||
RB_CHK_SYSHEADER([cmath], [CMATH])
|
||||
RB_CHK_SYSHEADER([memory], [MEMORY])
|
||||
RB_CHK_SYSHEADER([exception], [EXCEPTION])
|
||||
RB_CHK_SYSHEADER([cerrno], [CERRNO])
|
||||
|
@ -335,6 +290,7 @@ RB_CHK_SYSHEADER([vector], [VECTOR])
|
|||
RB_CHK_SYSHEADER([forward_list], [FORWARD_LIST])
|
||||
RB_CHK_SYSHEADER([unordered_map], [UNORDERED_MAP])
|
||||
RB_CHK_SYSHEADER([string], [STRING])
|
||||
RB_CHK_SYSHEADER([cstring], [CSTRING])
|
||||
RB_CHK_SYSHEADER([locale], [LOCALE])
|
||||
RB_CHK_SYSHEADER([codecvt], [CODECVT])
|
||||
RB_CHK_SYSHEADER([sstream], [SSTREAM])
|
||||
|
@ -395,104 +351,24 @@ AC_CHECK_FUNCS([ \
|
|||
strlcpy \
|
||||
strlcat \
|
||||
strnlen \
|
||||
strcasestr \
|
||||
strcasecmp \
|
||||
strncasecmp \
|
||||
strdup \
|
||||
strndup \
|
||||
strtok_r \
|
||||
snprintf \
|
||||
vsnprintf \
|
||||
gettimeofday \
|
||||
getrusage \
|
||||
gmtime_r \
|
||||
usleep \
|
||||
fstat \
|
||||
writev \
|
||||
sendmsg \
|
||||
socketpair \
|
||||
signalfd \
|
||||
timerfd_create \
|
||||
port_create \
|
||||
epoll_ctl \
|
||||
kevent \
|
||||
poll \
|
||||
select \
|
||||
getexecname \
|
||||
posix_spawn \
|
||||
arc4random \
|
||||
vsnprintf
|
||||
])
|
||||
|
||||
AC_SEARCH_LIBS(dlinfo, dl, AC_DEFINE(HAVE_DLINFO, 1, [Define if you have dlinfo]))
|
||||
AC_SEARCH_LIBS(nanosleep, rt posix4, AC_DEFINE(HAVE_NANOSLEEP, 1, [Define if you have nanosleep]))
|
||||
AC_SEARCH_LIBS(timer_create, rt, AC_DEFINE(HAVE_TIMER_CREATE, 1, [Define if you have timer_create]))
|
||||
|
||||
|
||||
dnl
|
||||
dnl Networking Functions
|
||||
dnl
|
||||
|
||||
AC_SEARCH_LIBS(socket, [socket],,)
|
||||
AC_CHECK_MEMBER([struct sockaddr.sa_len], [AC_DEFINE(SOCKADDR_IN_HAS_LEN, 1, [Define to 1 if sockaddr has a 'sa_len' member.])],,[[
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
]])
|
||||
|
||||
AC_CHECK_TYPE([socklen_t], rb_cv_socklen_t=socklen_t,[
|
||||
AC_MSG_CHECKING([for socklen_t equivalent])
|
||||
AC_CACHE_VAL([rb_cv_socklen_t],
|
||||
[
|
||||
# Systems have either "struct sockaddr *" or
|
||||
# "void *" as the second argument to getpeername
|
||||
rb_cv_socklen_t=
|
||||
for arg2 in "struct sockaddr" void; do
|
||||
for t in int size_t unsigned long "unsigned long"; do
|
||||
AC_TRY_COMPILE([
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#endif
|
||||
int getpeername (int, $arg2 *, $t *);
|
||||
],[
|
||||
$t len;
|
||||
getpeername(0,0,&len);
|
||||
],[
|
||||
rb_cv_socklen_t="$t"
|
||||
break
|
||||
AC_ARG_ENABLE(ipv6, AC_HELP_STRING([--disable-ipv6], [Disable IPv6 support]),
|
||||
[
|
||||
ipv6=$enableval
|
||||
], [
|
||||
ipv6=yes
|
||||
])
|
||||
done
|
||||
done
|
||||
|
||||
if test "x$rb_cv_socklen_t" = x; then
|
||||
AC_MSG_WARN([Cannot find a type to use in place of socklen_t using int])
|
||||
rb_cv_socklen_t=int
|
||||
fi
|
||||
])
|
||||
AC_MSG_RESULT($rb_cv_socklen_t)],
|
||||
[#include <sys/types.h>
|
||||
#include <sys/socket.h>])
|
||||
|
||||
rb_socklen_t=$rb_cv_socklen_t
|
||||
|
||||
AC_CHECK_TYPE([sa_family_t], [],
|
||||
[AC_DEFINE(sa_family_t, [u_int16_t], [If system does not define sa_family_t, define it here.])],
|
||||
[[#include <sys/types.h>
|
||||
#include <sys/socket.h>]])
|
||||
|
||||
AC_ARG_ENABLE(ipv6, AC_HELP_STRING([--disable-ipv6], [Disable IPv6 support]), [ipv6=$enableval], [ipv6=yes])
|
||||
|
||||
dnl TODO: IPV6 CHECKS
|
||||
|
||||
|
@ -502,75 +378,6 @@ else
|
|||
AC_DEFINE([HAVE_IPV6], [0], [IPv6 not supported])
|
||||
fi
|
||||
|
||||
AC_CHECK_TYPES([struct sockaddr_storage],[
|
||||
rb_have_sockaddr_storage=yes
|
||||
],[], [
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
])
|
||||
|
||||
|
||||
AC_MSG_CHECKING(for /dev/poll)
|
||||
if test -c "/dev/poll"; then
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_DEVPOLL, [1], [Define to 1 if you have devpoll])
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
|
||||
dnl SunOS/Solaris required libnsl for inet_ntoa()
|
||||
if test x"$SUN" = xyes; then
|
||||
AC_SEARCH_LIBS(inet_ntoa, nsl,, [AC_MSG_ERROR([libnsl not found! Aborting.])])
|
||||
fi
|
||||
|
||||
AC_SEARCH_LIBS(crypt, [crypt descrypt],,)
|
||||
|
||||
CRYPT_LIB=$ac_cv_search_crypt
|
||||
|
||||
if test "$CRYPT_LIB" = "none required"; then
|
||||
unset CRYPT_LIB
|
||||
elif test "$CRYPT_LIB" = no; then
|
||||
unset CRYPT_LIB
|
||||
fi
|
||||
|
||||
AC_SUBST(CRYPT_LIB)
|
||||
|
||||
dnl definitions are in m4/charybdis.m4
|
||||
RB_CHECK_TIMER_CREATE
|
||||
RB_CHECK_TIMERFD_CREATE
|
||||
|
||||
AC_CHECK_TYPE([sa_family_t], [],
|
||||
[AC_DEFINE(sa_family_t, [u_int16_t], [If system does not define sa_family_t, define it here.])],
|
||||
[[#include <sys/types.h>
|
||||
#include <sys/socket.h>]])
|
||||
|
||||
dnl check for various functions...
|
||||
|
||||
|
||||
dnl check for nanosleep
|
||||
AC_CHECK_FUNC(nanosleep,,[AC_CHECK_LIB(rt,nanosleep,
|
||||
LIBS="${LIBS} -lrt",
|
||||
[AC_CHECK_LIB(posix4,nanosleep, LIBS="${LIBS} -lposix4"
|
||||
)])])
|
||||
if test x$ac_cv_func_nanosleep = xno && test x$ac_cv_lib_posix4_nanosleep = xno && test x$ac_cv_lib_rt_nanosleep = xno
|
||||
then
|
||||
AC_MSG_RESULT("nanosleep not found..using select for delay")
|
||||
else
|
||||
AC_DEFINE([HAVE_NANOSLEEP], 1, [Define if nanosleep exists])
|
||||
fi
|
||||
|
||||
dnl check for /dev/null so we can use it to hold evil fd's
|
||||
AC_MSG_CHECKING([for /dev/null])
|
||||
if test -c /dev/null ; then
|
||||
AC_DEFINE(PATH_DEVNULL, "/dev/null", [Path to /dev/null])
|
||||
AC_MSG_RESULT(yes)
|
||||
else
|
||||
AC_DEFINE(PATH_DEVNULL, "devnull.log", [Path to /dev/null])
|
||||
AC_MSG_RESULT(no - using devnull.log)
|
||||
fi
|
||||
|
||||
|
||||
|
||||
dnl ***************************************************************************
|
||||
dnl TODO: sort this OS-specific section
|
||||
|
@ -813,7 +620,7 @@ AC_HELP_STRING([--with-included-boost[[[=shared]]]], [Use the boost sources from
|
|||
fi
|
||||
|
||||
boost_linkage="$withval"
|
||||
bash tools/boostrap.sh $BTOOLSET $BOOST_BUILT_LIBS release shared multi
|
||||
bash tools/boostrap.sh $BTOOLSET $BOOST_BUILT_LIBS release $withval multi
|
||||
if [[ $? != 0 ]]; then
|
||||
AC_MSG_ERROR([Failed to build included boost.])
|
||||
fi
|
||||
|
@ -858,9 +665,7 @@ else
|
|||
[
|
||||
AC_SUBST(BOOST_LIBS, ["$boost_libdir/libboost_coroutine-mgw53-1_61.dll.a $boost_libdir/libboost_context-mgw53-1_61.dll.a $boost_libdir/libboost_thread-mgw53-1_61.dll.a $boost_libdir/libboost_filesystem-mgw53-1_61.dll.a $boost_libdir/libboost_system-mgw53-1_61.dll.a"])
|
||||
], [
|
||||
AC_SUBST(BOOST_LIBS, ["-lboost_coroutine -lboost_context -lboost_thread -lboost_filesystem -lboost_system"])
|
||||
dnl AC_SUBST(BOOST_LIBS, ["$boost_libdir/libboost_filesystem.a"])
|
||||
dnl AC_SUBST(BOOST_LIBS, ["$boost_libdir/libboost_system.a"])
|
||||
AC_SUBST(BOOST_LIBS, ["$boost_libdir/libboost_coroutine.a $boost_libdir/libboost_context.a $boost_libdir/libboost_thread.a $boost_libdir/libboost_filesystem.a $boost_libdir/libboost_system.a"])
|
||||
])
|
||||
fi
|
||||
|
||||
|
@ -973,6 +778,11 @@ AC_HELP_STRING([--with-included-js[[[=shared]]]], [Use the JS engine (SpiderMonk
|
|||
fi
|
||||
|
||||
bash tools/buildjs.sh "$js_branch" "$js_options" "$js_jobs"
|
||||
|
||||
RB_DEFINE_UNQUOTED([ENABLE_JS], [1], [ Enable JavaScript support. ])
|
||||
RB_DEFINE_UNQUOTED([INC_JSAPI_H], [jsapi.h>], [ SpiderMonkey JavaScript API. ])
|
||||
RB_DEFINE_UNQUOTED([INC_JSFRIENDAPI_H], [jsfriendapi.h>], [ SpiderMonkey JavaScript Extended API. ])
|
||||
RB_DEFINE_UNQUOTED([INC_JS_CONVERSIONS_H], [js/Conversions.h>], [ SpiderMonkey JavaScript Conversions. ])
|
||||
],[
|
||||
AC_MSG_RESULT([no])
|
||||
with_included_js="no"
|
||||
|
@ -982,15 +792,29 @@ AC_HELP_STRING([--with-included-js[[[=shared]]]], [Use the JS engine (SpiderMonk
|
|||
[
|
||||
|
||||
], [
|
||||
AC_MSG_ERROR([Unable to find required JS engine (SpiderMonkey 45) package. Try apt-get install libmozjs-dev])
|
||||
AC_MSG_WARN([Unable to find JS engine (SpiderMonkey 45) package. Try apt-get install libmozjs-dev])
|
||||
])
|
||||
|
||||
dnl TODO
|
||||
AC_SUBST(JS_CPPFLAGS, ["-I/usr/include/mozjs-45"])
|
||||
AC_SUBST(JS_LDFLAGS, [])
|
||||
AC_SUBST(JS_LIBS, ["-lmozjs-45"])
|
||||
dnl AC_SUBST(JS_CPPFLAGS, ["-I/usr/include/mozjs-45"])
|
||||
dnl AC_SUBST(JS_LDFLAGS, [])
|
||||
dnl AC_SUBST(JS_LIBS, ["-lmozjs-45"])
|
||||
])
|
||||
|
||||
dnl TODO use an $enable_js var
|
||||
AM_CONDITIONAL([JS], [[[[ $with_included_js = yes ]]]])
|
||||
|
||||
|
||||
dnl
|
||||
dnl libgmp support
|
||||
dnl
|
||||
|
||||
PKG_CHECK_MODULES(GMP, [libgmp], [have_gmp="yes"], [have_gmp="no"])
|
||||
AM_CONDITIONAL([GMP], [test "x$have_gmp" = "xyes"])
|
||||
|
||||
AC_SUBST(GMP_CPPFLAGS, [])
|
||||
AC_SUBST(GMP_LDFLAGS, [])
|
||||
AC_SUBST(GMP_LIBS, ["-lgmp"])
|
||||
|
||||
|
||||
dnl
|
||||
|
@ -1427,6 +1251,7 @@ echo "Building RocksDB................... $with_included_rocksdb"
|
|||
echo "Building JS (SpiderMonkey) ........ $with_included_js"
|
||||
echo "Precompiled headers ............... $build_pch"
|
||||
echo "Developer debug ................... $debug"
|
||||
echo "GNU MP support .................... $have_gmp"
|
||||
echo "IPv6 support ...................... $ipv6"
|
||||
echo "SSL type........................... $SSL_TYPE"
|
||||
echo "Installing into ................... $prefix"
|
||||
|
|
|
@ -1,171 +0,0 @@
|
|||
extensiondir=@moduledir@
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir)/include \
|
||||
@BOOST_CPPFLAGS@ \
|
||||
-include $(top_srcdir)/include/ircd/ircd.h
|
||||
|
||||
if BUILD_PCH
|
||||
endif
|
||||
|
||||
AM_LDFLAGS = \
|
||||
-L$(top_srcdir)/ircd \
|
||||
-L$(top_srcdir)/rb \
|
||||
@BOOST_LDFLAGS@
|
||||
|
||||
AM_LDFLAGS += \
|
||||
-module \
|
||||
-shared \
|
||||
-export-dynamic \
|
||||
-avoid-version \
|
||||
-no-undefined \
|
||||
--no-allow-shlib-undefined \
|
||||
-export-symbols-regex _mheader
|
||||
|
||||
AM_LDFLAGS += \
|
||||
-lircd \
|
||||
-lrb \
|
||||
@BOOST_LIBS@
|
||||
|
||||
|
||||
#chm_adminonly_la_SOURCES = chm_adminonly.cc
|
||||
#chm_operonly_la_SOURCES = chm_operonly.cc
|
||||
#chm_operonly_compat_la_SOURCES = chm_operonly_compat.cc
|
||||
#chm_insecure_la_SOURCES = chm_insecure.cc
|
||||
#chm_nonotice_la_SOURCES = chm_nonotice.cc
|
||||
#chm_operpeace_la_SOURCES = chm_operpeace.cc
|
||||
#chm_quietunreg_compat_la_SOURCES = chm_quietunreg_compat.cc
|
||||
#chm_spamfilter_la_SOURCES = chm_spamfilter.cc
|
||||
#chm_sslonly_la_SOURCES = chm_sslonly.cc
|
||||
#chm_sslonly_compat_la_SOURCES = chm_sslonly_compat.cc
|
||||
#createauthonly_la_SOURCES = createauthonly.cc
|
||||
#createoperonly_la_SOURCES = createoperonly.cc
|
||||
#extb_account_la_SOURCES = extb_account.cc
|
||||
#extb_canjoin_la_SOURCES = extb_canjoin.cc
|
||||
#extb_channel_la_SOURCES = extb_channel.cc
|
||||
#extb_hostmask_la_SOURCES = extb_hostmask.cc
|
||||
#extb_oper_la_SOURCES = extb_oper.cc
|
||||
#extb_server_la_SOURCES = extb_server.cc
|
||||
#extb_ssl_la_SOURCES = extb_ssl.cc
|
||||
#extb_realname_la_SOURCES = extb_realname.cc
|
||||
#extb_usermode_la_SOURCES = extb_usermode.cc
|
||||
#extb_extgecos_la_SOURCES = extb_extgecos.cc
|
||||
#extb_combi_la_SOURCES = extb_combi.cc
|
||||
#force_user_invis_la_SOURCES = force_user_invis.cc
|
||||
#helpops_la_SOURCES = helpops.cc
|
||||
#hurt_la_SOURCES = hurt.cc
|
||||
#ip_cloaking_la_SOURCES = ip_cloaking.cc
|
||||
#override_la_SOURCES = override.cc
|
||||
#restrict_unauthenticated_la_SOURCES = restrict-unauthenticated.cc
|
||||
#sno_channelcreate_la_SOURCES = sno_channelcreate.cc
|
||||
#sno_farconnect_la_SOURCES = sno_farconnect.cc
|
||||
#sno_globalkline_la_SOURCES = sno_globalkline.cc
|
||||
#sno_globalnickchange_la_SOURCES = sno_globalnickchange.cc
|
||||
#sno_globaloper_la_SOURCES = sno_globaloper.cc
|
||||
#sno_whois_la_SOURCES = sno_whois.cc
|
||||
#umode_noctcp_la_SOURCES = umode_noctcp.cc
|
||||
#m_adminwall_la_SOURCES = m_adminwall.cc
|
||||
#m_echotags_la_SOURCES = m_echotags.cc
|
||||
#m_extendchans_la_SOURCES = m_extendchans.cc
|
||||
#m_findforwards_la_SOURCES = m_findforwards.cc
|
||||
#m_identify_la_SOURCES = m_identify.cc
|
||||
#m_locops_la_SOURCES = m_locops.cc
|
||||
#m_mkpasswd_la_SOURCES = m_mkpasswd.cc
|
||||
#m_ojoin_la_SOURCES = m_ojoin.cc
|
||||
#m_okick_la_SOURCES = m_okick.cc
|
||||
#m_omode_la_SOURCES = m_omode.cc
|
||||
#m_opme_la_SOURCES = m_opme.cc
|
||||
#m_sendbans_la_SOURCES = m_sendbans.cc
|
||||
#m_webirc_la_SOURCES = m_webirc.cc
|
||||
#m_remove_la_SOURCES = m_remove.cc
|
||||
#m_roleplay_la_SOURCES = m_roleplay.cc
|
||||
#hide_uncommon_channels_la_SOURCES = hide_uncommon_channels.cc
|
||||
#no_kill_services_la_SOURCES = no_kill_services.cc
|
||||
#no_locops_la_SOURCES = no_locops.cc
|
||||
#no_oper_invis_la_SOURCES = no_oper_invis.cc
|
||||
#spamfilter_nicks_la_SOURCES = spamfilter_nicks.cc
|
||||
#spy_admin_notice_la_SOURCES = spy_admin_notice.cc
|
||||
#spy_info_notice_la_SOURCES = spy_info_notice.cc
|
||||
#spy_links_notice_la_SOURCES = spy_links_notice.cc
|
||||
#spy_motd_notice_la_SOURCES = spy_motd_notice.cc
|
||||
#spy_stats_notice_la_SOURCES = spy_stats_notice.cc
|
||||
#spy_stats_p_notice_la_SOURCES = spy_stats_p_notice.cc
|
||||
#spy_trace_notice_la_SOURCES = spy_trace_notice.cc
|
||||
#example_module_la_SOURCES = example_module.cc
|
||||
|
||||
|
||||
#extension_LTLIBRARIES = \
|
||||
# chm_adminonly.la \
|
||||
# chm_operonly.la \
|
||||
# chm_operonly_compat.la \
|
||||
# chm_insecure.la \
|
||||
# chm_nonotice.la \
|
||||
# chm_operpeace.la \
|
||||
# chm_quietunreg_compat.la \
|
||||
# chm_spamfilter.la \
|
||||
# chm_sslonly.la \
|
||||
# chm_sslonly_compat.la \
|
||||
# createauthonly.la \
|
||||
# createoperonly.la \
|
||||
# extb_account.la \
|
||||
# extb_canjoin.la \
|
||||
# extb_channel.la \
|
||||
# extb_hostmask.la \
|
||||
# extb_oper.la \
|
||||
# extb_server.la \
|
||||
# extb_ssl.la \
|
||||
# extb_realname.la \
|
||||
# extb_usermode.la \
|
||||
# extb_extgecos.la \
|
||||
# extb_combi.la \
|
||||
# force_user_invis.la \
|
||||
# helpops.la \
|
||||
# hurt.la \
|
||||
# ip_cloaking.la \
|
||||
# override.la \
|
||||
# restrict-unauthenticated.la \
|
||||
# sno_channelcreate.la \
|
||||
# sno_farconnect.la \
|
||||
# sno_globalkline.la \
|
||||
# sno_globalnickchange.la \
|
||||
# sno_globaloper.la \
|
||||
# sno_whois.la \
|
||||
# umode_noctcp.la \
|
||||
# m_adminwall.la \
|
||||
# m_echotags.la \
|
||||
# m_extendchans.la \
|
||||
# m_findforwards.la \
|
||||
# m_identify.la \
|
||||
# m_locops.la \
|
||||
# m_mkpasswd.la \
|
||||
# m_ojoin.la \
|
||||
# m_okick.la \
|
||||
# m_omode.la \
|
||||
# m_opme.la \
|
||||
# m_sendbans.la \
|
||||
# m_webirc.la \
|
||||
# m_remove.la \
|
||||
# m_roleplay.la \
|
||||
# hide_uncommon_channels.la \
|
||||
# no_kill_services.la \
|
||||
# no_locops.la \
|
||||
# no_oper_invis.la \
|
||||
# spamfilter_nicks.la \
|
||||
# spy_admin_notice.la \
|
||||
# spy_info_notice.la \
|
||||
# spy_links_notice.la \
|
||||
# spy_motd_notice.la \
|
||||
# spy_stats_notice.la \
|
||||
# spy_stats_p_notice.la \
|
||||
# spy_trace_notice.la \
|
||||
# example_module.la
|
||||
#
|
||||
#if PCRE
|
||||
#
|
||||
#extension_LTLIBRARIES += spamfilter_expr.la
|
||||
#spamfilter_expr_la_SOURCES = spamfilter_expr.cc
|
||||
#spamfilter_expr_la_CPPFLAGS = $(AM_CPPFLAGS) $(PCRE_CFLAGS)
|
||||
#spamfilter_expr_la_LIBADD = $(PCRE_LIBS)
|
||||
#
|
||||
#endif
|
||||
#
|
|
@ -1,84 +0,0 @@
|
|||
This directory contains extensions (modules) to charybdis ircd that
|
||||
have been contributed by other people, or written by our development
|
||||
team. Unsupported extensions live under unsupported/.
|
||||
|
||||
|
||||
Modules
|
||||
-------
|
||||
|
||||
createauthonly.c - Only allow authenticated (identified) users to create
|
||||
channels.
|
||||
|
||||
ip_cloaking.c - Cloak (spoof) the host for users that have umode +h.
|
||||
|
||||
m_adminwall.c - Sends a message to all admins network-wide (umode +a)
|
||||
Syntax: ADMINWALL :<message>
|
||||
|
||||
m_findforwards.c - Find channels that forward (+f) to a given channel.
|
||||
Syntax: FINDFORWARDS <channel>
|
||||
|
||||
m_identify.c - Identifies to NickServ or ChanServ
|
||||
Syntax: IDENTIFY [nick|channel] <password>
|
||||
|
||||
m_mkpasswd.c - MKPASSWD - generate a DES or MD5 encryption of a password
|
||||
Syntax: MKPASSWD <plaintext> [MD5|DES]
|
||||
|
||||
m_ojoin.c - OJOIN - Join a channel through any modes or limits with
|
||||
an optional status (@+)
|
||||
Syntax: OJOIN [status]<channel>
|
||||
|
||||
m_olist.c - OLIST - Lists channels like LIST, but shows hidden
|
||||
channels. Oper only of course.
|
||||
|
||||
m_opme.c - OPME - Allows an admin to op themselves in an opless channel
|
||||
Syntax: OPME <channel>
|
||||
|
||||
m_omode.c - OMODE - Allows an admin to do all sorts of evil upon a
|
||||
channel, sets modes with extreme prejudice
|
||||
|
||||
m_remove.c - REMOVE - Implements /REMOVE, which allows a channel op to
|
||||
force-part a problematic user from a channel. Most
|
||||
likely, you don't want this, because it is non-standard,
|
||||
and easily worked around for autojoin purposes.
|
||||
|
||||
no_oper_invis.c - Disallow opers setting marking themselves as invisible
|
||||
(+i) unless they have the hidden_oper flag.
|
||||
|
||||
example_module.c - An example module to be used for creating your own.
|
||||
Syntax: TEST
|
||||
|
||||
|
||||
Spy Modules
|
||||
-----------
|
||||
|
||||
The following are the 'spy' parts, accessible via the +y snomask
|
||||
|
||||
spy_admin_notice.c - Spy on clients doing ADMIN
|
||||
spy_info_notice.c - Spy on clients doing INFO
|
||||
spy_links_notice.c - Spy on clients doing LINKS
|
||||
spy_motd_notice.c - Spy on clients doing MOTD
|
||||
spy_stats_notice.c - Spy on clients doing all STATS
|
||||
spy_stats_p_notice.c - Spy on clients doing STATS p only
|
||||
spy_trace_notice.c - Spy on clients doing TRACE
|
||||
|
||||
Note: if you have both spy_stats_notice.c and spy_stats_p_notice.c loaded
|
||||
you will get two messages.
|
||||
|
||||
Snomask Modules
|
||||
---------------
|
||||
|
||||
sno_farconnect.c - Remote client connect/exit notices (snomask +F)
|
||||
sno_globalkline.c - Global K/D/X-line activation notices
|
||||
sno_globaloper.c - Global oper-up notices
|
||||
sno_whois.c - Spy on clients who WHOIS you seeing idle time (snomask +W).
|
||||
|
||||
Extban Modules
|
||||
--------------
|
||||
|
||||
extb_account.so - Account bans (+b $a[:mask])
|
||||
extb_canjoin.so - Banned from another channel (+b $j:mask)
|
||||
extb_channel.so - Other-channel bans (+b $c:mask)
|
||||
extb_extgecos.so - Extended ban (+b $x:mask)
|
||||
extb_oper.so - Oper bans (+b $o)
|
||||
extb_realname.so - Realname (gecos) bans (+b $r:mask)
|
||||
extb_server.so - Server bans (+b $s:mask)
|
|
@ -1,46 +0,0 @@
|
|||
using namespace ircd;
|
||||
|
||||
static const char chm_adminonly_desc[] =
|
||||
"Enables channel mode +A that blocks non-admins from joining a channel";
|
||||
|
||||
static void h_can_join(hook_data_channel *);
|
||||
|
||||
mapi_hfn_list_av1 adminonly_hfnlist[] = {
|
||||
{ "can_join", (hookfn) h_can_join },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static chan::mode::type mymode;
|
||||
|
||||
static int
|
||||
_modinit(void)
|
||||
{
|
||||
using namespace chan::mode;
|
||||
|
||||
mymode = add('A', category::D, functor::staff);
|
||||
if (mymode == 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_moddeinit(void)
|
||||
{
|
||||
chan::mode::orphan('A');
|
||||
}
|
||||
|
||||
DECLARE_MODULE_AV2(chm_adminonly, _modinit, _moddeinit, NULL, NULL, adminonly_hfnlist, NULL, NULL, chm_adminonly_desc);
|
||||
|
||||
static void
|
||||
h_can_join(hook_data_channel *data)
|
||||
{
|
||||
client::client *source_p = data->client;
|
||||
const auto &chptr(data->chptr);
|
||||
|
||||
if((chptr->mode.mode & mymode) && !is(*source_p, umode::ADMIN)) {
|
||||
sendto_one_numeric(source_p, 519, "%s :Cannot join channel (+A) - you are not an IRC server administrator", chptr->name.c_str());
|
||||
data->approved = chan::mode::ERR_CUSTOM;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
using namespace ircd;
|
||||
|
||||
static const char chm_insecure_desc[] =
|
||||
"Adds channel mode +U that allows non-SSL users to join a channel, "
|
||||
"disallowing them by default";
|
||||
|
||||
static void h_can_join(hook_data_channel *);
|
||||
|
||||
mapi_hfn_list_av1 sslonly_hfnlist[] = {
|
||||
{ "can_join", (hookfn) h_can_join },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static chan::mode::type mymode;
|
||||
|
||||
static int
|
||||
_modinit(void)
|
||||
{
|
||||
using namespace chan::mode;
|
||||
|
||||
mymode = add('U', category::D, functor::simple);
|
||||
if (mymode == 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
_moddeinit(void)
|
||||
{
|
||||
chan::mode::orphan('U');
|
||||
}
|
||||
|
||||
DECLARE_MODULE_AV2(chm_insecure, _modinit, _moddeinit, NULL, NULL, sslonly_hfnlist, NULL, NULL, chm_insecure_desc);
|
||||
|
||||
static void
|
||||
h_can_join(hook_data_channel *data)
|
||||
{
|
||||
client::client *source_p = data->client;
|
||||
const auto &chptr(data->chptr);
|
||||
|
||||
if(!(chptr->mode.mode & mymode) && !is(*source_p, umode::SSLCLIENT)) {
|
||||
/* XXX This is equal to ERR_THROTTLE */
|
||||
sendto_one_numeric(source_p, 480, "%s :Cannot join channel (-U) - SSL/TLS required", chptr->name.c_str());
|
||||
data->approved = chan::mode::ERR_CUSTOM;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
/*
|
||||
* charybdis: an advanced ircd.
|
||||
* chm_nonotice: block NOTICEs (+T mode).
|
||||
*
|
||||
* Copyright (c) 2012 William Pitcock <nenolod@dereferenced.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char chm_nonotice_desc[] =
|
||||
"Adds channel mode +T which blocks notices to the channel.";
|
||||
|
||||
static chan::mode::type mode_nonotice;
|
||||
|
||||
static void chm_nonotice_process(hook_data_privmsg_channel *);
|
||||
|
||||
mapi_hfn_list_av1 chm_nonotice_hfnlist[] = {
|
||||
{ "privmsg_channel", (hookfn) chm_nonotice_process },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
chm_nonotice_process(hook_data_privmsg_channel *data)
|
||||
{
|
||||
/* don't waste CPU if message is already blocked */
|
||||
if (data->approved || data->msgtype != MESSAGE_TYPE_NOTICE)
|
||||
return;
|
||||
|
||||
/* block all notices except CTCPs; use chm_noctcp to block CTCPs. */
|
||||
if (data->chptr->mode.mode & mode_nonotice && *data->text != '\001')
|
||||
{
|
||||
sendto_one_numeric(data->source_p, ERR_CANNOTSENDTOCHAN, form_str(ERR_CANNOTSENDTOCHAN), data->chptr->name.c_str());
|
||||
data->approved = ERR_CANNOTSENDTOCHAN;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
_modinit(void)
|
||||
{
|
||||
using namespace chan::mode;
|
||||
|
||||
mode_nonotice = add('T', category::D, functor::simple);
|
||||
if (mode_nonotice == 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_moddeinit(void)
|
||||
{
|
||||
chan::mode::orphan('T');
|
||||
}
|
||||
|
||||
DECLARE_MODULE_AV2(chm_nonotice, _modinit, _moddeinit, NULL, NULL, chm_nonotice_hfnlist, NULL, NULL, chm_nonotice_desc);
|
|
@ -1,47 +0,0 @@
|
|||
using namespace ircd;
|
||||
|
||||
static const char chm_operonly_desc[] =
|
||||
"Adds channel mode +O which makes a channel operator-only";
|
||||
|
||||
static void h_can_join(hook_data_channel *);
|
||||
|
||||
mapi_hfn_list_av1 operonly_hfnlist[] = {
|
||||
{ "can_join", (hookfn) h_can_join },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static chan::mode::type mymode;
|
||||
|
||||
static int
|
||||
_modinit(void)
|
||||
{
|
||||
using namespace chan::mode;
|
||||
|
||||
mymode = add('O', category::D, functor::staff);
|
||||
if (mymode == 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
_moddeinit(void)
|
||||
{
|
||||
chan::mode::orphan('O');
|
||||
}
|
||||
|
||||
DECLARE_MODULE_AV2(chm_operonly, _modinit, _moddeinit, NULL, NULL, operonly_hfnlist, NULL, NULL, chm_operonly_desc);
|
||||
|
||||
static void
|
||||
h_can_join(hook_data_channel *data)
|
||||
{
|
||||
client::client *source_p = data->client;
|
||||
const auto &chptr(data->chptr);
|
||||
|
||||
if((chptr->mode.mode & mymode) && !is(*source_p, umode::OPER)) {
|
||||
sendto_one_numeric(source_p, 520, "%s :Cannot join channel (+O) - you are not an IRC operator", chptr->name.c_str());
|
||||
data->approved = chan::mode::ERR_CUSTOM;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* Treat cmode +-O as +-iI $o.
|
||||
*/
|
||||
|
||||
using namespace ircd::chan::mode;
|
||||
using namespace ircd;
|
||||
|
||||
static const char chm_operonly_compat[] =
|
||||
"Adds an emulated channel mode +O which is converted into mode +i and +I $o";
|
||||
|
||||
static int _modinit(void);
|
||||
static void _moddeinit(void);
|
||||
static void chm_operonly(client::client *source_p, chan::chan *chptr,
|
||||
int alevel, int parc, int *parn,
|
||||
const char **parv, int *errors, int dir, char c, type type);
|
||||
|
||||
DECLARE_MODULE_AV2(chm_operonly_compat, _modinit, _moddeinit, NULL, NULL, NULL, NULL, NULL, chm_operonly_compat);
|
||||
|
||||
static int
|
||||
_modinit(void)
|
||||
{
|
||||
table['O'].type = type(0);
|
||||
table['O'].category = category::D;
|
||||
table['O'].set_func = chm_operonly;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_moddeinit(void)
|
||||
{
|
||||
table['O'].type = type(0);
|
||||
table['O'].category = category::D;
|
||||
table['O'].set_func = functor::nosuch;
|
||||
}
|
||||
|
||||
static void
|
||||
chm_operonly(client::client *source_p, chan::chan *chptr,
|
||||
int alevel, int parc, int *parn,
|
||||
const char **parv, int *errors, int dir, char c, type type)
|
||||
{
|
||||
int newparn = 0;
|
||||
const char *newparv[] = { "$o" };
|
||||
|
||||
if (my(*source_p))
|
||||
{
|
||||
functor::simple(source_p, chptr, alevel, parc, parn, parv, errors, dir, 'i', INVITEONLY);
|
||||
functor::ban(source_p, chptr, alevel, 1, &newparn, newparv, errors, dir, 'I', INVEX);
|
||||
} else
|
||||
functor::nosuch(source_p, chptr, alevel, parc, parn, parv, errors, dir, c, type);
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* Do not allow operators to be kicked from +M channels.
|
||||
* -- kaniini
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char chm_operpeace_desc[] =
|
||||
"Adds channel mode +M which prohibits operators from being kicked";
|
||||
|
||||
static void hdl_can_kick(hook_data_channel_approval *);
|
||||
|
||||
mapi_hfn_list_av1 chm_operpeace_hfnlist[] = {
|
||||
{ "can_kick", (hookfn) hdl_can_kick },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static chan::mode::type mymode;
|
||||
|
||||
static int
|
||||
_modinit(void)
|
||||
{
|
||||
using namespace chan::mode;
|
||||
|
||||
mymode = add('M', category::D, functor::hidden);
|
||||
if (mymode == 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_moddeinit(void)
|
||||
{
|
||||
chan::mode::orphan('M');
|
||||
}
|
||||
|
||||
DECLARE_MODULE_AV2(chm_operpeace, _modinit, _moddeinit, NULL, NULL, chm_operpeace_hfnlist, NULL, NULL, chm_operpeace_desc);
|
||||
|
||||
static void
|
||||
hdl_can_kick(hook_data_channel_approval *data)
|
||||
{
|
||||
client::client *source_p = data->client;
|
||||
client::client *who = data->target;
|
||||
const auto &chptr(data->chptr);
|
||||
|
||||
if(is(*source_p, umode::OPER))
|
||||
return;
|
||||
|
||||
if((chptr->mode.mode & mymode) && is(*who, umode::OPER))
|
||||
{
|
||||
sendto_realops_snomask(sno::GENERAL, L_NETWIDE, "%s attempted to kick %s from %s (which is +M)",
|
||||
source_p->name, who->name, chptr->name.c_str());
|
||||
sendto_one_numeric(source_p, ERR_ISCHANSERVICE, "%s %s :Cannot kick IRC operators from that channel.",
|
||||
who->name, chptr->name.c_str());
|
||||
data->approved = 0;
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* Treat cmode +-R as +-q $~a.
|
||||
* -- jilles
|
||||
*/
|
||||
|
||||
namespace mode = ircd::chan::mode;
|
||||
using namespace mode;
|
||||
using namespace ircd;
|
||||
|
||||
static const char chm_quietunreg_compat_desc[] =
|
||||
"Adds an emulated channel mode +R which is converted into mode +q $~a";
|
||||
|
||||
static int _modinit(void);
|
||||
static void _moddeinit(void);
|
||||
static void chm_quietunreg(client::client *source_p, chan::chan *chptr,
|
||||
int alevel, int parc, int *parn,
|
||||
const char **parv, int *errors, int dir, char c, type type);
|
||||
|
||||
DECLARE_MODULE_AV2(chm_quietunreg_compat, _modinit, _moddeinit, NULL, NULL, NULL, NULL, NULL, chm_quietunreg_compat_desc);
|
||||
|
||||
static int
|
||||
_modinit(void)
|
||||
{
|
||||
table['R'].type = type(0);
|
||||
table['R'].category = category::D;
|
||||
table['R'].set_func = chm_quietunreg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_moddeinit(void)
|
||||
{
|
||||
table['R'].type = type(0);
|
||||
table['R'].category = category(0);
|
||||
table['R'].set_func = functor::nosuch;
|
||||
}
|
||||
|
||||
static void
|
||||
chm_quietunreg(client::client *source_p, chan::chan *chptr,
|
||||
int alevel, int parc, int *parn,
|
||||
const char **parv, int *errors, int dir, char c, type type)
|
||||
{
|
||||
int newparn = 0;
|
||||
const char *newparv[] = { "$~a" };
|
||||
|
||||
if (my(*source_p))
|
||||
functor::ban(source_p, chptr, alevel, 1, &newparn, newparv, errors, dir, 'q', QUIET);
|
||||
else
|
||||
functor::nosuch(source_p, chptr, alevel, parc, parn, parv, errors, dir, c, type);
|
||||
}
|
|
@ -1,157 +0,0 @@
|
|||
/************************************************************************
|
||||
* charybdis: an advanced ircd. extensions/chm_spamfilter.c
|
||||
* Copyright (C) 2016 Jason Volk
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "spamfilter.h"
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
int chm_spamfilter;
|
||||
int h_spamfilter_query;
|
||||
int h_spamfilter_reject;
|
||||
|
||||
char reject_reason[BUFSIZE - CHANNELLEN - 32];
|
||||
|
||||
|
||||
static
|
||||
void hook_privmsg_channel(hook_data_privmsg_channel *const hook)
|
||||
{
|
||||
// Check for mootness by other hooks first
|
||||
if(hook->approved != 0 || EmptyString(hook->text))
|
||||
return;
|
||||
|
||||
// Assess channel related
|
||||
if(~hook->chptr->mode.mode & chm_spamfilter)
|
||||
return;
|
||||
|
||||
// Assess client related
|
||||
if(is_exempt_spambot(*hook->source_p))
|
||||
return;
|
||||
|
||||
// Assess type related
|
||||
if(hook->msgtype != MESSAGE_TYPE_NOTICE && hook->msgtype != MESSAGE_TYPE_PRIVMSG)
|
||||
return;
|
||||
|
||||
// Invoke the active spamfilters
|
||||
call_hook(h_spamfilter_query, hook);
|
||||
if(hook->approved == 0)
|
||||
return;
|
||||
|
||||
call_hook(h_spamfilter_reject, hook);
|
||||
sendto_realops_snomask(sno::REJ|sno::BOTS, L_NETWIDE,
|
||||
"spamfilter: REJECT %s[%s@%s] on %s to %s (%s)",
|
||||
hook->source_p->name,
|
||||
hook->source_p->username,
|
||||
hook->source_p->orighost,
|
||||
hook->source_p->servptr->name,
|
||||
hook->chptr->name.c_str(),
|
||||
hook->reason?: "filter gave no reason");
|
||||
|
||||
hook->reason = reject_reason;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void substitute_reject_reason(void)
|
||||
{
|
||||
rb_dlink_list subs = {0};
|
||||
substitution_append_var(&subs, "network-name", ServerInfo.network_name?: "${network-name}");
|
||||
substitution_append_var(&subs, "admin-email", AdminInfo.email?: "${admin-email}");
|
||||
const char *const substituted = substitution_parse(reject_reason, &subs);
|
||||
rb_strlcpy(reject_reason, substituted, sizeof(reject_reason));
|
||||
substitution_free(&subs);
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void set_reject_reason(void *const str)
|
||||
{
|
||||
rb_strlcpy(reject_reason, (const char *)str, sizeof(reject_reason));
|
||||
substitute_reject_reason();
|
||||
}
|
||||
|
||||
|
||||
struct ConfEntry conf_spamfilter[] =
|
||||
{
|
||||
{ "reject_reason", CF_QSTRING, set_reject_reason, 0, NULL },
|
||||
{ "\0", 0, NULL, 0, NULL }
|
||||
};
|
||||
|
||||
|
||||
static
|
||||
int modinit(void)
|
||||
{
|
||||
using namespace chan::mode;
|
||||
|
||||
chm_spamfilter = add(MODE_SPAMFILTER, category::D, functor::simple);
|
||||
if(!chm_spamfilter)
|
||||
return -1;
|
||||
|
||||
add_top_conf("spamfilter", NULL, NULL, conf_spamfilter);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void modfini(void)
|
||||
{
|
||||
remove_top_conf("spamfilter");
|
||||
chan::mode::orphan(MODE_SPAMFILTER);
|
||||
}
|
||||
|
||||
|
||||
mapi_hlist_av1 hlist[] =
|
||||
{
|
||||
{ "spamfilter_query", &h_spamfilter_query, },
|
||||
{ "spamfilter_reject", &h_spamfilter_reject, },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
mapi_hfn_list_av1 hfnlist[] =
|
||||
{
|
||||
{ "privmsg_channel", (hookfn)hook_privmsg_channel },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static const char chm_spamfilter_desc[] =
|
||||
"Adds channel mode +Y which enables various spam mitigations";
|
||||
|
||||
DECLARE_MODULE_AV2
|
||||
(
|
||||
chm_spamfilter,
|
||||
modinit,
|
||||
modfini,
|
||||
NULL,
|
||||
hlist,
|
||||
hfnlist,
|
||||
NULL,
|
||||
NULL,
|
||||
chm_spamfilter_desc
|
||||
);
|
|
@ -1,47 +0,0 @@
|
|||
using namespace ircd;
|
||||
|
||||
static const char chm_sslonly_desc[] =
|
||||
"Adds channel mode +S that bans non-SSL users from joing a channel";
|
||||
|
||||
static void h_can_join(hook_data_channel *);
|
||||
|
||||
mapi_hfn_list_av1 sslonly_hfnlist[] = {
|
||||
{ "can_join", (hookfn) h_can_join },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static chan::mode::type mymode;
|
||||
|
||||
static int
|
||||
_modinit(void)
|
||||
{
|
||||
using namespace chan::mode;
|
||||
|
||||
mymode = add('S', category::D, functor::simple);
|
||||
if (mymode == 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_moddeinit(void)
|
||||
{
|
||||
chan::mode::orphan('S');
|
||||
}
|
||||
|
||||
DECLARE_MODULE_AV2(chm_sslonly, _modinit, _moddeinit, NULL, NULL, sslonly_hfnlist, NULL, NULL, chm_sslonly_desc);
|
||||
|
||||
static void
|
||||
h_can_join(hook_data_channel *data)
|
||||
{
|
||||
client::client *source_p = data->client;
|
||||
const auto &chptr(data->chptr);
|
||||
|
||||
if((chptr->mode.mode & mymode) && !is(*source_p, umode::SSLCLIENT)) {
|
||||
/* XXX This is equal to ERR_THROTTLE */
|
||||
sendto_one_numeric(source_p, 480, "%s :Cannot join channel (+S) - SSL/TLS required", chptr->name.c_str());
|
||||
data->approved = chan::mode::ERR_CUSTOM;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
* Treat cmode +-S as +-b $~z.
|
||||
*/
|
||||
|
||||
using namespace ircd::chan::mode;
|
||||
using namespace ircd;
|
||||
|
||||
static const char chm_sslonly_compat_desc[] =
|
||||
"Adds an emulated channel mode +S which is converted into mode +b $~z";
|
||||
|
||||
static int _modinit(void);
|
||||
static void _moddeinit(void);
|
||||
static void chm_sslonly(client::client *source_p, chan::chan *chptr,
|
||||
int alevel, int parc, int *parn,
|
||||
const char **parv, int *errors, int dir, char c, type type);
|
||||
|
||||
DECLARE_MODULE_AV2(chm_sslonly_compat, _modinit, _moddeinit, NULL, NULL, NULL, NULL, NULL, chm_sslonly_compat_desc);
|
||||
|
||||
static int
|
||||
_modinit(void)
|
||||
{
|
||||
table['S'].type = type(0);
|
||||
table['S'].set_func = chm_sslonly;
|
||||
table['S'].category = category::D;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_moddeinit(void)
|
||||
{
|
||||
table['S'].type = type(0);
|
||||
table['S'].category = category(0);
|
||||
table['S'].set_func = functor::nosuch;
|
||||
}
|
||||
|
||||
static void
|
||||
chm_sslonly(client::client *source_p, chan::chan *chptr,
|
||||
int alevel, int parc, int *parn,
|
||||
const char **parv, int *errors, int dir, char c, type type)
|
||||
{
|
||||
int newparn = 0;
|
||||
const char *newparv[] = { "$~z" };
|
||||
|
||||
if (my(*source_p))
|
||||
functor::ban(source_p, chptr, alevel, 1, &newparn, newparv, errors, dir, 'b', BAN);
|
||||
else
|
||||
functor::nosuch(source_p, chptr, alevel, parc, parn, parv, errors, dir, c, type);
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/*
|
||||
* This module restricts channel creation to authenticated users
|
||||
* and IRC operators only. This module could be useful for
|
||||
* running private chat systems, or if a network gets droneflood
|
||||
* problems. It will return ERR_NEEDREGGEDNICK on failure.
|
||||
* -- nenolod
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char restrict_desc[] = "Restricts channel creation to authenticated users and IRC operators only";
|
||||
|
||||
static void h_can_create_channel_authenticated(hook_data_client_approval *);
|
||||
|
||||
mapi_hfn_list_av1 restrict_hfnlist[] = {
|
||||
{ "can_create_channel", (hookfn) h_can_create_channel_authenticated },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
DECLARE_MODULE_AV2(createauthonly, NULL, NULL, NULL, NULL, restrict_hfnlist, NULL, NULL, restrict_desc);
|
||||
|
||||
static void
|
||||
h_can_create_channel_authenticated(hook_data_client_approval *data)
|
||||
{
|
||||
client::client *source_p = data->client;
|
||||
|
||||
if (suser(user(*source_p)).empty() && !is(*source_p, umode::OPER))
|
||||
data->approved = ERR_NEEDREGGEDNICK;
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* This module restricts channel creation to opered up users
|
||||
* only. This module could be useful for running private chat
|
||||
* systems, or if a network gets droneflood problems. It will
|
||||
* return ERR_NEEDREGGEDNICK on failure.
|
||||
* -- nenolod
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char restrict_desc[] = "Restricts channel creation to IRC operators";
|
||||
|
||||
static void h_can_create_channel_authenticated(hook_data_client_approval *);
|
||||
|
||||
mapi_hfn_list_av1 restrict_hfnlist[] = {
|
||||
{ "can_create_channel", (hookfn) h_can_create_channel_authenticated },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
DECLARE_MODULE_AV2(createoperonly, NULL, NULL, NULL, NULL, restrict_hfnlist, NULL, NULL, restrict_desc);
|
||||
|
||||
static void
|
||||
h_can_create_channel_authenticated(hook_data_client_approval *data)
|
||||
{
|
||||
client::client *source_p = data->client;
|
||||
|
||||
if (!is(*source_p, umode::OPER))
|
||||
{
|
||||
sendto_one_notice(source_p, ":*** Channel creation is restricted to network staff only.");
|
||||
data->approved = ERR_NEEDREGGEDNICK;
|
||||
}
|
||||
}
|
|
@ -1,271 +0,0 @@
|
|||
/************************************************************************
|
||||
* IRC - Internet Relay Chat, doc/example_module.c
|
||||
* Copyright (C) 2001 Hybrid 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/* List of ircd includes from ../include/ */
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
/* This string describes the module. Always declare it a static const char[].
|
||||
* It is preferred for stylistic reasons to put it first.
|
||||
*
|
||||
* Make it short, sweet, and to the point.
|
||||
*/
|
||||
static const char example_desc[] = "This is an example Charybdis module.";
|
||||
|
||||
/* Declare the void's initially up here, as modules dont have an
|
||||
* include file, we will normally have client_p, source_p, parc
|
||||
* and parv[] where:
|
||||
*
|
||||
* client_p == client issuing command
|
||||
* source_p == where the command came from
|
||||
* parc == the number of parameters
|
||||
* parv == an array of the parameters
|
||||
*/
|
||||
|
||||
static void munreg_test(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[]);
|
||||
static void mclient_test(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[]);
|
||||
static void mserver_test(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[]);
|
||||
static void mrclient_test(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[]);
|
||||
static void moper_test(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[]);
|
||||
|
||||
/* Show the commands this module can handle in a msgtab
|
||||
* and give the msgtab a name, here its test_msgtab
|
||||
*/
|
||||
|
||||
struct Message test_msgtab = {
|
||||
"TEST", /* the /COMMAND you want */
|
||||
0, /* SET TO ZERO -- number of times command used by clients */
|
||||
0, /* SET TO ZERO -- number of times command used by clients */
|
||||
0, /* SET TO ZERO -- number of times command used by clients */
|
||||
0, /* ALWAYS SET TO 0 */
|
||||
|
||||
/* the functions to call for each handler. If not using the generic
|
||||
* handlers, the first param is the function to call, the second is the
|
||||
* required number of parameters. NOTE: If you specify a min para of 2,
|
||||
* then parv[1] must *also* be non-empty.
|
||||
*/
|
||||
{
|
||||
{munreg_test, 0}, /* function call for unregistered clients, 0 parms required */
|
||||
{mclient_test, 0}, /* function call for local clients, 0 parms required */
|
||||
{mrclient_test, 0}, /* function call for remote clients, 0 parms required */
|
||||
{mserver_test, 0}, /* function call for servers, 0 parms required */
|
||||
mg_ignore, /* function call for ENCAP, unused in this test */
|
||||
{moper_test, 0} /* function call for operators, 0 parms required */
|
||||
}
|
||||
};
|
||||
/*
|
||||
* There are also some macros for the above function calls and parameter counts.
|
||||
* Here's a list:
|
||||
*
|
||||
* mg_ignore: ignore the command when it comes from certain types
|
||||
* mg_not_oper: tell the client it requires being an operator
|
||||
* mg_reg: prevent the client using this if registered
|
||||
* mg_unreg: prevent the client using this if unregistered
|
||||
*
|
||||
* These macros assume a parameter count of zero; you do not set it.
|
||||
* For further details, see include/msg.h
|
||||
*/
|
||||
|
||||
|
||||
/* The mapi_clist_av1 indicates which commands (struct Message)
|
||||
* should be loaded from the module. The list should be terminated
|
||||
* by a NULL.
|
||||
*/
|
||||
mapi_clist_av1 test_clist[] = { &test_msgtab, NULL };
|
||||
|
||||
/* The mapi_hlist_av1 indicates which hook functions we need to be able to
|
||||
* call. We need to declare an integer, then add the name of the hook
|
||||
* function to call and a pointer to this integer. The list should be
|
||||
* terminated with NULLs.
|
||||
*/
|
||||
int doing_example_hook;
|
||||
mapi_hlist_av1 test_hlist[] = {
|
||||
{ "doing_example_hook", &doing_example_hook, },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
/* The mapi_hfn_list_av1 declares the hook functions which other modules can
|
||||
* call. The first parameter is the name of the hook, the second is a void
|
||||
* returning function, with arbitrary parameters casted to (hookfn). This
|
||||
* list must be terminated with NULLs.
|
||||
*/
|
||||
static void show_example_hook(void *unused);
|
||||
|
||||
mapi_hfn_list_av1 test_hfnlist[] = {
|
||||
{ "doing_example_hook", (hookfn) show_example_hook },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
/* The mapi_cap_list_av2 declares the capabilities this module adds. This is
|
||||
* for protocol usage. Here we declare both server and client capabilities.
|
||||
* The first parameter is the cap type (server or client). The second is the
|
||||
* name of the capability we wish to register. The third is the data attached
|
||||
* to the cap (typically NULL). The last parameter is a pointer to an integer
|
||||
* for the CAP index (recommended).
|
||||
*/
|
||||
unsigned int CAP_TESTCAP_SERVER, CAP_TESTCAP_CLIENT;
|
||||
mapi_cap_list_av2 test_cap_list[] = {
|
||||
{ MAPI_CAP_SERVER, "TESTCAP", NULL, &CAP_TESTCAP_SERVER },
|
||||
{ MAPI_CAP_CLIENT, "testcap", NULL, &CAP_TESTCAP_CLIENT },
|
||||
{ 0, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
/* Here we tell it what to do when the module is loaded */
|
||||
static int
|
||||
modinit(void)
|
||||
{
|
||||
/* Nothing to do for the example module. */
|
||||
/* The init function should return -1 on failure,
|
||||
which will cause the module to be unloaded,
|
||||
otherwise 0 to indicate success. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* here we tell it what to do when the module is unloaded */
|
||||
static void
|
||||
moddeinit(void)
|
||||
{
|
||||
/* Again, nothing to do. */
|
||||
}
|
||||
|
||||
/* DECLARE_MODULE_AV2() actually declare the MAPI header. */
|
||||
DECLARE_MODULE_AV2(
|
||||
/* The first argument is the name */
|
||||
example,
|
||||
/* The second argument is the function to call on load */
|
||||
modinit,
|
||||
/* And the function to call on unload */
|
||||
moddeinit,
|
||||
/* Then the MAPI command list */
|
||||
test_clist,
|
||||
/* Next the hook list, if we have one. */
|
||||
test_hlist,
|
||||
/* Then the hook function list, if we have one */
|
||||
test_hfnlist,
|
||||
/* Then the caps list, if we have one */
|
||||
test_cap_list,
|
||||
/* Then the version number of this module (NULL for bundled) */
|
||||
NULL,
|
||||
/* And finally, the description of this module */
|
||||
example_desc);
|
||||
|
||||
/* Any of the above arguments can be NULL to indicate they aren't used. */
|
||||
|
||||
/*
|
||||
* mr_test
|
||||
* parv[1] = parameter
|
||||
*/
|
||||
|
||||
/* Here we have the functions themselves that we declared above,
|
||||
* and the fairly normal C coding
|
||||
*/
|
||||
static void
|
||||
munreg_test(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[])
|
||||
{
|
||||
if(parc < 2)
|
||||
{
|
||||
sendto_one_notice(&source, ":You are unregistered and sent no parameters");
|
||||
}
|
||||
else
|
||||
{
|
||||
sendto_one_notice(&source, ":You are unregistered and sent parameter: %s", parv[1]);
|
||||
}
|
||||
|
||||
/* illustration of how to call a hook function */
|
||||
call_hook(doing_example_hook, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* mclient_test
|
||||
* parv[1] = parameter
|
||||
*/
|
||||
static void
|
||||
mclient_test(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[])
|
||||
{
|
||||
if(parc < 2)
|
||||
{
|
||||
sendto_one_notice(&source, ":You are a normal user, and sent no parameters");
|
||||
}
|
||||
else
|
||||
{
|
||||
sendto_one_notice(&source, ":You are a normal user, and send parameters: %s", parv[1]);
|
||||
}
|
||||
|
||||
/* illustration of how to call a hook function */
|
||||
call_hook(doing_example_hook, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* mrclient_test
|
||||
* parv[1] = parameter
|
||||
*/
|
||||
static void
|
||||
mrclient_test(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[])
|
||||
{
|
||||
if(parc < 2)
|
||||
{
|
||||
sendto_one_notice(&source, ":You are a remote client, and sent no parameters");
|
||||
}
|
||||
else
|
||||
{
|
||||
sendto_one_notice(&source, ":You are a remote client, and sent parameters: %s", parv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* mserver_test
|
||||
* parv[1] = parameter
|
||||
*/
|
||||
static void
|
||||
mserver_test(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[])
|
||||
{
|
||||
if(parc < 2)
|
||||
{
|
||||
sendto_one_notice(&source, ":You are a server, and sent no parameters");
|
||||
}
|
||||
else
|
||||
{
|
||||
sendto_one_notice(&source, ":You are a server, and sent parameters: %s", parv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* moper_test
|
||||
* parv[1] = parameter
|
||||
*/
|
||||
static void
|
||||
moper_test(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[])
|
||||
{
|
||||
if(parc < 2)
|
||||
{
|
||||
sendto_one_notice(&source, ":You are an operator, and sent no parameters");
|
||||
}
|
||||
else
|
||||
{
|
||||
sendto_one_notice(&source, ":You are an operator, and sent parameters: %s", parv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
show_example_hook(void *unused)
|
||||
{
|
||||
sendto_realops_snomask(sno::GENERAL, L_ALL, "Called example hook!");
|
||||
}
|
||||
|
||||
/* END OF EXAMPLE MODULE */
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* Account extban type: bans all users with any/matching account
|
||||
* -- jilles
|
||||
*/
|
||||
|
||||
namespace mode = ircd::chan::mode;
|
||||
namespace ext = mode::ext;
|
||||
using namespace ircd;
|
||||
|
||||
static const char extb_desc[] = "Account ($a) extban type";
|
||||
|
||||
static int _modinit(void);
|
||||
static void _moddeinit(void);
|
||||
static int eb_account(const char *data, client::client *client_p, chan::chan *chptr, mode::type);
|
||||
|
||||
DECLARE_MODULE_AV2(extb_account, _modinit, _moddeinit, NULL, NULL, NULL, NULL, NULL, extb_desc);
|
||||
|
||||
static int
|
||||
_modinit(void)
|
||||
{
|
||||
ext::table['a'] = eb_account;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_moddeinit(void)
|
||||
{
|
||||
ext::table['a'] = NULL;
|
||||
}
|
||||
|
||||
static int eb_account(const char *data, client::client *client_p,
|
||||
chan::chan *chptr, mode::type type)
|
||||
{
|
||||
using namespace ext;
|
||||
|
||||
(void)chptr;
|
||||
/* $a alone matches any logged in user */
|
||||
if (data == NULL)
|
||||
return suser(user(*client_p)).empty()? NOMATCH : MATCH;
|
||||
/* $a:MASK matches users logged in under matching account */
|
||||
return match(data, suser(user(*client_p))) ? MATCH : NOMATCH;
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* Canjoin extban type: matches users who are or are not banned from a
|
||||
* specified channel.
|
||||
* -- nenolod/jilles
|
||||
*/
|
||||
|
||||
namespace mode = ircd::chan::mode;
|
||||
namespace ext = mode::ext;
|
||||
using namespace ircd;
|
||||
|
||||
static const char extb_desc[] = "Can join ($j) extban type - matches users who are or are not banned from a specified channel";
|
||||
|
||||
static int _modinit(void);
|
||||
static void _moddeinit(void);
|
||||
static int eb_canjoin(const char *data, client::client *client_p, chan::chan *chptr, mode::type type);
|
||||
|
||||
DECLARE_MODULE_AV2(extb_canjoin, _modinit, _moddeinit, NULL, NULL, NULL, NULL, NULL, extb_desc);
|
||||
|
||||
static int
|
||||
_modinit(void)
|
||||
{
|
||||
ext::table['j'] = eb_canjoin;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_moddeinit(void)
|
||||
{
|
||||
ext::table['j'] = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
eb_canjoin(const char *data, client::client *client_p, chan::chan *chptr, mode::type type)
|
||||
{
|
||||
using namespace ext;
|
||||
|
||||
chan::chan *chptr2;
|
||||
int ret;
|
||||
static int recurse = 0;
|
||||
|
||||
/* don't process a $j in a $j'ed list */
|
||||
if (recurse)
|
||||
return INVALID;
|
||||
if (data == NULL)
|
||||
return INVALID;
|
||||
chptr2 = chan::get(data, std::nothrow);
|
||||
/* must exist, and no point doing this with the same channel */
|
||||
if (chptr2 == NULL || chptr2 == chptr)
|
||||
return INVALID;
|
||||
/* require consistent target */
|
||||
if (chptr->name[0] == '#' && data[0] == '&')
|
||||
return INVALID;
|
||||
/* this allows getting some information about ban exceptions
|
||||
* but +s/+p doesn't seem the right criterion */
|
||||
#if 0
|
||||
/* privacy! don't allow +s/+p channels to influence another channel */
|
||||
if (!PubChannel(chptr2))
|
||||
return INVALID;
|
||||
#endif
|
||||
recurse = 1;
|
||||
ret = check(*chptr2, mode::BAN, *client_p)? MATCH : NOMATCH;
|
||||
recurse = 0;
|
||||
return ret;
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
* Channel extban type: matches users who are in a certain public channel
|
||||
* -- jilles
|
||||
*/
|
||||
|
||||
namespace mode = ircd::chan::mode;
|
||||
namespace ext = mode::ext;
|
||||
using namespace ircd;
|
||||
|
||||
static const char extb_desc[] = "Channel ($c) extban type";
|
||||
|
||||
static int _modinit(void);
|
||||
static void _moddeinit(void);
|
||||
static int eb_channel(const char *data, client::client *client_p, chan::chan *chptr, mode::type type);
|
||||
|
||||
DECLARE_MODULE_AV2(extb_channel, _modinit, _moddeinit, NULL, NULL, NULL, NULL, NULL, extb_desc);
|
||||
|
||||
static int
|
||||
_modinit(void)
|
||||
{
|
||||
ext::table['c'] = eb_channel;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_moddeinit(void)
|
||||
{
|
||||
ext::table['c'] = NULL;
|
||||
}
|
||||
|
||||
static int eb_channel(const char *data, client::client *client_p,
|
||||
chan::chan *chptr, mode::type type)
|
||||
{
|
||||
using namespace ext;
|
||||
|
||||
chan::chan *chptr2;
|
||||
|
||||
(void)chptr;
|
||||
|
||||
if (data == NULL)
|
||||
return INVALID;
|
||||
|
||||
chptr2 = chan::get(data, std::nothrow);
|
||||
if (chptr2 == NULL)
|
||||
return INVALID;
|
||||
/* require consistent target */
|
||||
if (chptr->name[0] == '#' && data[0] == '&')
|
||||
return INVALID;
|
||||
/* privacy! don't allow +s/+p channels to influence another channel */
|
||||
if (!is_public(chptr2) && chptr2 != chptr)
|
||||
return INVALID;
|
||||
|
||||
return is_member(chptr2, client_p)? MATCH : NOMATCH;
|
||||
}
|
|
@ -1,272 +0,0 @@
|
|||
/*
|
||||
* Extban that combines other extbans.
|
||||
*
|
||||
* Basic example:
|
||||
* $&:~a,m:*!*@gateway/web/cgi-irc*
|
||||
* Which means: match unidentified webchat users.
|
||||
* ("m" is another new extban type, which just does a normal match).
|
||||
*
|
||||
* More complicated example:
|
||||
* $&:~a,|:(m:*!*@gateway/web/foo,m:*!*@gateway/web/bar)
|
||||
* Which means: unidentified and using the foo or bar gateway.
|
||||
*
|
||||
* Rules:
|
||||
*
|
||||
* - Optional pair of parens around data.
|
||||
*
|
||||
* - component bans are separated by commas, but commas between
|
||||
* matching pairs of parens are skipped.
|
||||
*
|
||||
* - Unbalanced parens are an error.
|
||||
*
|
||||
* - Parens, commas and backslashes can be escaped by backslashes.
|
||||
*
|
||||
* - A backslash before any character other than a paren or backslash
|
||||
* is just a backslash (backslash and character are both used).
|
||||
*
|
||||
* - Non-existant extbans are invalid.
|
||||
* This is primarily for consistency with non-combined bans:
|
||||
* the ircd does not let you set +b $f unless the 'f' extban is loaded,
|
||||
* so setting $&:f should be impossible too.
|
||||
*
|
||||
* Issues:
|
||||
* - Backslashes double inside nested bans.
|
||||
* Hopefully acceptable because they should be rare.
|
||||
*
|
||||
* - Is performance good enough?
|
||||
* I suspect it is, but have done no load testing.
|
||||
*/
|
||||
|
||||
namespace mode = ircd::chan::mode;
|
||||
namespace ext = mode::ext;
|
||||
using namespace ircd;
|
||||
|
||||
static const char extb_desc[] = "Combination ($&, $|) extban types";
|
||||
|
||||
// #define MOD_DEBUG(s) sendto_realops_snomask(sno::DEBUG, L_NETWIDE, (s))
|
||||
#define MOD_DEBUG(s)
|
||||
#define RETURN_INVALID { recursion_depth--; return INVALID; }
|
||||
|
||||
static int _modinit(void);
|
||||
static void _moddeinit(void);
|
||||
static int eb_or(const char *data, client::client *client_p, chan::chan *chptr, mode::type);
|
||||
static int eb_and(const char *data, client::client *client_p, chan::chan *chptr, mode::type);
|
||||
static int eb_combi(const char *data, client::client *client_p, chan::chan *chptr, mode::type, bool is_and);
|
||||
static int recursion_depth = 0;
|
||||
|
||||
DECLARE_MODULE_AV2(extb_extended, _modinit, _moddeinit, NULL, NULL, NULL, NULL, NULL, extb_desc);
|
||||
|
||||
static int
|
||||
_modinit(void)
|
||||
{
|
||||
ext::table['&'] = eb_and;
|
||||
ext::table['|'] = eb_or;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_moddeinit(void)
|
||||
{
|
||||
ext::table['&'] = NULL;
|
||||
ext::table['|'] = NULL;
|
||||
}
|
||||
|
||||
static int eb_or(const char *data, client::client *client_p,
|
||||
chan::chan *chptr, mode::type type)
|
||||
{
|
||||
return eb_combi(data, client_p, chptr, type, false);
|
||||
}
|
||||
|
||||
static int eb_and(const char *data, client::client *client_p,
|
||||
chan::chan *chptr, mode::type type)
|
||||
{
|
||||
return eb_combi(data, client_p, chptr, type, true);
|
||||
}
|
||||
|
||||
static int eb_combi(const char *data, client::client *client_p,
|
||||
chan::chan *chptr, mode::type type, bool is_and)
|
||||
{
|
||||
using namespace ext;
|
||||
|
||||
const char *p, *banend;
|
||||
bool have_result = false;
|
||||
int allowed_nodes = 11;
|
||||
size_t datalen;
|
||||
|
||||
if (recursion_depth >= 5) {
|
||||
MOD_DEBUG("combo invalid: recursion depth too high");
|
||||
return INVALID;
|
||||
}
|
||||
|
||||
if (EmptyString(data)) {
|
||||
MOD_DEBUG("combo invalid: empty data");
|
||||
return INVALID;
|
||||
}
|
||||
|
||||
datalen = strlen(data);
|
||||
if (datalen > chan::ban::LEN) {
|
||||
/* I'd be sad if this ever happened, but if it does we
|
||||
* could overflow the buffer used below, so...
|
||||
*/
|
||||
MOD_DEBUG("combo invalid: > BANLEN");
|
||||
return INVALID;
|
||||
}
|
||||
banend = data + datalen;
|
||||
|
||||
if (data[0] == '(') {
|
||||
p = data + 1;
|
||||
banend--;
|
||||
if (*banend != ')') {
|
||||
MOD_DEBUG("combo invalid: starting but no closing paren");
|
||||
return INVALID;
|
||||
}
|
||||
} else {
|
||||
p = data;
|
||||
}
|
||||
|
||||
/* Empty combibans are invalid. */
|
||||
if (banend == p) {
|
||||
MOD_DEBUG("combo invalid: no data (after removing parens)");
|
||||
return INVALID;
|
||||
}
|
||||
|
||||
/* Implementation note:
|
||||
* I want it to be impossible to set a syntactically invalid combi-ban.
|
||||
* (mismatched parens).
|
||||
* That is: valid_extban should return false for those.
|
||||
* Ideally we do not parse the entire ban when actually matching it:
|
||||
* we can just short-circuit if we already know the ban is valid.
|
||||
* Unfortunately there is no separate hook or mode_type for validation,
|
||||
* so we always keep parsing even after we have determined a result.
|
||||
*/
|
||||
|
||||
recursion_depth++;
|
||||
|
||||
while (--allowed_nodes) {
|
||||
bool invert = false;
|
||||
char *child_data, child_data_buf[chan::ban::LEN];
|
||||
ext::func f;
|
||||
|
||||
if (*p == '~') {
|
||||
invert = true;
|
||||
p++;
|
||||
if (p == banend) {
|
||||
MOD_DEBUG("combo invalid: no data after ~");
|
||||
RETURN_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
f = ext::table[uint8_t(*p++)];
|
||||
if (!f) {
|
||||
MOD_DEBUG("combo invalid: non-existant child extban");
|
||||
RETURN_INVALID;
|
||||
}
|
||||
|
||||
if (*p == ':') {
|
||||
unsigned int parencount = 0;
|
||||
bool escaped = false, done = false;
|
||||
char *o;
|
||||
|
||||
p++;
|
||||
|
||||
/* Possible optimization: we can skip the actual copy if
|
||||
* we already have_result.
|
||||
*/
|
||||
o = child_data = child_data_buf;
|
||||
while (true) {
|
||||
if (p == banend) {
|
||||
if (parencount) {
|
||||
MOD_DEBUG("combo invalid: EOD while in parens");
|
||||
RETURN_INVALID;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (escaped) {
|
||||
if (*p != '(' && *p != ')' && *p != '\\' && *p != ',')
|
||||
*o++ = '\\';
|
||||
*o++ = *p++;
|
||||
escaped = false;
|
||||
} else {
|
||||
switch (*p) {
|
||||
case '\\':
|
||||
escaped = true;
|
||||
break;
|
||||
case '(':
|
||||
parencount++;
|
||||
*o++ = *p;
|
||||
break;
|
||||
case ')':
|
||||
if (!parencount) {
|
||||
MOD_DEBUG("combo invalid: negative parencount");
|
||||
RETURN_INVALID;
|
||||
}
|
||||
parencount--;
|
||||
*o++ = *p;
|
||||
break;
|
||||
case ',':
|
||||
if (parencount)
|
||||
*o++ = *p;
|
||||
else
|
||||
done = true;
|
||||
break;
|
||||
default:
|
||||
*o++ = *p;
|
||||
break;
|
||||
}
|
||||
if (done)
|
||||
break;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
*o = '\0';
|
||||
} else {
|
||||
child_data = NULL;
|
||||
}
|
||||
|
||||
if (!have_result) {
|
||||
int child_result = f(child_data, client_p, chptr, type);
|
||||
|
||||
if (child_result == INVALID) {
|
||||
MOD_DEBUG("combo invalid: child invalid");
|
||||
RETURN_INVALID;
|
||||
}
|
||||
|
||||
/* Convert child_result to a plain boolean result */
|
||||
if (invert)
|
||||
child_result = child_result == NOMATCH;
|
||||
else
|
||||
child_result = child_result == MATCH;
|
||||
|
||||
if (is_and ? !child_result : child_result)
|
||||
have_result = true;
|
||||
}
|
||||
|
||||
if (p == banend)
|
||||
break;
|
||||
|
||||
if (*p++ != ',') {
|
||||
MOD_DEBUG("combo invalid: no ',' after ban");
|
||||
RETURN_INVALID;
|
||||
}
|
||||
|
||||
if (p == banend) {
|
||||
MOD_DEBUG("combo invalid: banend after ','");
|
||||
RETURN_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
/* at this point, *p should == banend */
|
||||
if (p != banend) {
|
||||
MOD_DEBUG("combo invalid: more child extbans than allowed");
|
||||
RETURN_INVALID;
|
||||
}
|
||||
|
||||
recursion_depth--;
|
||||
|
||||
if (is_and)
|
||||
return have_result ? NOMATCH : MATCH;
|
||||
else
|
||||
return have_result ? MATCH : NOMATCH;
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
/*
|
||||
* Extended extban type: bans all users with matching nick!user@host#gecos.
|
||||
* Requested by Lockwood.
|
||||
* - nenolod
|
||||
*/
|
||||
|
||||
namespace mode = ircd::chan::mode;
|
||||
namespace ext = mode::ext;
|
||||
using namespace ircd;
|
||||
|
||||
static const char extb_desc[] = "Extended mask ($x) extban type";
|
||||
|
||||
static int _modinit(void);
|
||||
static void _moddeinit(void);
|
||||
static int eb_extended(const char *data, client::client *client_p, chan::chan *chptr, mode::type);
|
||||
|
||||
DECLARE_MODULE_AV2(extb_extended, _modinit, _moddeinit, NULL, NULL, NULL, NULL, NULL, extb_desc);
|
||||
|
||||
static int
|
||||
_modinit(void)
|
||||
{
|
||||
ext::table['x'] = eb_extended;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_moddeinit(void)
|
||||
{
|
||||
ext::table['x'] = NULL;
|
||||
}
|
||||
|
||||
static int eb_extended(const char *data, client::client *client_p,
|
||||
chan::chan *chptr, mode::type type)
|
||||
{
|
||||
using namespace ext;
|
||||
|
||||
char buf[BUFSIZE];
|
||||
int ret;
|
||||
|
||||
(void)chptr;
|
||||
|
||||
if (data == NULL)
|
||||
return INVALID;
|
||||
|
||||
snprintf(buf, BUFSIZE, "%s!%s@%s#%s",
|
||||
client_p->name, client_p->username, client_p->host, client_p->info);
|
||||
|
||||
ret = match(data, buf) ? MATCH : NOMATCH;
|
||||
|
||||
if (ret == NOMATCH && is_dyn_spoof(*client_p))
|
||||
{
|
||||
snprintf(buf, BUFSIZE, "%s!%s@%s#%s",
|
||||
client_p->name, client_p->username, client_p->orighost, client_p->info);
|
||||
|
||||
ret = match(data, buf) ? MATCH : NOMATCH;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
/*
|
||||
* Hostmask extban type: bans all users matching a given hostmask, used for stacked extbans
|
||||
* -- kaniini
|
||||
*/
|
||||
|
||||
namespace mode = ircd::chan::mode;
|
||||
namespace ext = mode::ext;
|
||||
using namespace ircd;
|
||||
|
||||
static const char extb_desc[] = "Hostmask ($m) extban type";
|
||||
|
||||
static int _modinit(void);
|
||||
static void _moddeinit(void);
|
||||
static int eb_hostmask(const char *data, client::client *client_p, chan::chan *chptr, mode::type);
|
||||
|
||||
DECLARE_MODULE_AV2(extb_hostmask, _modinit, _moddeinit, NULL, NULL, NULL, NULL, NULL, extb_desc);
|
||||
|
||||
static int
|
||||
_modinit(void)
|
||||
{
|
||||
ext::table['m'] = eb_hostmask;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_moddeinit(void)
|
||||
{
|
||||
ext::table['m'] = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
eb_hostmask(const char *banstr, client::client *client_p, chan::chan *chptr, mode::type type)
|
||||
{
|
||||
using namespace ext;
|
||||
|
||||
char src_host[NICKLEN + USERLEN + HOSTLEN + 6];
|
||||
char src_iphost[NICKLEN + USERLEN + HOSTLEN + 6];
|
||||
char src_althost[NICKLEN + USERLEN + HOSTLEN + 6];
|
||||
char src_ip4host[NICKLEN + USERLEN + HOSTLEN + 6];
|
||||
struct sockaddr_in ip4;
|
||||
char *s = src_host, *s2 = src_iphost, *s3 = NULL, *s4 = NULL;
|
||||
|
||||
sprintf(src_host, "%s!%s@%s", client_p->name, client_p->username, client_p->host);
|
||||
sprintf(src_iphost, "%s!%s@%s", client_p->name, client_p->username, client_p->sockhost);
|
||||
|
||||
/* handle hostmangling if necessary */
|
||||
if (client_p->localClient->mangledhost != NULL)
|
||||
{
|
||||
if (!strcmp(client_p->host, client_p->localClient->mangledhost))
|
||||
sprintf(src_althost, "%s!%s@%s", client_p->name, client_p->username, client_p->orighost);
|
||||
else if (!is_dyn_spoof(*client_p))
|
||||
sprintf(src_althost, "%s!%s@%s", client_p->name, client_p->username, client_p->localClient->mangledhost);
|
||||
|
||||
s3 = src_althost;
|
||||
}
|
||||
|
||||
#ifdef RB_IPV6
|
||||
/* handle Teredo if necessary */
|
||||
if (GET_SS_FAMILY(&client_p->localClient->ip) == AF_INET6 && rb_ipv4_from_ipv6((const struct sockaddr_in6 *) &client_p->localClient->ip, &ip4))
|
||||
{
|
||||
sprintf(src_ip4host, "%s!%s@", client_p->name, client_p->username);
|
||||
s4 = src_ip4host + strlen(src_ip4host);
|
||||
rb_inet_ntop_sock((struct sockaddr *)&ip4,
|
||||
s4, src_ip4host + sizeof src_ip4host - s4);
|
||||
s4 = src_ip4host;
|
||||
}
|
||||
#endif
|
||||
|
||||
return match(banstr, s) || match(banstr, s2) || (s3 != NULL && match(banstr, s3)) || (s4 != NULL && match(banstr, s4)) ? MATCH : NOMATCH;
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
* Oper extban type: matches opers
|
||||
* -- jilles
|
||||
*/
|
||||
|
||||
namespace mode = ircd::chan::mode;
|
||||
namespace ext = mode::ext;
|
||||
using namespace ircd;
|
||||
|
||||
static const char extb_desc[] = "Oper ($o) extban type";
|
||||
|
||||
static int _modinit(void);
|
||||
static void _moddeinit(void);
|
||||
static int eb_oper(const char *data, client::client *client_p, chan::chan *chptr, mode::type);
|
||||
|
||||
DECLARE_MODULE_AV2(extb_oper, _modinit, _moddeinit, NULL, NULL, NULL, NULL, NULL, extb_desc);
|
||||
|
||||
static int
|
||||
_modinit(void)
|
||||
{
|
||||
ext::table['o'] = eb_oper;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_moddeinit(void)
|
||||
{
|
||||
ext::table['o'] = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
eb_oper(const char *data, client::client *client_p, chan::chan *chptr, mode::type type)
|
||||
{
|
||||
using namespace ext;
|
||||
|
||||
if (data != NULL)
|
||||
{
|
||||
struct PrivilegeSet *set = privilegeset_get(data);
|
||||
if (set != NULL && client_p->localClient->privset == set)
|
||||
return MATCH;
|
||||
|
||||
/* $o:admin or whatever */
|
||||
return HasPrivilege(client_p, data) ? MATCH : NOMATCH;
|
||||
}
|
||||
|
||||
return is(*client_p, umode::OPER) ? MATCH : NOMATCH;
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* Realname extban type: bans all users with matching gecos
|
||||
* -- jilles
|
||||
*/
|
||||
|
||||
namespace mode = ircd::chan::mode;
|
||||
namespace ext = mode::ext;
|
||||
using namespace ircd;
|
||||
|
||||
static const char extb_desc[] = "Realname/GECOS ($r) extban type";
|
||||
|
||||
static int _modinit(void);
|
||||
static void _moddeinit(void);
|
||||
static int eb_realname(const char *data, client::client *client_p, chan::chan *chptr, mode::type);
|
||||
|
||||
DECLARE_MODULE_AV2(extb_realname, _modinit, _moddeinit, NULL, NULL, NULL, NULL, NULL, extb_desc);
|
||||
|
||||
static int
|
||||
_modinit(void)
|
||||
{
|
||||
ext::table['r'] = eb_realname;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_moddeinit(void)
|
||||
{
|
||||
ext::table['r'] = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
eb_realname(const char *data, client::client *client_p, chan::chan *chptr, mode::type type)
|
||||
{
|
||||
using namespace ext;
|
||||
using namespace mode;
|
||||
|
||||
/* This type is not safe for exceptions */
|
||||
if (type == EXCEPTION || type == INVEX)
|
||||
return INVALID;
|
||||
|
||||
if (data == NULL)
|
||||
return INVALID;
|
||||
|
||||
return match(data, client_p->info)? MATCH : NOMATCH;
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* Server name extban type: bans all users using a certain server
|
||||
* -- jilles
|
||||
*/
|
||||
|
||||
namespace mode = ircd::chan::mode;
|
||||
namespace ext = mode::ext;
|
||||
using namespace ircd;
|
||||
|
||||
static const char extb_desc[] = "Server ($s) extban type";
|
||||
|
||||
static int _modinit(void);
|
||||
static void _moddeinit(void);
|
||||
static int eb_server(const char *data, client::client *client_p, chan::chan *chptr, mode::type);
|
||||
|
||||
DECLARE_MODULE_AV2(extb_server, _modinit, _moddeinit, NULL, NULL, NULL, NULL, NULL, extb_desc);
|
||||
|
||||
static int
|
||||
_modinit(void)
|
||||
{
|
||||
ext::table['s'] = eb_server;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_moddeinit(void)
|
||||
{
|
||||
ext::table['s'] = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
eb_server(const char *data, client::client *client_p, chan::chan *chptr, mode::type type)
|
||||
{
|
||||
using namespace ext;
|
||||
using namespace mode;
|
||||
|
||||
/* This type is not safe for exceptions */
|
||||
if (type == EXCEPTION || type == INVEX)
|
||||
return INVALID;
|
||||
|
||||
if (data == NULL)
|
||||
return INVALID;
|
||||
|
||||
return match(data, me.name)? MATCH : NOMATCH;
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
/* SSL extban type: matches ssl users */
|
||||
|
||||
namespace mode = ircd::chan::mode;
|
||||
namespace ext = mode::ext;
|
||||
using namespace ircd;
|
||||
|
||||
static const char extb_desc[] = "SSL/TLS ($z) extban type";
|
||||
|
||||
static int _modinit(void);
|
||||
static void _moddeinit(void);
|
||||
static int eb_ssl(const char *data, client::client *client_p, chan::chan *chptr, mode::type);
|
||||
|
||||
DECLARE_MODULE_AV2(extb_ssl, _modinit, _moddeinit, NULL, NULL, NULL, NULL, NULL, extb_desc);
|
||||
|
||||
static int
|
||||
_modinit(void)
|
||||
{
|
||||
ext::table['z'] = eb_ssl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_moddeinit(void)
|
||||
{
|
||||
ext::table['z'] = NULL;
|
||||
}
|
||||
|
||||
static int eb_ssl(const char *data, client::client *client_p,
|
||||
chan::chan *chptr, mode::type type)
|
||||
{
|
||||
using namespace ext;
|
||||
|
||||
(void)chptr;
|
||||
if (data != NULL)
|
||||
return INVALID;
|
||||
|
||||
return is(*client_p, umode::SSLCLIENT) ? MATCH : NOMATCH;
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
/*
|
||||
* Usermode extban type: bans all users with a specific usermode
|
||||
* -- nenolod
|
||||
*/
|
||||
|
||||
namespace mode = ircd::chan::mode;
|
||||
namespace ext = mode::ext;
|
||||
using namespace ircd;
|
||||
|
||||
static const char extb_desc[] = "Usermode ($m) extban type";
|
||||
|
||||
static int _modinit(void);
|
||||
static void _moddeinit(void);
|
||||
static int eb_usermode(const char *data, client::client *client_p, chan::chan *chptr, mode::type);
|
||||
|
||||
DECLARE_MODULE_AV2(extb_usermode, _modinit, _moddeinit, NULL, NULL, NULL, NULL, NULL, extb_desc);
|
||||
|
||||
static int
|
||||
_modinit(void)
|
||||
{
|
||||
ext::table['u'] = eb_usermode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_moddeinit(void)
|
||||
{
|
||||
ext::table['u'] = NULL;
|
||||
}
|
||||
|
||||
static int eb_usermode(const char *data, client::client *client_p,
|
||||
chan::chan *chptr, mode::type type)
|
||||
{
|
||||
using namespace ext;
|
||||
|
||||
int dir = MODE_ADD;
|
||||
unsigned int modes_ack = 0, modes_nak = 0;
|
||||
const char *p;
|
||||
|
||||
(void)chptr;
|
||||
|
||||
/* $m must have a specified mode */
|
||||
if (data == NULL)
|
||||
return INVALID;
|
||||
|
||||
for (p = data; *p != '\0'; p++)
|
||||
{
|
||||
switch (*p)
|
||||
{
|
||||
case '+':
|
||||
dir = MODE_ADD;
|
||||
break;
|
||||
case '-':
|
||||
dir = MODE_DEL;
|
||||
break;
|
||||
default:
|
||||
switch (dir)
|
||||
{
|
||||
case MODE_DEL:
|
||||
modes_nak |= umode::table[(unsigned char) *p];
|
||||
break;
|
||||
case MODE_ADD:
|
||||
default:
|
||||
modes_ack |= umode::table[(unsigned char) *p];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ((client_p->mode & modes_ack) == modes_ack &&
|
||||
!(client_p->mode & modes_nak)) ?
|
||||
MATCH : NOMATCH;
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
* Deny user to remove +i flag except they are irc operators
|
||||
*
|
||||
* Based off no_oper_invis.c by jilles
|
||||
*
|
||||
* Note that +i must be included in default_umodes
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char noi_desc[] =
|
||||
"Do not allow users to remove user mode +i unless they are operators";
|
||||
|
||||
static void h_noi_umode_changed(hook_data_umode_changed *);
|
||||
|
||||
mapi_hfn_list_av1 noi_hfnlist[] = {
|
||||
{ "umode_changed", (hookfn) h_noi_umode_changed },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
DECLARE_MODULE_AV2(force_user_invis, NULL, NULL, NULL, NULL, noi_hfnlist, NULL, NULL, noi_desc);
|
||||
|
||||
static void
|
||||
h_noi_umode_changed(hook_data_umode_changed *hdata)
|
||||
{
|
||||
client::client *source_p = hdata->client;
|
||||
|
||||
if (my(*source_p) && !is(*source_p, umode::OPER) && !is(*source_p, umode::INVISIBLE)) {
|
||||
set(*source_p, umode::INVISIBLE);
|
||||
}
|
||||
}
|
|
@ -1,183 +0,0 @@
|
|||
/*
|
||||
* Helpops system.
|
||||
* -- kaniini
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char helpops_desc[] = "The helpops system as used by freenode";
|
||||
|
||||
static rb_dlink_list helper_list = { NULL, NULL, 0 };
|
||||
static void h_hdl_stats_request(hook_data_int *hdata);
|
||||
static void h_hdl_new_remote_user(client::client *client_p);
|
||||
static void h_hdl_client_exit(hook_data_client_exit *hdata);
|
||||
static void h_hdl_umode_changed(hook_data_umode_changed *hdata);
|
||||
static void h_hdl_whois(hook_data_client *hdata);
|
||||
static void mo_dehelper(struct MsgBuf *, client::client &, client::client &, int, const char **);
|
||||
static void me_dehelper(struct MsgBuf *, client::client &, client::client &, int, const char **);
|
||||
static void do_dehelper(client::client &source, client::client &target_p);
|
||||
|
||||
mapi_hfn_list_av1 helpops_hfnlist[] = {
|
||||
{ "doing_stats", (hookfn) h_hdl_stats_request },
|
||||
{ "new_remote_user", (hookfn) h_hdl_new_remote_user },
|
||||
{ "client_exit", (hookfn) h_hdl_client_exit },
|
||||
{ "umode_changed", (hookfn) h_hdl_umode_changed },
|
||||
{ "doing_whois", (hookfn) h_hdl_whois },
|
||||
{ "doing_whois_global", (hookfn) h_hdl_whois },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
struct Message dehelper_msgtab = {
|
||||
"DEHELPER", 0, 0, 0, 0,
|
||||
{mg_unreg, mg_not_oper, mg_not_oper, mg_ignore, {me_dehelper, 2}, {mo_dehelper, 2}}
|
||||
};
|
||||
|
||||
mapi_clist_av1 helpops_clist[] = { &dehelper_msgtab, NULL };
|
||||
|
||||
umode::mode UMODE_HELPOPS { 'H' };
|
||||
|
||||
static void
|
||||
mo_dehelper(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char **parv)
|
||||
{
|
||||
client::client *target_p;
|
||||
|
||||
if (!IsOperAdmin(&source))
|
||||
{
|
||||
sendto_one(&source, form_str(ERR_NOPRIVS), me.name, source.name, "admin");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!(target_p = client::find_named_person(parv[1])))
|
||||
{
|
||||
sendto_one_numeric(&source, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), parv[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
if(my(*target_p))
|
||||
do_dehelper(source, *target_p);
|
||||
else
|
||||
sendto_one(target_p, ":%s ENCAP %s DEHELPER %s",
|
||||
use_id(&source), target_p->servptr->name, use_id(target_p));
|
||||
}
|
||||
|
||||
static void
|
||||
me_dehelper(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char **parv)
|
||||
{
|
||||
client::client *target_p = client::find_person(parv[1]);
|
||||
if(!target_p)
|
||||
{
|
||||
sendto_one_numeric(&source, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), parv[1]);
|
||||
return;
|
||||
}
|
||||
if(!my(*target_p))
|
||||
return;
|
||||
|
||||
do_dehelper(source, *target_p);
|
||||
}
|
||||
|
||||
static void
|
||||
do_dehelper(client::client &source, client::client &target)
|
||||
{
|
||||
const char *fakeparv[4];
|
||||
|
||||
if(!(target.mode & UMODE_HELPOPS))
|
||||
return;
|
||||
|
||||
sendto_realops_snomask(sno::GENERAL, L_NETWIDE, "%s is using DEHELPER on %s",
|
||||
source.name, target.name);
|
||||
sendto_one_notice(&target, ":*** %s is using DEHELPER on you", source.name);
|
||||
|
||||
fakeparv[0] = fakeparv[1] = target.name;
|
||||
fakeparv[2] = "-H";
|
||||
fakeparv[3] = NULL;
|
||||
user_mode(&target, &target, 3, fakeparv);
|
||||
}
|
||||
|
||||
static int
|
||||
_modinit(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
h_hdl_stats_request(hook_data_int *hdata)
|
||||
{
|
||||
client::client *target_p;
|
||||
rb_dlink_node *helper_ptr;
|
||||
unsigned int count = 0;
|
||||
|
||||
if (hdata->arg2 != 'p')
|
||||
return;
|
||||
|
||||
RB_DLINK_FOREACH (helper_ptr, helper_list.head)
|
||||
{
|
||||
target_p = (client::client *)helper_ptr->data;
|
||||
|
||||
if (away(user(*target_p)).size())
|
||||
continue;
|
||||
|
||||
count++;
|
||||
|
||||
sendto_one_numeric(hdata->client, RPL_STATSDEBUG,
|
||||
"p :%s (%s@%s)",
|
||||
target_p->name, target_p->username,
|
||||
target_p->host);
|
||||
}
|
||||
|
||||
sendto_one_numeric(hdata->client, RPL_STATSDEBUG,
|
||||
"p :%u staff members", count);
|
||||
|
||||
hdata->result = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
h_hdl_new_remote_user(client::client *client_p)
|
||||
{
|
||||
if (client_p->mode & UMODE_HELPOPS)
|
||||
rb_dlinkAddAlloc(client_p, &helper_list);
|
||||
}
|
||||
|
||||
static void
|
||||
h_hdl_client_exit(hook_data_client_exit *hdata)
|
||||
{
|
||||
if (hdata->target->mode & UMODE_HELPOPS)
|
||||
rb_dlinkFindDestroy(hdata->target, &helper_list);
|
||||
}
|
||||
|
||||
static void
|
||||
h_hdl_umode_changed(hook_data_umode_changed *hdata)
|
||||
{
|
||||
client::client &source = *hdata->client;
|
||||
|
||||
/* didn't change +H umode, we don't need to do anything */
|
||||
if (!((hdata->oldumodes ^ source.mode) & UMODE_HELPOPS))
|
||||
return;
|
||||
|
||||
if (source.mode & UMODE_HELPOPS)
|
||||
{
|
||||
if (my(source) && !HasPrivilege(&source, "usermode:helpops"))
|
||||
{
|
||||
source.mode &= ~UMODE_HELPOPS;
|
||||
sendto_one(&source, form_str(ERR_NOPRIVS), me.name, source.name, "usermode:helpops");
|
||||
return;
|
||||
}
|
||||
|
||||
rb_dlinkAddAlloc(&source, &helper_list);
|
||||
}
|
||||
else if (!(source.mode & UMODE_HELPOPS))
|
||||
rb_dlinkFindDestroy(&source, &helper_list);
|
||||
}
|
||||
|
||||
static void
|
||||
h_hdl_whois(hook_data_client *hdata)
|
||||
{
|
||||
client::client &source = *hdata->client;
|
||||
client::client *target_p = hdata->target;
|
||||
|
||||
if ((target_p->mode & UMODE_HELPOPS) && away(user(*target_p)).empty())
|
||||
{
|
||||
sendto_one_numeric(&source, RPL_WHOISHELPOP, form_str(RPL_WHOISHELPOP), target_p->name);
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_MODULE_AV2(helpops, _modinit, nullptr, helpops_clist, NULL, helpops_hfnlist, NULL, NULL, helpops_desc);
|
|
@ -1,23 +0,0 @@
|
|||
/*
|
||||
* Override WHOIS logic to hide channel memberships that are not common.
|
||||
* -- kaniini
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char hide_desc[] = "Hides channel memberships not shared";
|
||||
|
||||
static void h_huc_doing_whois_channel_visibility(hook_data_client *);
|
||||
|
||||
mapi_hfn_list_av1 huc_hfnlist[] = {
|
||||
{ "doing_whois_channel_visibility", (hookfn) h_huc_doing_whois_channel_visibility },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
DECLARE_MODULE_AV2(hide_uncommon_channels, NULL, NULL, NULL, NULL, huc_hfnlist, NULL, NULL, hide_desc);
|
||||
|
||||
static void
|
||||
h_huc_doing_whois_channel_visibility(hook_data_client *hdata)
|
||||
{
|
||||
hdata->approved = (is_public(hdata->chptr) && !is(*hdata->target, umode::INVISIBLE)) || is_member(hdata->chptr, hdata->client);
|
||||
}
|
|
@ -1,620 +0,0 @@
|
|||
/*
|
||||
* charybdis: an advanced Internet Relay Chat Daemon(ircd).
|
||||
*
|
||||
* Copyright (C) 2006 charybdis development team
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
/* {{{ Structures */
|
||||
#define HURT_CUTOFF (10) /* protocol messages. */
|
||||
#define HURT_DEFAULT_EXPIRE (7 * 24 * 60) /* minutes. */
|
||||
#define HURT_EXIT_REASON "Hurt: Failed to identify to services"
|
||||
|
||||
enum {
|
||||
HEAL_NICK = 0,
|
||||
HEAL_IP
|
||||
};
|
||||
|
||||
typedef struct _hurt_state {
|
||||
time_t start_time;
|
||||
uint32_t n_hurts;
|
||||
rb_dlink_list hurt_clients;
|
||||
uint16_t cutoff;
|
||||
time_t default_expire;
|
||||
const char *exit_reason;
|
||||
} hurt_state_t;
|
||||
|
||||
typedef struct _hurt {
|
||||
char *ip;
|
||||
struct sockaddr *saddr;
|
||||
int saddr_bits;
|
||||
char *reason;
|
||||
time_t expire;
|
||||
} hurt_t;
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Prototypes */
|
||||
static void mo_hurt(struct MsgBuf *, client::client &, client::client &, int, const char **);
|
||||
static void me_hurt(struct MsgBuf *, client::client &, client::client &, int, const char **);
|
||||
static void mo_heal(struct MsgBuf *, client::client &, client::client &, int, const char **);
|
||||
static void me_heal(struct MsgBuf *, client::client &, client::client &, int, const char **);
|
||||
|
||||
static int modinit(void);
|
||||
static void modfini(void);
|
||||
|
||||
static void client_exit_hook(hook_data_client_exit *);
|
||||
static void new_local_user_hook(client::client *);
|
||||
static void doing_stats_hook(hook_data_int *hdata);
|
||||
|
||||
static void hurt_check_event(void *);
|
||||
static void hurt_expire_event(void *);
|
||||
|
||||
static hurt_t *hurt_new(time_t, const char *, const char *);
|
||||
static void hurt_add(hurt_t *);
|
||||
static void hurt_propagate(client::client *, client::client *, hurt_t *);
|
||||
static hurt_t *hurt_find(const char *ip);
|
||||
static hurt_t *hurt_find_exact(const char *ip);
|
||||
static void hurt_remove(const char *ip);
|
||||
static void hurt_destroy(void *hurt);
|
||||
|
||||
static void heal_nick(client::client &, client::client *);
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* {{{ State containers */
|
||||
|
||||
rb_dlink_list hurt_confs = { NULL, NULL, 0 };
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Messages */
|
||||
struct Message hurt_msgtab = {
|
||||
"HURT", 0, 0, 0, 0, {
|
||||
mg_ignore, mg_ignore, mg_ignore,
|
||||
mg_ignore, {me_hurt, 0}, {mo_hurt, 3}
|
||||
}
|
||||
};
|
||||
|
||||
struct Message heal_msgtab = {
|
||||
"HEAL", 0, 0, 0, 0, {
|
||||
mg_ignore, mg_ignore, mg_ignore,
|
||||
mg_ignore, {me_heal, 0}, {mo_heal, 2}
|
||||
}
|
||||
};
|
||||
/* }}} */
|
||||
|
||||
/* {{{ Misc module stuff */
|
||||
mapi_hfn_list_av1 hurt_hfnlist[] = {
|
||||
{"client_exit", (hookfn) client_exit_hook},
|
||||
{"new_local_user", (hookfn) new_local_user_hook},
|
||||
{"doing_stats", (hookfn) doing_stats_hook},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
mapi_clist_av1 hurt_clist[] = { &hurt_msgtab, &heal_msgtab, NULL };
|
||||
|
||||
static const char hurt_desc[] =
|
||||
"Prevents \"hurt\" users from messaging anyone but operators or "
|
||||
"services until they identify or are \"healed\"";
|
||||
|
||||
DECLARE_MODULE_AV2(
|
||||
hurt,
|
||||
modinit,
|
||||
modfini,
|
||||
hurt_clist,
|
||||
NULL,
|
||||
hurt_hfnlist,
|
||||
NULL,
|
||||
NULL,
|
||||
hurt_desc
|
||||
);
|
||||
/* }}} */
|
||||
|
||||
|
||||
hurt_state_t hurt_state;
|
||||
|
||||
/*
|
||||
* Module constructor/destructor.
|
||||
*/
|
||||
|
||||
/* {{{ static int modinit() */
|
||||
|
||||
struct ev_entry *hurt_expire_ev = NULL;
|
||||
struct ev_entry *hurt_check_ev = NULL;
|
||||
|
||||
static int
|
||||
modinit(void)
|
||||
{
|
||||
/* set-up hurt_state. */
|
||||
hurt_state.start_time = rb_current_time();
|
||||
hurt_state.cutoff = HURT_CUTOFF;
|
||||
hurt_state.default_expire = HURT_DEFAULT_EXPIRE;
|
||||
hurt_state.exit_reason = HURT_EXIT_REASON;
|
||||
|
||||
/* add our event handlers. */
|
||||
hurt_expire_ev = rb_event_add("hurt_expire", hurt_expire_event, NULL, 60);
|
||||
hurt_check_ev = rb_event_add("hurt_check", hurt_check_event, NULL, 5);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ static void modfini() */
|
||||
static void
|
||||
modfini(void)
|
||||
{
|
||||
rb_dlink_node *ptr, *next_ptr;
|
||||
|
||||
/* and delete our events. */
|
||||
rb_event_delete(hurt_expire_ev);
|
||||
rb_event_delete(hurt_check_ev);
|
||||
|
||||
RB_DLINK_FOREACH_SAFE (ptr, next_ptr, hurt_state.hurt_clients.head)
|
||||
{
|
||||
rb_dlinkDestroy(ptr, &hurt_state.hurt_clients);
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/*
|
||||
* Message handlers.
|
||||
*/
|
||||
|
||||
/* {{{ static void mo_hurt()
|
||||
*
|
||||
* HURT [<expire>] <ip> <reason>
|
||||
*
|
||||
* parv[1] - expire or ip
|
||||
* parv[2] - ip or reason
|
||||
* parv[3] - reason or NULL
|
||||
*/
|
||||
static void
|
||||
mo_hurt(struct MsgBuf *msgbuf_p, client::client &client, client::client &source,
|
||||
int parc, const char **parv)
|
||||
{
|
||||
const char *ip, *expire, *reason;
|
||||
int expire_time;
|
||||
hurt_t *hurt;
|
||||
client::client *target_p;
|
||||
|
||||
if (!IsOperK(&source)) {
|
||||
sendto_one(&source, form_str(ERR_NOPRIVS), me.name,
|
||||
source.name, "kline");
|
||||
return;
|
||||
}
|
||||
|
||||
if (parc == 3)
|
||||
expire = NULL, ip = parv[1], reason = parv[2];
|
||||
else
|
||||
expire = parv[1], ip = parv[2], reason = parv[3];
|
||||
|
||||
if (!expire)
|
||||
expire_time = HURT_DEFAULT_EXPIRE;
|
||||
if (expire && (expire_time = valid_temp_time(expire)) < 1) {
|
||||
sendto_one_notice(&source, ":Permanent HURTs are not supported");
|
||||
return;
|
||||
}
|
||||
if (EmptyString(reason)) {
|
||||
sendto_one_notice(&source, ":Empty HURT reasons are bad for business");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Is this a client? */
|
||||
if (strchr(ip, '.') == NULL && strchr(ip, ':') == NULL)
|
||||
{
|
||||
target_p = client::find_named_person(ip);
|
||||
if (target_p == NULL)
|
||||
{
|
||||
sendto_one_numeric(&source, ERR_NOSUCHNICK,
|
||||
form_str(ERR_NOSUCHNICK), ip);
|
||||
return;
|
||||
}
|
||||
ip = target_p->orighost;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!strncmp(ip, "*@", 2))
|
||||
ip += 2;
|
||||
if (strchr(ip, '!') || strchr(ip, '@'))
|
||||
{
|
||||
sendto_one_notice(&source, ":Invalid HURT mask [%s]",
|
||||
ip);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (hurt_find(ip) != NULL) {
|
||||
sendto_one(&source, ":[%s] already HURT", ip);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* okay, we've got this far, now it's time to add the the HURT locally
|
||||
* and propagate it to other servers on the network.
|
||||
*/
|
||||
sendto_realops_snomask(sno::GENERAL, L_ALL,
|
||||
"%s added HURT on [%s] for %ld minutes with reason [%s]",
|
||||
get_oper_name(&source), ip, (long) expire_time / 60, reason);
|
||||
|
||||
hurt = hurt_new(expire_time, ip, reason);
|
||||
hurt_add(hurt);
|
||||
hurt_propagate(NULL, &source, hurt);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ static void me_hurt()
|
||||
*
|
||||
* [ENCAP mask] HURT <target> <expire> <ip> <reason>
|
||||
*
|
||||
* parv[1] - expire
|
||||
* parv[2] - ip
|
||||
* parv[3] - reason
|
||||
*/
|
||||
static void
|
||||
me_hurt(struct MsgBuf *msgbuf_p, client::client &client, client::client &source,
|
||||
int parc, const char **parv)
|
||||
{
|
||||
time_t expire_time;
|
||||
hurt_t *hurt;
|
||||
|
||||
/*
|
||||
* right... if we don't get enough arguments, or if we get any invalid
|
||||
* arguments, just ignore this request - shit happens, and it's not worth
|
||||
* dropping a server over.
|
||||
*/
|
||||
if (parc < 4 || !is_person(source))
|
||||
return;
|
||||
if ((expire_time = atoi(parv[1])) < 1)
|
||||
return;
|
||||
if (hurt_find(parv[2]) != NULL)
|
||||
return;
|
||||
if (EmptyString(parv[3]))
|
||||
return;
|
||||
|
||||
sendto_realops_snomask(sno::GENERAL, L_ALL,
|
||||
"%s added HURT on [%s] for %ld minutes with reason [%s]",
|
||||
get_oper_name(&source), parv[2], (long) expire_time / 60, parv[3]);
|
||||
hurt = hurt_new(expire_time, parv[2], parv[3]);
|
||||
hurt_add(hurt);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ static void mo_heal()
|
||||
*
|
||||
* HURT <nick>|<ip>
|
||||
*
|
||||
* parv[1] - nick or ip
|
||||
*/
|
||||
static void
|
||||
mo_heal(struct MsgBuf *msgbuf_p, client::client &client, client::client &source,
|
||||
int parc, const char **parv)
|
||||
{
|
||||
client::client *target_p;
|
||||
|
||||
if (!IsOperUnkline(&source))
|
||||
{
|
||||
sendto_one(&source, form_str(ERR_NOPRIVS),
|
||||
me.name, source.name, "unkline");
|
||||
return;
|
||||
}
|
||||
|
||||
if (client::clean_nick(parv[1], 0))
|
||||
{
|
||||
target_p = client::find_named_person(parv[1]);
|
||||
if (target_p == NULL)
|
||||
{
|
||||
sendto_one_numeric(&source, ERR_NOSUCHNICK,
|
||||
form_str(ERR_NOSUCHNICK), parv[1]);
|
||||
return;
|
||||
}
|
||||
if (my_connect(*target_p))
|
||||
heal_nick(source, target_p);
|
||||
else
|
||||
sendto_one(target_p, ":%s ENCAP %s HEAL %s",
|
||||
get_id(&source, target_p),
|
||||
target_p->servptr->name,
|
||||
get_id(target_p, target_p));
|
||||
}
|
||||
else if (strchr(parv[1], '.'))
|
||||
{
|
||||
if (hurt_find_exact(parv[1]) == NULL)
|
||||
{
|
||||
sendto_one_notice(&source, ":Mask [%s] is not HURT", parv[1]);
|
||||
return;
|
||||
}
|
||||
hurt_remove(parv[1]);
|
||||
sendto_realops_snomask(sno::GENERAL, L_ALL, "%s removed HURT on %s",
|
||||
get_oper_name(&source), parv[1]);
|
||||
sendto_server(NULL, NULL, NOCAPS, NOCAPS, ":%s ENCAP * HEAL %s",
|
||||
source.name, parv[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
sendto_one(&source, ":[%s] is not a valid IP address/nick", parv[1]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static void
|
||||
me_heal(struct MsgBuf *msgbuf_p, client::client &client, client::client &source,
|
||||
int parc, const char **parv)
|
||||
{
|
||||
client::client *target_p;
|
||||
|
||||
/* as noted in me_hurt(), if we don't get sufficient arguments...
|
||||
* *poof*, it's dropped...
|
||||
*/
|
||||
if (parc < 2)
|
||||
return;
|
||||
|
||||
if (client::clean_nick(parv[1], 0))
|
||||
{
|
||||
target_p = client::find_person(parv[1]);
|
||||
if (target_p != NULL && my_connect(*target_p))
|
||||
heal_nick(source, target_p);
|
||||
}
|
||||
else if (strchr(parv[1], '.')) /* host or mask to remove ban for */
|
||||
{
|
||||
if (hurt_find_exact(parv[1]) == NULL)
|
||||
return;
|
||||
|
||||
hurt_remove(parv[1]);
|
||||
sendto_realops_snomask(sno::GENERAL, L_ALL, "%s removed HURT on %s",
|
||||
get_oper_name(&source), parv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Event handlers.
|
||||
*/
|
||||
|
||||
/* {{{ static void hurt_check_event() */
|
||||
static void
|
||||
hurt_check_event(void *arg)
|
||||
{
|
||||
rb_dlink_node *ptr, *next_ptr;
|
||||
client::client *client_p;
|
||||
|
||||
RB_DLINK_FOREACH_SAFE (ptr, next_ptr, hurt_state.hurt_clients.head) {
|
||||
client_p = (client::client *)ptr->data;
|
||||
if (suser(user(*client_p)).size())
|
||||
{
|
||||
rb_dlinkDestroy(ptr, &hurt_state.hurt_clients);
|
||||
sendto_one_notice(client_p, ":HURT restriction removed for this session");
|
||||
client_p->localClient->target_last = rb_current_time(); /* don't ask --nenolod */
|
||||
}
|
||||
else if (client_p->localClient->receiveM > hurt_state.cutoff)
|
||||
exit_client(NULL, client_p, &me, hurt_state.exit_reason);
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ static void hurt_expire_event() */
|
||||
static void
|
||||
hurt_expire_event(void *unused)
|
||||
{
|
||||
rb_dlink_node *ptr, *next_ptr;
|
||||
hurt_t *hurt;
|
||||
|
||||
RB_DLINK_FOREACH_SAFE (ptr, next_ptr, hurt_confs.head)
|
||||
{
|
||||
hurt = (hurt_t *) ptr->data;
|
||||
|
||||
if (hurt->expire <= rb_current_time())
|
||||
{
|
||||
rb_dlinkFindDestroy(hurt, &hurt_confs);
|
||||
hurt_destroy(hurt);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/*
|
||||
* Hook functions.
|
||||
*/
|
||||
|
||||
/* {{{ static void client_exit_hook() */
|
||||
static void
|
||||
client_exit_hook(hook_data_client_exit *data)
|
||||
{
|
||||
s_assert(data != NULL);
|
||||
s_assert(data->target != NULL);
|
||||
|
||||
rb_dlinkFindDestroy(data->target, &hurt_state.hurt_clients);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ static void new_local_user_hook() */
|
||||
static void
|
||||
new_local_user_hook(client::client *const source)
|
||||
{
|
||||
if (is_any_dead(*source) || suser(user(*source)).size() || is_exempt_kline(*source))
|
||||
return;
|
||||
|
||||
if (hurt_find(source->sockhost) || hurt_find(source->orighost))
|
||||
{
|
||||
source->localClient->target_last = rb_current_time() + 600; /* don't ask --nenolod */
|
||||
set_tg_change(*source);
|
||||
rb_dlinkAddAlloc(source, &hurt_state.hurt_clients);
|
||||
sendto_one_notice(source, ":You are hurt. Please identify to services immediately, or use /stats p for assistance.");
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ static void doing_stats_hook() */
|
||||
static void
|
||||
doing_stats_hook(hook_data_int *hdata)
|
||||
{
|
||||
rb_dlink_node *ptr;
|
||||
hurt_t *hurt;
|
||||
|
||||
s_assert(hdata);
|
||||
s_assert(hdata->client);
|
||||
|
||||
client::client &source = *hdata->client;
|
||||
if(hdata->arg2 != (int) 's')
|
||||
return;
|
||||
if((ConfigFileEntry.stats_k_oper_only == 2) && !is(source, umode::OPER))
|
||||
return;
|
||||
if ((ConfigFileEntry.stats_k_oper_only == 1) && !is(source, umode::OPER))
|
||||
{
|
||||
hurt = hurt_find(source.sockhost);
|
||||
if (hurt != NULL)
|
||||
{
|
||||
sendto_one_numeric(&source, RPL_STATSKLINE,
|
||||
form_str(RPL_STATSKLINE), 's',
|
||||
"*", hurt->ip, hurt->reason, "", "");
|
||||
return;
|
||||
}
|
||||
|
||||
hurt = hurt_find(source.orighost);
|
||||
if (hurt != NULL)
|
||||
{
|
||||
sendto_one_numeric(&source, RPL_STATSKLINE,
|
||||
form_str(RPL_STATSKLINE), 's',
|
||||
"*", hurt->ip, hurt->reason, "", "");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
RB_DLINK_FOREACH(ptr, hurt_confs.head)
|
||||
{
|
||||
hurt = (hurt_t *) ptr->data;
|
||||
sendto_one_numeric(&source, RPL_STATSKLINE,
|
||||
form_str(RPL_STATSKLINE), 's',
|
||||
"*", hurt->ip, hurt->reason, "", "");
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ static void hurt_propagate()
|
||||
*
|
||||
* client_p - specific server to propagate HURT to, or NULL to propagate to all
|
||||
* servers.
|
||||
* &source - source (oper who added the HURT)
|
||||
* hurt - HURT to be propagated
|
||||
*/
|
||||
static void
|
||||
hurt_propagate(client::client *client, client::client *source, hurt_t *hurt)
|
||||
{
|
||||
if (client)
|
||||
sendto_one(client,
|
||||
":%s ENCAP %s HURT %ld %s :%s",
|
||||
source->name, client->name,
|
||||
(long)(hurt->expire - rb_current_time()),
|
||||
hurt->ip, hurt->reason);
|
||||
else
|
||||
sendto_server(&me, NULL, NOCAPS, NOCAPS,
|
||||
":%s ENCAP * HURT %ld %s :%s",
|
||||
source->name,
|
||||
(long)(hurt->expire - rb_current_time()),
|
||||
hurt->ip, hurt->reason);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ static hurt_t *hurt_new() */
|
||||
static hurt_t *
|
||||
hurt_new(time_t expire, const char *ip, const char *reason)
|
||||
{
|
||||
hurt_t *hurt;
|
||||
|
||||
hurt = (hurt_t *)rb_malloc(sizeof(hurt_t));
|
||||
|
||||
hurt->ip = rb_strdup(ip);
|
||||
hurt->reason = rb_strdup(reason);
|
||||
hurt->expire = rb_current_time() + expire;
|
||||
|
||||
return hurt;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ static void hurt_destroy() */
|
||||
static void
|
||||
hurt_destroy(void *hurt)
|
||||
{
|
||||
hurt_t *h;
|
||||
|
||||
if (!hurt)
|
||||
return;
|
||||
|
||||
h = (hurt_t *) hurt;
|
||||
rb_free(h->ip);
|
||||
rb_free(h->reason);
|
||||
rb_free(h);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static void
|
||||
hurt_add(hurt_t *hurt)
|
||||
{
|
||||
rb_dlinkAddAlloc(hurt, &hurt_confs);
|
||||
}
|
||||
|
||||
static hurt_t *
|
||||
hurt_find_exact(const char *ip)
|
||||
{
|
||||
rb_dlink_node *ptr;
|
||||
hurt_t *hurt;
|
||||
|
||||
RB_DLINK_FOREACH(ptr, hurt_confs.head)
|
||||
{
|
||||
hurt = (hurt_t *) ptr->data;
|
||||
|
||||
if (!rb_strcasecmp(ip, hurt->ip))
|
||||
return hurt;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static hurt_t *
|
||||
hurt_find(const char *ip)
|
||||
{
|
||||
rb_dlink_node *ptr;
|
||||
hurt_t *hurt;
|
||||
|
||||
RB_DLINK_FOREACH(ptr, hurt_confs.head)
|
||||
{
|
||||
hurt = (hurt_t *) ptr->data;
|
||||
|
||||
if (match(hurt->ip, ip))
|
||||
return hurt;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
hurt_remove(const char *ip)
|
||||
{
|
||||
hurt_t *hurt = hurt_find_exact(ip);
|
||||
|
||||
rb_dlinkFindDestroy(hurt, &hurt_confs);
|
||||
hurt_destroy(hurt);
|
||||
}
|
||||
|
||||
/* {{{ static void heal_nick() */
|
||||
static void
|
||||
heal_nick(client::client &source, client::client *target_p)
|
||||
{
|
||||
if (rb_dlinkFindDestroy(target_p, &hurt_state.hurt_clients))
|
||||
{
|
||||
sendto_realops_snomask(sno::GENERAL, L_ALL, "%s used HEAL on %s",
|
||||
get_oper_name(&source), get_client_name(target_p, HIDE_IP));
|
||||
sendto_one_notice(target_p, ":HURT restriction temporarily removed by operator");
|
||||
sendto_one_notice(&source, ":HURT restriction on %s temporarily removed", target_p->name);
|
||||
target_p->localClient->target_last = rb_current_time(); /* don't ask --nenolod */
|
||||
}
|
||||
else
|
||||
{
|
||||
sendto_one_notice(&source, ":%s was not hurt", target_p->name);
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/*
|
||||
* vim: ts=8 sw=8 noet fdm=marker tw=80
|
||||
*/
|
|
@ -1,212 +0,0 @@
|
|||
/*
|
||||
* Charybdis: an advanced ircd
|
||||
* ip_cloaking.c: provide user hostname cloaking
|
||||
*
|
||||
* Written originally by nenolod, altered to use FNV by Elizabeth in 2008
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char ip_cloaking_desc[] = "New IP cloaking module that uses user mode +x instead of +h";
|
||||
|
||||
umode::mode UMODE_IP_CLOAKING { 'x' };
|
||||
|
||||
static int
|
||||
_modinit(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_moddeinit(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void check_umode_change(void *data);
|
||||
static void check_new_user(void *data);
|
||||
mapi_hfn_list_av1 ip_cloaking_hfnlist[] = {
|
||||
{ "umode_changed", (hookfn) check_umode_change },
|
||||
{ "new_local_user", (hookfn) check_new_user },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
DECLARE_MODULE_AV2(ip_cloaking, _modinit, _moddeinit, NULL, NULL,
|
||||
ip_cloaking_hfnlist, NULL, NULL, ip_cloaking_desc);
|
||||
|
||||
static void
|
||||
distribute_hostchange(client::client *client_p, char *newhost)
|
||||
{
|
||||
if (newhost != client_p->orighost)
|
||||
sendto_one_numeric(client_p, RPL_HOSTHIDDEN, "%s :is now your hidden host",
|
||||
newhost);
|
||||
else
|
||||
sendto_one_numeric(client_p, RPL_HOSTHIDDEN, "%s :hostname reset",
|
||||
newhost);
|
||||
|
||||
sendto_server(NULL, NULL,
|
||||
CAP_EUID | CAP_TS6, NOCAPS, ":%s CHGHOST %s :%s",
|
||||
use_id(&me), use_id(client_p), newhost);
|
||||
sendto_server(NULL, NULL,
|
||||
CAP_TS6, CAP_EUID, ":%s ENCAP * CHGHOST %s :%s",
|
||||
use_id(&me), use_id(client_p), newhost);
|
||||
|
||||
change_nick_user_host(client_p, client_p->name, client_p->username, newhost, 0, "Changing host");
|
||||
|
||||
if (newhost != client_p->orighost)
|
||||
set_dyn_spoof(*client_p);
|
||||
else
|
||||
clear_dyn_spoof(*client_p);
|
||||
}
|
||||
|
||||
static void
|
||||
do_host_cloak_ip(const char *inbuf, char *outbuf)
|
||||
{
|
||||
/* None of the characters in this table can be valid in an IP */
|
||||
char chartable[] = "ghijklmnopqrstuvwxyz";
|
||||
char *tptr;
|
||||
uint32_t accum = fnv_hash((const unsigned char*) inbuf, 32);
|
||||
int sepcount = 0;
|
||||
int totalcount = 0;
|
||||
int ipv6 = 0;
|
||||
|
||||
rb_strlcpy(outbuf, inbuf, HOSTLEN + 1);
|
||||
|
||||
if (strchr(outbuf, ':'))
|
||||
{
|
||||
ipv6 = 1;
|
||||
|
||||
/* Damn you IPv6...
|
||||
* We count the number of colons so we can calculate how much
|
||||
* of the host to cloak. This is because some hostmasks may not
|
||||
* have as many octets as we'd like.
|
||||
*
|
||||
* We have to do this ahead of time because doing this during
|
||||
* the actual cloaking would get ugly
|
||||
*/
|
||||
for (tptr = outbuf; *tptr != '\0'; tptr++)
|
||||
if (*tptr == ':')
|
||||
totalcount++;
|
||||
}
|
||||
else if (!strchr(outbuf, '.'))
|
||||
return;
|
||||
|
||||
for (tptr = outbuf; *tptr != '\0'; tptr++)
|
||||
{
|
||||
if (*tptr == ':' || *tptr == '.')
|
||||
{
|
||||
sepcount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ipv6 && sepcount < totalcount / 2)
|
||||
continue;
|
||||
|
||||
if (!ipv6 && sepcount < 2)
|
||||
continue;
|
||||
|
||||
*tptr = chartable[(*tptr + accum) % 20];
|
||||
accum = (accum << 1) | (accum >> 31);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
do_host_cloak_host(const char *inbuf, char *outbuf)
|
||||
{
|
||||
char b26_alphabet[] = "abcdefghijklmnopqrstuvwxyz";
|
||||
char *tptr;
|
||||
uint32_t accum = fnv_hash((const unsigned char*) inbuf, 32);
|
||||
|
||||
rb_strlcpy(outbuf, inbuf, HOSTLEN + 1);
|
||||
|
||||
/* pass 1: scramble first section of hostname using base26
|
||||
* alphabet toasted against the FNV hash of the string.
|
||||
*
|
||||
* numbers are not changed at this time, only letters.
|
||||
*/
|
||||
for (tptr = outbuf; *tptr != '\0'; tptr++)
|
||||
{
|
||||
if (*tptr == '.')
|
||||
break;
|
||||
|
||||
if (isdigit((unsigned char)*tptr) || *tptr == '-')
|
||||
continue;
|
||||
|
||||
*tptr = b26_alphabet[(*tptr + accum) % 26];
|
||||
|
||||
/* Rotate one bit to avoid all digits being turned odd or even */
|
||||
accum = (accum << 1) | (accum >> 31);
|
||||
}
|
||||
|
||||
/* pass 2: scramble each number in the address */
|
||||
for (tptr = outbuf; *tptr != '\0'; tptr++)
|
||||
{
|
||||
if (isdigit((unsigned char)*tptr))
|
||||
*tptr = '0' + (*tptr + accum) % 10;
|
||||
|
||||
accum = (accum << 1) | (accum >> 31);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
check_umode_change(void *vdata)
|
||||
{
|
||||
hook_data_umode_changed *data = (hook_data_umode_changed *)vdata;
|
||||
client::client *source_p = data->client;
|
||||
|
||||
if (!my(*source_p))
|
||||
return;
|
||||
|
||||
/* didn't change +h umode, we don't need to do anything */
|
||||
if (!((data->oldumodes ^ source_p->mode) & UMODE_IP_CLOAKING))
|
||||
return;
|
||||
|
||||
if (source_p->mode & UMODE_IP_CLOAKING)
|
||||
{
|
||||
if (is_ip_spoof(*source_p) || source_p->localClient->mangledhost == NULL || (is_dyn_spoof(*source_p) && strcmp(source_p->host, source_p->localClient->mangledhost)))
|
||||
{
|
||||
source_p->mode &= ~UMODE_IP_CLOAKING;
|
||||
return;
|
||||
}
|
||||
if (strcmp(source_p->host, source_p->localClient->mangledhost))
|
||||
{
|
||||
distribute_hostchange(source_p, source_p->localClient->mangledhost);
|
||||
}
|
||||
else /* not really nice, but we need to send this numeric here */
|
||||
sendto_one_numeric(source_p, RPL_HOSTHIDDEN, "%s :is now your hidden host",
|
||||
source_p->host);
|
||||
}
|
||||
else if (!(source_p->mode & UMODE_IP_CLOAKING))
|
||||
{
|
||||
if (source_p->localClient->mangledhost != NULL &&
|
||||
!strcmp(source_p->host, source_p->localClient->mangledhost))
|
||||
{
|
||||
distribute_hostchange(source_p, source_p->orighost);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
check_new_user(void *vdata)
|
||||
{
|
||||
client::client *source_p = (client::client *)vdata;
|
||||
|
||||
if (is_ip_spoof(*source_p))
|
||||
{
|
||||
source_p->mode &= ~UMODE_IP_CLOAKING;
|
||||
return;
|
||||
}
|
||||
source_p->localClient->mangledhost = (char *)rb_malloc(HOSTLEN + 1);
|
||||
if (!irccmp(source_p->orighost, source_p->sockhost))
|
||||
do_host_cloak_ip(source_p->orighost, source_p->localClient->mangledhost);
|
||||
else
|
||||
do_host_cloak_host(source_p->orighost, source_p->localClient->mangledhost);
|
||||
if (is_dyn_spoof(*source_p))
|
||||
source_p->mode &= ~UMODE_IP_CLOAKING;
|
||||
if (source_p->mode & UMODE_IP_CLOAKING)
|
||||
{
|
||||
rb_strlcpy(source_p->host, source_p->localClient->mangledhost, sizeof(source_p->host));
|
||||
if (irccmp(source_p->host, source_p->orighost))
|
||||
set_dyn_spoof(*source_p);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
* ircd-ratbox: A slightly useful ircd.
|
||||
* m_adminwall.c: Sends a message to all admins
|
||||
*
|
||||
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
|
||||
* Copyright (C) 1996-2002 Hybrid Development Team
|
||||
* Copyright (C) 2002-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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char adminwall_desc[] =
|
||||
"Provides the ADMINWALL command to send a message to all administrators";
|
||||
|
||||
static void mo_adminwall(struct MsgBuf *, client::client &, client::client &, int, const char **);
|
||||
static void me_adminwall(struct MsgBuf *, client::client &, client::client &, int, const char **);
|
||||
|
||||
struct Message adminwall_msgtab = {
|
||||
"ADMINWALL", 0, 0, 0, 0,
|
||||
{mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_adminwall, 2}, {mo_adminwall, 2}}
|
||||
};
|
||||
|
||||
mapi_clist_av1 adminwall_clist[] = { &adminwall_msgtab, NULL };
|
||||
|
||||
DECLARE_MODULE_AV2(adminwall, NULL, NULL, adminwall_clist, NULL, NULL, NULL, NULL, adminwall_desc);
|
||||
|
||||
/*
|
||||
* mo_adminwall (write to *all* admins currently online)
|
||||
* parv[1] = message text
|
||||
*/
|
||||
|
||||
static void
|
||||
mo_adminwall(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[])
|
||||
{
|
||||
if(!is(source, umode::ADMIN))
|
||||
{
|
||||
sendto_one(&source, form_str(ERR_NOPRIVS),
|
||||
me.name, source.name, "adminwall");
|
||||
return;
|
||||
}
|
||||
sendto_wallops_flags(umode::ADMIN, &source, "ADMINWALL - %s", parv[1]);
|
||||
sendto_match_servs(&source, "*", CAP_ENCAP, NOCAPS, "ENCAP * ADMINWALL :%s", parv[1]);
|
||||
}
|
||||
|
||||
static void
|
||||
me_adminwall(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[])
|
||||
{
|
||||
sendto_wallops_flags(umode::ADMIN, &source, "ADMINWALL - %s", parv[1]);
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
using namespace ircd;
|
||||
|
||||
static void m_echotags(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[]);
|
||||
|
||||
struct Message echotags_msgtab = {
|
||||
"ECHOTAGS", 0, 0, 0, 0,
|
||||
{ mg_ignore, {m_echotags, 0}, mg_ignore, mg_ignore, mg_ignore, {m_echotags, 0} }
|
||||
};
|
||||
|
||||
mapi_clist_av1 echotags_clist[] = { &echotags_msgtab, NULL };
|
||||
|
||||
static const char echotags_desc[] = "A test module for tags";
|
||||
|
||||
DECLARE_MODULE_AV2(echotags, NULL, NULL, echotags_clist, NULL, NULL, NULL, NULL, echotags_desc);
|
||||
|
||||
static void
|
||||
m_echotags(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[])
|
||||
{
|
||||
sendto_one_notice(&source, ":*** You sent %zu tags.", msgbuf_p->n_tags);
|
||||
|
||||
for (size_t i = 0; i < msgbuf_p->n_tags; i++)
|
||||
{
|
||||
struct MsgTag *tag = &msgbuf_p->tags[i];
|
||||
|
||||
if (tag->value)
|
||||
sendto_one_notice(&source, ":*** %zu: %s => %s", i, tag->key, tag->value);
|
||||
else
|
||||
sendto_one_notice(&source, ":*** %zu: %s", i, tag->key);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
/*
|
||||
* charybdis
|
||||
* m_extendchans.c: Allow an oper or service to let a given user join more channels.
|
||||
*
|
||||
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
|
||||
* Copyright (C) 1996-2002 Hybrid Development Team
|
||||
* Copyright (C) 2002-2006 ircd-ratbox development team
|
||||
* Copyright (C) 2006-2016 ircd-seven development team
|
||||
* Copyright (C) 2015-2016 ChatLounge IRC Network 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char extendchans_desc[] =
|
||||
"Allow an oper or service to let a given user join more channels";
|
||||
|
||||
static void mo_extendchans(struct MsgBuf *, client::client &, client::client &, int, const char **);
|
||||
static void me_extendchans(struct MsgBuf *, client::client &, client::client &, int, const char **);
|
||||
|
||||
struct Message extendchans_msgtab = {
|
||||
"EXTENDCHANS", 0, 0, 0, 0,
|
||||
{ mg_unreg, mg_ignore, mg_ignore, mg_ignore, {me_extendchans, 2}, {mo_extendchans, 2}}
|
||||
};
|
||||
|
||||
mapi_clist_av1 extendchans_clist[] = { &extendchans_msgtab, NULL };
|
||||
|
||||
DECLARE_MODULE_AV2(extendchans, NULL, NULL, extendchans_clist, NULL, NULL, NULL, NULL, extendchans_desc);
|
||||
|
||||
static void
|
||||
mo_extendchans(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[])
|
||||
{
|
||||
client::client *target_p;
|
||||
|
||||
if(!HasPrivilege(&source, "oper:extendchans"))
|
||||
{
|
||||
sendto_one(&source, form_str(ERR_NOPRIVS), me.name, source.name, "extendchans");
|
||||
return;
|
||||
}
|
||||
|
||||
if(EmptyString(parv[1]))
|
||||
{
|
||||
sendto_one(&source, form_str(ERR_NEEDMOREPARAMS), me.name, source.name, "EXTENDCHANS");
|
||||
return;
|
||||
}
|
||||
|
||||
if((target_p = find_chasing(&source, parv[1], NULL)) == NULL)
|
||||
return;
|
||||
|
||||
/* Is the target user local? */
|
||||
if(my(*target_p))
|
||||
{
|
||||
sendto_one_notice(target_p, ":*** %s (%s@%s) is extending your channel limit",
|
||||
source.name, source.username, source.host);
|
||||
set_extend_chans(*target_p);
|
||||
}
|
||||
else /* Target user isn't local, so pass it on. */
|
||||
{
|
||||
client::client *cptr = target_p->servptr;
|
||||
sendto_one(cptr, ":%s ENCAP %s EXTENDCHANS %s",
|
||||
get_id(&source, cptr), cptr->name, get_id(target_p, cptr));
|
||||
}
|
||||
|
||||
sendto_one_notice(&source, ":You have extended the channel limit on: %s (%s@%s)",
|
||||
target_p->name, target_p->username, target_p->orighost);
|
||||
}
|
||||
|
||||
static void
|
||||
me_extendchans(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[])
|
||||
{
|
||||
client::client *target_p;
|
||||
|
||||
target_p = client::find_person(parv[1]);
|
||||
if(target_p == NULL)
|
||||
{
|
||||
sendto_one_numeric(&source, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), parv[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Is the target user local? If not, pass it on. */
|
||||
if(!my(*target_p))
|
||||
{
|
||||
client::client *cptr = target_p->servptr;
|
||||
sendto_one(cptr, ":%s ENCAP %s EXTENDCHANS %s",
|
||||
get_id(&source, cptr), cptr->name, get_id(target_p, cptr));
|
||||
return;
|
||||
}
|
||||
|
||||
sendto_one_notice(target_p, ":*** %s (%s@%s) is extending your channel limit",
|
||||
source.name, source.username, source.host);
|
||||
set_extend_chans(*target_p);
|
||||
}
|
|
@ -1,100 +0,0 @@
|
|||
/*
|
||||
* IRC - Internet Relay Chat, contrib/m_findforwards.c
|
||||
* Copyright (C) 2002 Hybrid Development Team
|
||||
* Copyright (C) 2004 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char findfowards_desc[] = "Allows operators to find forwards to a given channel";
|
||||
|
||||
static void m_findforwards(struct MsgBuf *msgbuf_p, client::client &client, client::client &source,
|
||||
int parc, const char *parv[]);
|
||||
|
||||
struct Message findforwards_msgtab = {
|
||||
"FINDFORWARDS", 0, 0, 0, 0,
|
||||
{mg_unreg, {m_findforwards, 2}, mg_ignore, mg_ignore, mg_ignore, {m_findforwards, 2}}
|
||||
};
|
||||
|
||||
mapi_clist_av1 findforwards_clist[] = { &findforwards_msgtab, NULL };
|
||||
|
||||
DECLARE_MODULE_AV2(findforwards, NULL, NULL, findforwards_clist, NULL, NULL, NULL, NULL, findfowards_desc);
|
||||
|
||||
/*
|
||||
** mo_findforwards
|
||||
** parv[1] = channel
|
||||
*/
|
||||
static void
|
||||
m_findforwards(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[])
|
||||
{
|
||||
static time_t last_used = 0;
|
||||
chan::chan *chptr;
|
||||
chan::membership *msptr;
|
||||
rb_dlink_node *ptr;
|
||||
char buf[414];
|
||||
char *p = buf, *end = buf + sizeof buf - 1;
|
||||
*p = '\0';
|
||||
|
||||
/* Allow ircops to search for forwards to nonexistent channels */
|
||||
if(!is(source, umode::OPER))
|
||||
{
|
||||
if((chptr = chan::get(parv[1], std::nothrow)) == NULL || (msptr = get(chptr->members, source, std::nothrow)) == NULL)
|
||||
{
|
||||
sendto_one_numeric(&source, ERR_NOTONCHANNEL,
|
||||
form_str(ERR_NOTONCHANNEL), parv[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!is_chanop(msptr))
|
||||
{
|
||||
sendto_one(&source, form_str(ERR_CHANOPRIVSNEEDED),
|
||||
me.name, source.name, parv[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
if((last_used + ConfigFileEntry.pace_wait) > rb_current_time())
|
||||
{
|
||||
sendto_one(&source, form_str(RPL_LOAD2HI),
|
||||
me.name, source.name, "FINDFORWARDS");
|
||||
return;
|
||||
}
|
||||
else
|
||||
last_used = rb_current_time();
|
||||
}
|
||||
|
||||
for(const auto &pit : chan::chans)
|
||||
{
|
||||
chptr = pit.second.get();
|
||||
if(!irccmp(chptr->mode.forward, parv[1]))
|
||||
{
|
||||
if(p + chptr->name.size() >= end - 13)
|
||||
{
|
||||
strcpy(p, "<truncated> ");
|
||||
p += 12;
|
||||
break;
|
||||
}
|
||||
strcpy(p, chptr->name.c_str());
|
||||
p += chptr->name.size();
|
||||
*p++ = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
if(buf[0])
|
||||
*(--p) = '\0';
|
||||
|
||||
sendto_one_notice(&source, ":Forwards for %s: %s", parv[1], buf);
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
/*
|
||||
* m_identify.c: dalnet-style /identify that sends to nickserv or chanserv
|
||||
*
|
||||
* Copyright (C) 2006 Jilles Tjoelker
|
||||
* Copyright (C) 2006 charybdis 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.
|
||||
*/
|
||||
|
||||
#define SVS_chanserv_NICK "ChanServ"
|
||||
#define SVS_nickserv_NICK "NickServ"
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char identify_desc[] = "Adds the IDENTIFY alias that forwards to NickServ or ChanServ";
|
||||
|
||||
static void m_identify(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[]);
|
||||
|
||||
struct Message identify_msgtab = {
|
||||
"IDENTIFY", 0, 0, 0, 0,
|
||||
{mg_unreg, {m_identify, 0}, mg_ignore, mg_ignore, mg_ignore, {m_identify, 0}}
|
||||
};
|
||||
|
||||
mapi_clist_av1 identify_clist[] = {
|
||||
&identify_msgtab,
|
||||
NULL
|
||||
};
|
||||
|
||||
DECLARE_MODULE_AV2(identify, NULL, NULL, identify_clist, NULL, NULL, NULL, NULL, identify_desc);
|
||||
|
||||
static void
|
||||
m_identify(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[])
|
||||
{
|
||||
const char *nick;
|
||||
client::client *target_p;
|
||||
|
||||
if (parc < 2 || EmptyString(parv[1]))
|
||||
{
|
||||
sendto_one(&source, form_str(ERR_NOTEXTTOSEND), me.name, source.name);
|
||||
return;
|
||||
}
|
||||
|
||||
nick = parv[1][0] == '#' ? SVS_chanserv_NICK : SVS_nickserv_NICK;
|
||||
if ((target_p = client::find_named_person(nick)) && is(*target_p, umode::SERVICE))
|
||||
{
|
||||
sendto_one(target_p, ":%s PRIVMSG %s :IDENTIFY %s", get_id(&source, target_p), get_id(target_p, target_p), reconstruct_parv(parc - 1, &parv[1]));
|
||||
}
|
||||
else
|
||||
{
|
||||
sendto_one_numeric(&source, ERR_SERVICESDOWN, form_str(ERR_SERVICESDOWN), nick);
|
||||
}
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
* ircd-ratbox: A slightly useful ircd.
|
||||
* m_locops.c: Sends a message to all operators on the local server.
|
||||
*
|
||||
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
|
||||
* Copyright (C) 1996-2002 Hybrid Development Team
|
||||
* Copyright (C) 2002-2005 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char locops_desc[] =
|
||||
"Provides the LOCOPS command to send a message to all local operators";
|
||||
|
||||
static void m_locops(struct MsgBuf *, client::client &, client::client &, int, const char **);
|
||||
static void ms_locops(struct MsgBuf *, client::client &, client::client &, int, const char **);
|
||||
static void me_locops(struct MsgBuf *, client::client &, client::client &, int, const char **);
|
||||
|
||||
struct Message locops_msgtab = {
|
||||
"LOCOPS", 0, 0, 0, 0,
|
||||
{mg_unreg, mg_not_oper, {ms_locops, 3}, mg_ignore, {me_locops, 2}, {m_locops, 2}}
|
||||
};
|
||||
|
||||
mapi_clist_av1 locops_clist[] = { &locops_msgtab, NULL };
|
||||
|
||||
DECLARE_MODULE_AV2(locops, NULL, NULL, locops_clist, NULL, NULL, NULL, NULL, locops_desc);
|
||||
|
||||
/*
|
||||
* m_locops - LOCOPS message handler
|
||||
* (write to *all* local opers currently online)
|
||||
* parv[1] = message text
|
||||
*/
|
||||
static void
|
||||
m_locops(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[])
|
||||
{
|
||||
sendto_wallops_flags(umode::LOCOPS, &source, "LOCOPS - %s", parv[1]);
|
||||
|
||||
if(rb_dlink_list_length(&cluster_conf_list) > 0)
|
||||
cluster_generic(&source, "LOCOPS", SHARED_LOCOPS, CAP_CLUSTER,
|
||||
":%s", parv[1]);
|
||||
}
|
||||
|
||||
static void
|
||||
ms_locops(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[])
|
||||
{
|
||||
/* &source parv[1] parv[2]
|
||||
* oper target serv message
|
||||
*/
|
||||
propagate_generic(&source, "LOCOPS", parv[1], CAP_CLUSTER,
|
||||
":%s", parv[2]);
|
||||
|
||||
if(!match(parv[1], me.name))
|
||||
return;
|
||||
|
||||
if(find_shared_conf("*", "*", source.servptr->name, SHARED_LOCOPS))
|
||||
sendto_wallops_flags(umode::LOCOPS, &source, "SLOCOPS - %s", parv[2]);
|
||||
}
|
||||
|
||||
static void
|
||||
me_locops(struct MsgBuf *msgbuf_p, client::client &client, client::client &source,
|
||||
int parc, const char *parv[])
|
||||
{
|
||||
if(!is_person(source))
|
||||
return;
|
||||
|
||||
if(find_shared_conf("*", "*", source.servptr->name, SHARED_LOCOPS))
|
||||
sendto_wallops_flags(umode::LOCOPS, &source, "SLOCOPS - %s", parv[1]);
|
||||
}
|
||||
|
|
@ -1,211 +0,0 @@
|
|||
/*
|
||||
* m_mkpasswd.c: Encrypts a password online.
|
||||
*
|
||||
* Based on mkpasswd.c, originally by Nelson Minar (minar@reed.edu)
|
||||
* You can use this code in any way as long as these names remain.
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
const char mkpasswd_desc[] = "Hash a password for use in ircd.conf";
|
||||
|
||||
static void m_mkpasswd(struct MsgBuf *msgbuf_p, client::client &client, client::client &source,
|
||||
int parc, const char *parv[]);
|
||||
static void mo_mkpasswd(struct MsgBuf *msgbuf_p, client::client &client, client::client &source,
|
||||
int parc, const char *parv[]);
|
||||
|
||||
static char *make_md5_salt(int);
|
||||
static char *make_sha256_salt(int);
|
||||
static char *make_sha512_salt(int);
|
||||
static char *generate_random_salt(char *, int);
|
||||
static char *generate_poor_salt(char *, int);
|
||||
|
||||
static char saltChars[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
/* 0 .. 63, ascii - 64 */
|
||||
|
||||
struct Message mkpasswd_msgtab = {
|
||||
"MKPASSWD", 0, 0, 0, 0,
|
||||
{mg_unreg, {m_mkpasswd, 2}, mg_ignore, mg_ignore, mg_ignore, {mo_mkpasswd, 2}}
|
||||
};
|
||||
|
||||
mapi_clist_av1 mkpasswd_clist[] = { &mkpasswd_msgtab, NULL };
|
||||
|
||||
DECLARE_MODULE_AV2(mkpasswd, NULL, NULL, mkpasswd_clist, NULL, NULL, NULL, NULL, mkpasswd_desc);
|
||||
|
||||
|
||||
/* m_mkpasswd - mkpasswd message handler
|
||||
* parv[1] = password
|
||||
* parv[2] = type
|
||||
*/
|
||||
static void
|
||||
m_mkpasswd(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[])
|
||||
{
|
||||
static time_t last_used = 0;
|
||||
char *salt;
|
||||
const char *crypted;
|
||||
const char *hashtype;
|
||||
const char hashdefault[] = "SHA512";
|
||||
|
||||
if(EmptyString(parv[1]))
|
||||
{
|
||||
sendto_one(&source, form_str(ERR_NEEDMOREPARAMS), me.name, source.name, "MKPASSWD");
|
||||
return;
|
||||
}
|
||||
|
||||
if(parc < 3)
|
||||
hashtype = hashdefault;
|
||||
else
|
||||
hashtype = parv[2];
|
||||
|
||||
if((last_used + ConfigFileEntry.pace_wait) > rb_current_time())
|
||||
{
|
||||
/* safe enough to give this on a local connect only */
|
||||
sendto_one(&source, form_str(RPL_LOAD2HI), me.name, source.name, "MKPASSWD");
|
||||
return;
|
||||
}
|
||||
else
|
||||
last_used = rb_current_time();
|
||||
|
||||
if(!irccmp(hashtype, "SHA256"))
|
||||
salt = make_sha256_salt(16);
|
||||
else if(!irccmp(hashtype, "SHA512"))
|
||||
salt = make_sha512_salt(16);
|
||||
else if(!irccmp(hashtype, "MD5"))
|
||||
salt = make_md5_salt(8);
|
||||
else
|
||||
{
|
||||
sendto_one_notice(&source,
|
||||
":MKPASSWD syntax error: MKPASSWD pass [SHA256|SHA512|MD5]");
|
||||
return;
|
||||
}
|
||||
|
||||
crypted = rb_crypt(parv[1], salt);
|
||||
sendto_one_notice(&source, ":Hash [%s] for %s: %s", hashtype, parv[1], crypted ? crypted : "???");
|
||||
}
|
||||
|
||||
/* mo_mkpasswd - mkpasswd message handler
|
||||
* parv[1] = password
|
||||
* parv[2] = type
|
||||
*/
|
||||
static void
|
||||
mo_mkpasswd(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[])
|
||||
{
|
||||
char *salt;
|
||||
const char *crypted;
|
||||
const char *hashtype;
|
||||
const char hashdefault[] = "SHA512";
|
||||
|
||||
if(EmptyString(parv[1]))
|
||||
{
|
||||
sendto_one(&source, form_str(ERR_NEEDMOREPARAMS), me.name, source.name, "MKPASSWD");
|
||||
return;
|
||||
}
|
||||
|
||||
if(parc < 3)
|
||||
hashtype = hashdefault;
|
||||
else
|
||||
hashtype = parv[2];
|
||||
|
||||
if(!irccmp(hashtype, "SHA256"))
|
||||
salt = make_sha256_salt(16);
|
||||
else if(!irccmp(hashtype, "SHA512"))
|
||||
salt = make_sha512_salt(16);
|
||||
else if(!irccmp(hashtype, "MD5"))
|
||||
salt = make_md5_salt(8);
|
||||
else
|
||||
{
|
||||
sendto_one_notice(&source,
|
||||
":MKPASSWD syntax error: MKPASSWD pass [SHA256|SHA512|MD5]");
|
||||
return;
|
||||
}
|
||||
|
||||
crypted = rb_crypt(parv[1], salt);
|
||||
sendto_one_notice(&source, ":Hash [%s] for %s: %s", hashtype, parv[1], crypted ? crypted : "???");
|
||||
}
|
||||
|
||||
char *
|
||||
make_md5_salt(int length)
|
||||
{
|
||||
static char salt[21];
|
||||
if(length > 16)
|
||||
{
|
||||
printf("MD5 salt length too long\n");
|
||||
exit(0);
|
||||
}
|
||||
salt[0] = '$';
|
||||
salt[1] = '1';
|
||||
salt[2] = '$';
|
||||
generate_random_salt(&salt[3], length);
|
||||
salt[length + 3] = '$';
|
||||
salt[length + 4] = '\0';
|
||||
return salt;
|
||||
}
|
||||
|
||||
char *
|
||||
make_sha256_salt(int length)
|
||||
{
|
||||
static char salt[21];
|
||||
if(length > 16)
|
||||
{
|
||||
printf("SHA256 salt length too long\n");
|
||||
exit(0);
|
||||
}
|
||||
salt[0] = '$';
|
||||
salt[1] = '5';
|
||||
salt[2] = '$';
|
||||
generate_random_salt(&salt[3], length);
|
||||
salt[length + 3] = '$';
|
||||
salt[length + 4] = '\0';
|
||||
return salt;
|
||||
}
|
||||
|
||||
char *
|
||||
make_sha512_salt(int length)
|
||||
{
|
||||
static char salt[21];
|
||||
if(length > 16)
|
||||
{
|
||||
printf("SHA512 salt length too long\n");
|
||||
exit(0);
|
||||
}
|
||||
salt[0] = '$';
|
||||
salt[1] = '6';
|
||||
salt[2] = '$';
|
||||
generate_random_salt(&salt[3], length);
|
||||
salt[length + 3] = '$';
|
||||
salt[length + 4] = '\0';
|
||||
return salt;
|
||||
}
|
||||
|
||||
char *
|
||||
generate_poor_salt(char *salt, int length)
|
||||
{
|
||||
int i;
|
||||
|
||||
srand(time(NULL));
|
||||
for(i = 0; i < length; i++)
|
||||
salt[i] = saltChars[rand() % 64];
|
||||
|
||||
return (salt);
|
||||
}
|
||||
|
||||
char *
|
||||
generate_random_salt(char *salt, int length)
|
||||
{
|
||||
int fd, i;
|
||||
|
||||
if((fd = open("/dev/urandom", O_RDONLY)) < 0)
|
||||
return (generate_poor_salt(salt, length));
|
||||
|
||||
if(read(fd, salt, (size_t)length) != length)
|
||||
{
|
||||
close(fd);
|
||||
return (generate_poor_salt(salt, length));
|
||||
}
|
||||
|
||||
for(i = 0; i < length; i++)
|
||||
salt[i] = saltChars[int(abs(salt[i])) % 64];
|
||||
|
||||
close(fd);
|
||||
return (salt);
|
||||
}
|
|
@ -1,126 +0,0 @@
|
|||
/* contrib/m_ojoin.c
|
||||
* Copyright (C) 2002 Hybrid Development Team
|
||||
* Copyright (C) 2004 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char ojoin_desc[] = "Allow admins to forcibly join channels with the OJOIN command";
|
||||
|
||||
static void mo_ojoin(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[]);
|
||||
|
||||
struct Message ojoin_msgtab = {
|
||||
"OJOIN", 0, 0, 0, 0,
|
||||
{mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_ojoin, 2}}
|
||||
};
|
||||
|
||||
mapi_clist_av1 ojoin_clist[] = { &ojoin_msgtab, NULL };
|
||||
|
||||
DECLARE_MODULE_AV2(ojoin, NULL, NULL, ojoin_clist, NULL, NULL, NULL, NULL, ojoin_desc);
|
||||
|
||||
/*
|
||||
** mo_ojoin
|
||||
** parv[1] = channel
|
||||
*/
|
||||
static void
|
||||
mo_ojoin(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[])
|
||||
{
|
||||
chan::chan *chptr;
|
||||
int move_me = 0;
|
||||
|
||||
/* admins only */
|
||||
if(!IsOperAdmin(&source))
|
||||
{
|
||||
sendto_one(&source, form_str(ERR_NOPRIVS), me.name, source.name, "admin");
|
||||
return;
|
||||
}
|
||||
|
||||
if(*parv[1] == '@' || *parv[1] == '+')
|
||||
{
|
||||
parv[1]++;
|
||||
move_me = 1;
|
||||
}
|
||||
|
||||
if((chptr = chan::get(parv[1], std::nothrow)) == NULL)
|
||||
{
|
||||
sendto_one_numeric(&source, ERR_NOSUCHCHANNEL,
|
||||
form_str(ERR_NOSUCHCHANNEL), parv[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
if(is_member(chptr, &source))
|
||||
{
|
||||
sendto_one_notice(&source, ":Please part %s before using OJOIN", parv[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
if(move_me == 1)
|
||||
parv[1]--;
|
||||
|
||||
sendto_wallops_flags(umode::WALLOP, &me,
|
||||
"OJOIN called for %s by %s!%s@%s",
|
||||
parv[1], source.name, source.username, source.host);
|
||||
ilog(L_MAIN, "OJOIN called for %s by %s",
|
||||
parv[1], get_oper_name(&source));
|
||||
/* only sends stuff for #channels remotely */
|
||||
sendto_server(NULL, chptr, NOCAPS, NOCAPS,
|
||||
":%s WALLOPS :OJOIN called for %s by %s!%s@%s",
|
||||
me.name, parv[1],
|
||||
source.name, source.username, source.host);
|
||||
|
||||
if(*parv[1] == '@')
|
||||
{
|
||||
add(*chptr, source, chan::CHANOP);
|
||||
sendto_server(&client, chptr, CAP_TS6, NOCAPS,
|
||||
":%s SJOIN %ld %s + :@%s",
|
||||
me.id, (long) chptr->channelts, chptr->name.c_str(), source.id);
|
||||
send_join(*chptr, source);
|
||||
sendto_channel_local(chan::ALL_MEMBERS, chptr, ":%s MODE %s +o %s",
|
||||
me.name, chptr->name.c_str(), source.name);
|
||||
|
||||
}
|
||||
else if(*parv[1] == '+')
|
||||
{
|
||||
add(*chptr, source, chan::VOICE);
|
||||
sendto_server(&client, chptr, CAP_TS6, NOCAPS,
|
||||
":%s SJOIN %ld %s + :+%s",
|
||||
me.id, (long) chptr->channelts, chptr->name.c_str(), source.id);
|
||||
send_join(*chptr, source);
|
||||
sendto_channel_local(chan::ALL_MEMBERS, chptr, ":%s MODE %s +v %s",
|
||||
me.name, chptr->name.c_str(), source.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
add(*chptr, source, chan::PEON);
|
||||
sendto_server(&client, chptr, CAP_TS6, NOCAPS,
|
||||
":%s JOIN %ld %s +",
|
||||
source.id, (long) chptr->channelts, chptr->name.c_str());
|
||||
send_join(*chptr, source);
|
||||
}
|
||||
|
||||
/* send the topic... */
|
||||
if(chptr->topic)
|
||||
{
|
||||
sendto_one(&source, form_str(RPL_TOPIC), me.name,
|
||||
source.name, chptr->name.c_str(), chptr->topic.text.c_str());
|
||||
sendto_one(&source, form_str(RPL_TOPICWHOTIME), me.name,
|
||||
source.name, chptr->name.c_str(), chptr->topic.info.c_str(), chptr->topic.time);
|
||||
}
|
||||
|
||||
source.localClient->last_join_time = rb_current_time();
|
||||
channel_member_names(chptr, &source, 1);
|
||||
}
|
|
@ -1,125 +0,0 @@
|
|||
/*
|
||||
* ircd-ratbox: A slightly useful ircd.
|
||||
* m_okick.c: Kicks a user from a channel with much prejudice.
|
||||
*
|
||||
* Copyright (C) 2002 by the past and present ircd coders, and others.
|
||||
* Copyright (C) 2004 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char okick_desc[] = "Allow admins to forcibly kick users from channels with the OKICK command";
|
||||
|
||||
static void mo_okick(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[]);
|
||||
|
||||
struct Message okick_msgtab = {
|
||||
"OKICK", 0, 0, 0, 0,
|
||||
{mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_okick, 4}}
|
||||
};
|
||||
|
||||
mapi_clist_av1 okick_clist[] = { &okick_msgtab, NULL };
|
||||
|
||||
DECLARE_MODULE_AV2(okick, NULL, NULL, okick_clist, NULL, NULL, NULL, NULL, okick_desc);
|
||||
|
||||
/*
|
||||
** m_okick
|
||||
** parv[1] = channel
|
||||
** parv[2] = client to kick
|
||||
** parv[3] = kick comment
|
||||
*/
|
||||
static void
|
||||
mo_okick(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[])
|
||||
{
|
||||
client::client *who;
|
||||
client::client *target_p;
|
||||
chan::chan *chptr;
|
||||
chan::membership *msptr;
|
||||
int chasing = 0;
|
||||
char *comment;
|
||||
char *name;
|
||||
char *p = NULL;
|
||||
char *user;
|
||||
static char buf[BUFSIZE];
|
||||
|
||||
if(*parv[2] == '\0')
|
||||
{
|
||||
sendto_one(&source, form_str(ERR_NEEDMOREPARAMS), me.name, source.name, "KICK");
|
||||
return;
|
||||
}
|
||||
|
||||
if(my(source) && !is_flood_done(source))
|
||||
flood_endgrace(&source);
|
||||
|
||||
comment = (EmptyString(LOCAL_COPY(parv[3]))) ? LOCAL_COPY(parv[2]) : LOCAL_COPY(parv[3]);
|
||||
if(strlen(comment) > (size_t) TOPICLEN)
|
||||
comment[TOPICLEN] = '\0';
|
||||
|
||||
*buf = '\0';
|
||||
if((p = (char *)strchr(parv[1], ',')))
|
||||
*p = '\0';
|
||||
|
||||
name = LOCAL_COPY(parv[1]);
|
||||
|
||||
chptr = chan::get(name, std::nothrow);
|
||||
if(!chptr)
|
||||
{
|
||||
sendto_one_numeric(&source, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if((p = (char *)strchr(parv[2], ',')))
|
||||
*p = '\0';
|
||||
user = LOCAL_COPY(parv[2]); // strtoken(&p2, parv[2], ",");
|
||||
if(!(who = find_chasing(&source, user, &chasing)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if((target_p = find_client(user)) == NULL)
|
||||
{
|
||||
sendto_one(&source, form_str(ERR_NOSUCHNICK), user);
|
||||
return;
|
||||
}
|
||||
|
||||
if((msptr = get(chptr->members, *target_p, std::nothrow)) == NULL)
|
||||
{
|
||||
sendto_one(&source, form_str(ERR_USERNOTINCHANNEL), parv[1], parv[2]);
|
||||
return;
|
||||
}
|
||||
|
||||
sendto_wallops_flags(umode::WALLOP, &me,
|
||||
"OKICK called for %s %s by %s!%s@%s",
|
||||
chptr->name.c_str(), target_p->name,
|
||||
source.name, source.username, source.host);
|
||||
ilog(L_MAIN, "OKICK called for %s %s by %s",
|
||||
chptr->name.c_str(), target_p->name,
|
||||
get_oper_name(&source));
|
||||
/* only sends stuff for #channels remotely */
|
||||
sendto_server(NULL, chptr, NOCAPS, NOCAPS,
|
||||
":%s WALLOPS :OKICK called for %s %s by %s!%s@%s",
|
||||
me.name, chptr->name.c_str(), target_p->name,
|
||||
source.name, source.username, source.host);
|
||||
|
||||
sendto_channel_local(chan::ALL_MEMBERS, chptr, ":%s KICK %s %s :%s",
|
||||
me.name, chptr->name.c_str(), who->name, comment);
|
||||
sendto_server(&me, chptr, CAP_TS6, NOCAPS,
|
||||
":%s KICK %s %s :%s", me.id, chptr->name.c_str(), who->id, comment);
|
||||
|
||||
del(*chptr, *target_p);
|
||||
}
|
|
@ -1,150 +0,0 @@
|
|||
/*
|
||||
* Charybdis: an advanced Internet Relay Chat Daemon(ircd).
|
||||
* m_omode.c: allows oper mode hacking
|
||||
*
|
||||
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
|
||||
* Copyright (C) 1996-2002 Hybrid Development Team
|
||||
* Copyright (C) 2002-2004 ircd-ratbox development team
|
||||
* Copyright (C) 2006 Charybdis 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char omode_desc[] = "Allow admins to forcibly change modes on channels with the OMODE command";
|
||||
|
||||
static void mo_omode(struct MsgBuf *, client::client &, client::client &, int, const char **);
|
||||
|
||||
struct Message omode_msgtab = {
|
||||
"OMODE", 0, 0, 0, 0,
|
||||
{mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_omode, 3}}
|
||||
};
|
||||
|
||||
mapi_clist_av1 omode_clist[] = { &omode_msgtab, NULL };
|
||||
|
||||
DECLARE_MODULE_AV2(omode, NULL, NULL, omode_clist, NULL, NULL, NULL, NULL, omode_desc);
|
||||
|
||||
/*
|
||||
* mo_omode - MODE command handler
|
||||
* parv[1] - channel
|
||||
*/
|
||||
static void
|
||||
mo_omode(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[])
|
||||
{
|
||||
chan::chan *chptr = NULL;
|
||||
chan::membership *msptr;
|
||||
char params[512];
|
||||
int i;
|
||||
int wasonchannel;
|
||||
|
||||
/* admins only */
|
||||
if(!IsOperAdmin(&source))
|
||||
{
|
||||
sendto_one(&source, form_str(ERR_NOPRIVS), me.name, source.name, "admin");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now, try to find the channel in question */
|
||||
if(!rfc1459::is_chan_prefix(parv[1][0]) || !chan::valid_name(parv[1]))
|
||||
{
|
||||
sendto_one_numeric(&source, ERR_BADCHANNAME,
|
||||
form_str(ERR_BADCHANNAME), parv[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
chptr = chan::get(parv[1], std::nothrow);
|
||||
|
||||
if(chptr == NULL)
|
||||
{
|
||||
sendto_one_numeric(&source, ERR_NOSUCHCHANNEL,
|
||||
form_str(ERR_NOSUCHCHANNEL), parv[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now know the channel exists */
|
||||
msptr = get(chptr->members, source, std::nothrow);
|
||||
wasonchannel = msptr != NULL;
|
||||
|
||||
if (is_chanop(msptr))
|
||||
{
|
||||
sendto_one_notice(&source, ":Use a normal MODE you idiot");
|
||||
return;
|
||||
}
|
||||
|
||||
params[0] = '\0';
|
||||
for (i = 2; i < parc; i++)
|
||||
{
|
||||
if (i != 2)
|
||||
rb_strlcat(params, " ", sizeof params);
|
||||
rb_strlcat(params, parv[i], sizeof params);
|
||||
}
|
||||
|
||||
sendto_wallops_flags(umode::WALLOP, &me,
|
||||
"OMODE called for [%s] [%s] by %s!%s@%s",
|
||||
parv[1], params, source.name, source.username, source.host);
|
||||
ilog(L_MAIN, "OMODE called for [%s] [%s] by %s",
|
||||
parv[1], params, get_oper_name(&source));
|
||||
|
||||
if(chptr->name[0] != '&')
|
||||
sendto_server(NULL, NULL, NOCAPS, NOCAPS,
|
||||
":%s WALLOPS :OMODE called for [%s] [%s] by %s!%s@%s",
|
||||
me.name, parv[1], params, source.name, source.username,
|
||||
source.host);
|
||||
|
||||
#if 0
|
||||
set_channel_mode(&client, source.servptr, chptr, msptr,
|
||||
parc - 2, parv + 2);
|
||||
#else
|
||||
if (parc == 4 && !strcmp(parv[2], "+o") && !irccmp(parv[3], source.name))
|
||||
{
|
||||
/* Opping themselves */
|
||||
if (!wasonchannel)
|
||||
{
|
||||
sendto_one_numeric(&source, ERR_USERNOTINCHANNEL,
|
||||
form_str(ERR_USERNOTINCHANNEL), parv[3], chptr->name.c_str());
|
||||
return;
|
||||
}
|
||||
sendto_channel_local(chan::ALL_MEMBERS, chptr, ":%s MODE %s +o %s",
|
||||
me.name, parv[1], source.name);
|
||||
sendto_server(NULL, chptr, CAP_TS6, NOCAPS,
|
||||
":%s TMODE %ld %s +o %s",
|
||||
me.id, (long) chptr->channelts, parv[1],
|
||||
source.id);
|
||||
msptr->flags |= chan::CHANOP;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Hack it so set_channel_mode() will accept */
|
||||
if (wasonchannel)
|
||||
msptr->flags |= chan::CHANOP;
|
||||
else
|
||||
{
|
||||
add(*chptr, source, chan::CHANOP);
|
||||
msptr = get(chptr->members, source, std::nothrow);
|
||||
}
|
||||
set_channel_mode(&client, &source, chptr, msptr,
|
||||
parc - 2, parv + 2);
|
||||
/* We know they were not opped before and they can't have opped
|
||||
* themselves as set_channel_mode() does not allow that
|
||||
* -- jilles */
|
||||
if (wasonchannel)
|
||||
msptr->flags &= ~chan::CHANOP;
|
||||
else
|
||||
del(*chptr, get_client(*msptr));
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -1,98 +0,0 @@
|
|||
/* contrib/m_opme.c
|
||||
* Copyright (C) 2002 Hybrid Development Team
|
||||
* Copyright (C) 2004 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char opme_desc[] = "Allow admins to op themselves on opless channels";
|
||||
|
||||
static void mo_opme(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[]);
|
||||
|
||||
struct Message opme_msgtab = {
|
||||
"OPME", 0, 0, 0, 0,
|
||||
{mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_opme, 2}}
|
||||
};
|
||||
|
||||
mapi_clist_av1 opme_clist[] = { &opme_msgtab, NULL };
|
||||
|
||||
DECLARE_MODULE_AV2(opme, NULL, NULL, opme_clist, NULL, NULL, NULL, NULL, opme_desc);
|
||||
|
||||
/*
|
||||
** mo_opme
|
||||
** parv[1] = channel
|
||||
*/
|
||||
static void
|
||||
mo_opme(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[])
|
||||
{
|
||||
chan::chan *chptr;
|
||||
chan::membership *msptr;
|
||||
rb_dlink_node *ptr;
|
||||
|
||||
/* admins only */
|
||||
if(!IsOperAdmin(&source))
|
||||
{
|
||||
sendto_one(&source, form_str(ERR_NOPRIVS), me.name, source.name, "admin");
|
||||
return;
|
||||
}
|
||||
|
||||
if((chptr = chan::get(parv[1], std::nothrow)) == NULL)
|
||||
{
|
||||
sendto_one_numeric(&source, ERR_NOSUCHCHANNEL,
|
||||
form_str(ERR_NOSUCHCHANNEL), parv[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
for(auto &pit : chptr->members.global)
|
||||
{
|
||||
msptr = &pit.second;
|
||||
|
||||
if(is_chanop(msptr))
|
||||
{
|
||||
sendto_one_notice(&source, ":%s Channel is not opless", parv[1]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
msptr = get(chptr->members, source, std::nothrow);
|
||||
|
||||
if(msptr == NULL)
|
||||
return;
|
||||
|
||||
msptr->flags |= chan::CHANOP;
|
||||
|
||||
sendto_wallops_flags(umode::WALLOP, &me,
|
||||
"OPME called for [%s] by %s!%s@%s",
|
||||
parv[1], source.name, source.username, source.host);
|
||||
ilog(L_MAIN, "OPME called for [%s] by %s",
|
||||
parv[1], get_oper_name(&source));
|
||||
|
||||
/* dont send stuff for local channels remotely. */
|
||||
if(chptr->name[0] != '&')
|
||||
{
|
||||
sendto_server(NULL, NULL, NOCAPS, NOCAPS,
|
||||
":%s WALLOPS :OPME called for [%s] by %s!%s@%s",
|
||||
me.name, parv[1], source.name, source.username, source.host);
|
||||
sendto_server(NULL, chptr, CAP_TS6, NOCAPS, ":%s PART %s", source.id, parv[1]);
|
||||
sendto_server(NULL, chptr, CAP_TS6, NOCAPS,
|
||||
":%s SJOIN %ld %s + :@%s",
|
||||
me.id, (long) chptr->channelts, parv[1], source.id);
|
||||
}
|
||||
|
||||
sendto_channel_local(chan::ALL_MEMBERS, chptr,
|
||||
":%s MODE %s +o %s", me.name, parv[1], source.name);
|
||||
}
|
|
@ -1,211 +0,0 @@
|
|||
/*
|
||||
* ircd-ratbox: A slightly useful ircd.
|
||||
* m_kick.c: Kicks a user from a channel.
|
||||
*
|
||||
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
|
||||
* Copyright (C) 1996-2002 Hybrid Development Team
|
||||
* Copyright (C) 2002-2005 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char description[] = "Provides the REMOVE command, an alternative to KICK";
|
||||
|
||||
static void m_remove(struct MsgBuf *, client::client &, client::client &, int, const char **);
|
||||
static void remove_quote_part(hook_data_privmsg_channel *);
|
||||
|
||||
unsigned int CAP_REMOVE;
|
||||
static char part_buf[REASONLEN + 1];
|
||||
|
||||
struct Message remove_msgtab = {
|
||||
"REMOVE", 0, 0, 0, 0,
|
||||
{mg_unreg, {m_remove, 3}, {m_remove, 3}, {m_remove, 3}, mg_ignore, {m_remove, 3}}
|
||||
};
|
||||
|
||||
mapi_clist_av1 remove_clist[] = { &remove_msgtab, NULL };
|
||||
mapi_hfn_list_av1 remove_hfnlist[] = {
|
||||
{ "privmsg_channel", (hookfn) remove_quote_part },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
mapi_cap_list_av2 remove_cap_list[] = {
|
||||
{ MAPI_CAP_SERVER, "REMOVE", NULL, &CAP_REMOVE },
|
||||
{ 0, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
DECLARE_MODULE_AV2(remove, NULL, NULL, remove_clist, NULL, remove_hfnlist, remove_cap_list, NULL, description);
|
||||
|
||||
static void
|
||||
m_remove(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[])
|
||||
{
|
||||
chan::membership *msptr;
|
||||
client::client *who;
|
||||
chan::chan *chptr;
|
||||
int chasing = 0;
|
||||
char *comment;
|
||||
const char *name;
|
||||
char *p = NULL;
|
||||
const char *user;
|
||||
static char buf[BUFSIZE];
|
||||
|
||||
if(my(source) && !is_flood_done(source))
|
||||
flood_endgrace(&source);
|
||||
|
||||
*buf = '\0';
|
||||
if((p = (char *)strchr(parv[1], ',')))
|
||||
*p = '\0';
|
||||
|
||||
name = parv[1];
|
||||
|
||||
chptr = chan::get(name, std::nothrow);
|
||||
if(chptr == NULL)
|
||||
{
|
||||
sendto_one_numeric(&source, ERR_NOSUCHCHANNEL, form_str(ERR_NOSUCHCHANNEL), name);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!is_server(source))
|
||||
{
|
||||
msptr = get(chptr->members, source, std::nothrow);
|
||||
|
||||
if((msptr == NULL) && my_connect(source))
|
||||
{
|
||||
sendto_one_numeric(&source, ERR_NOTONCHANNEL,
|
||||
form_str(ERR_NOTONCHANNEL), name);
|
||||
return;
|
||||
}
|
||||
|
||||
if(get_channel_access(&source, chptr, msptr, MODE_ADD, NULL) < chan::CHANOP)
|
||||
{
|
||||
if(my_connect(source))
|
||||
{
|
||||
sendto_one(&source, form_str(ERR_CHANOPRIVSNEEDED),
|
||||
me.name, source.name, name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If its a TS 0 channel, do it the old way */
|
||||
if(chptr->channelts == 0)
|
||||
{
|
||||
sendto_one(&source, form_str(ERR_CHANOPRIVSNEEDED),
|
||||
get_id(&me, &source), get_id(&source, &source), name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Its a user doing a kick, but is not showing as chanop locally
|
||||
* its also not a user ON -my- server, and the channel has a TS.
|
||||
* There are two cases we can get to this point then...
|
||||
*
|
||||
* 1) connect burst is happening, and for some reason a legit
|
||||
* op has sent a KICK, but the SJOIN hasn't happened yet or
|
||||
* been seen. (who knows.. due to lag...)
|
||||
*
|
||||
* 2) The channel is desynced. That can STILL happen with TS
|
||||
*
|
||||
* Now, the old code roger wrote, would allow the KICK to
|
||||
* go through. Thats quite legit, but lets weird things like
|
||||
* KICKS by users who appear not to be chanopped happen,
|
||||
* or even neater, they appear not to be on the channel.
|
||||
* This fits every definition of a desync, doesn't it? ;-)
|
||||
* So I will allow the KICK, otherwise, things are MUCH worse.
|
||||
* But I will warn it as a possible desync.
|
||||
*
|
||||
* -Dianora
|
||||
*/
|
||||
}
|
||||
|
||||
if((p = (char *)strchr(parv[2], ',')))
|
||||
*p = '\0';
|
||||
|
||||
user = parv[2]; /* strtoken(&p2, parv[2], ","); */
|
||||
|
||||
if(!(who = find_chasing(&source, user, &chasing)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
msptr = get(chptr->members, *who, std::nothrow);
|
||||
|
||||
if(msptr != NULL)
|
||||
{
|
||||
if(my(source) && is(*who, umode::SERVICE))
|
||||
{
|
||||
sendto_one(&source, form_str(ERR_ISCHANSERVICE),
|
||||
me.name, source.name, who->name, chptr->name.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(my(source))
|
||||
{
|
||||
hook_data_channel_approval hookdata;
|
||||
|
||||
hookdata.client = &source;
|
||||
hookdata.chptr = chptr;
|
||||
hookdata.msptr = msptr;
|
||||
hookdata.target = who;
|
||||
hookdata.approved = 1;
|
||||
hookdata.dir = MODE_ADD; /* ensure modules like override speak up */
|
||||
|
||||
call_hook(h_can_kick, &hookdata);
|
||||
|
||||
if (!hookdata.approved)
|
||||
return;
|
||||
}
|
||||
|
||||
comment = LOCAL_COPY((EmptyString(parv[3])) ? who->name : parv[3]);
|
||||
if(strlen(comment) > (size_t) REASONLEN)
|
||||
comment[REASONLEN] = '\0';
|
||||
|
||||
/* jdc
|
||||
* - In the case of a server kicking a user (i.e. CLEARCHAN),
|
||||
* the kick should show up as coming from the server which did
|
||||
* the kick.
|
||||
* - Personally, flame and I believe that server kicks shouldn't
|
||||
* be sent anyways. Just waiting for some oper to abuse it...
|
||||
*/
|
||||
sendto_channel_local(chan::ALL_MEMBERS, chptr,
|
||||
":%s!%s@%s PART %s :requested by %s (%s)",
|
||||
who->name, who->username,
|
||||
who->host, name, source.name, comment);
|
||||
|
||||
sendto_server(&client, chptr, CAP_REMOVE, NOCAPS,
|
||||
":%s REMOVE %s %s :%s",
|
||||
use_id(&source), chptr->name.c_str(), use_id(who), comment);
|
||||
sendto_server(&client, chptr, NOCAPS, CAP_REMOVE,
|
||||
":%s KICK %s %s :%s",
|
||||
use_id(&source), chptr->name.c_str(), use_id(who), comment);
|
||||
|
||||
del(*chptr, get_client(*msptr));
|
||||
}
|
||||
else if (my(source))
|
||||
sendto_one_numeric(&source, ERR_USERNOTINCHANNEL,
|
||||
form_str(ERR_USERNOTINCHANNEL), user, name);
|
||||
}
|
||||
|
||||
static void
|
||||
remove_quote_part(hook_data_privmsg_channel *data)
|
||||
{
|
||||
if (data->approved || EmptyString(data->text) || data->msgtype != MESSAGE_TYPE_PART)
|
||||
return;
|
||||
|
||||
rb_strlcpy(part_buf, "\"", sizeof(part_buf) - 1);
|
||||
rb_strlcat(part_buf, data->text, sizeof(part_buf) - 1);
|
||||
rb_strlcat(part_buf, "\"", sizeof(part_buf));
|
||||
|
||||
data->text = part_buf;
|
||||
}
|
|
@ -1,210 +0,0 @@
|
|||
/*
|
||||
* roleplay commands for charybdis.
|
||||
*
|
||||
* adds NPC, NPCA, and SCENE which allow users to send messages from 'fake'
|
||||
* nicknames. in the case of NPC and NPCA, the nickname will be underlined
|
||||
* to clearly show that it is fake. SCENE is a special case and not underlined.
|
||||
* these commands only work on channels set +N
|
||||
*
|
||||
* also adds oper commands FSAY and FACTION, which are like NPC and NPCA
|
||||
* except without the underline.
|
||||
*
|
||||
* all of these messages have the hostmask npc.fakeuser.invalid, and their ident
|
||||
* is the nickname of the user running the commands.
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char roleplay_desc[] =
|
||||
"Adds a roleplaying system that allows faked nicknames to talk in a channel set +N";
|
||||
|
||||
static void m_scene(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[]);
|
||||
static void m_fsay(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[]);
|
||||
static void m_faction(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[]);
|
||||
static void m_npc(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[]);
|
||||
static void m_npca(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[]);
|
||||
static void m_displaymsg(struct MsgBuf *msgbuf_p, client::client &source, const char *channel, int underline, int action, const char *nick, const char *text);
|
||||
static void me_roleplay(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[]);
|
||||
static unsigned int mymode;
|
||||
|
||||
static int
|
||||
_modinit(void)
|
||||
{
|
||||
using namespace chan::mode;
|
||||
|
||||
/* initalize the +N cmode */
|
||||
mymode = add('N', category::D, functor::simple);
|
||||
if (mymode == 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_moddeinit(void)
|
||||
{
|
||||
/* orphan the +N cmode on modunload */
|
||||
chan::mode::orphan('N');
|
||||
}
|
||||
|
||||
|
||||
struct Message scene_msgtab = {
|
||||
"SCENE", 0, 0, 0, 0,
|
||||
{mg_unreg, {m_scene, 3}, mg_ignore, mg_ignore, mg_ignore, {m_scene, 3}}
|
||||
};
|
||||
|
||||
/* this serves as an alias for people who are used to inspircd/unreal m_roleplay */
|
||||
struct Message ambiance_msgtab = {
|
||||
"AMBIANCE", 0, 0, 0, 0,
|
||||
{mg_unreg, {m_scene, 3}, mg_ignore, mg_ignore, mg_ignore, {m_scene, 3}}
|
||||
};
|
||||
|
||||
struct Message fsay_msgtab = {
|
||||
"FSAY", 0, 0, 0, 0,
|
||||
{mg_unreg, {m_npc, 4}, mg_ignore, mg_ignore, mg_ignore, {m_fsay, 4}}
|
||||
};
|
||||
|
||||
struct Message faction_msgtab = {
|
||||
"FACTION", 0, 0, 0, 0,
|
||||
{mg_unreg, {m_npca, 4}, mg_ignore, mg_ignore, mg_ignore, {m_faction, 4}}
|
||||
};
|
||||
|
||||
struct Message npc_msgtab = {
|
||||
"NPC", 0, 0, 0, 0,
|
||||
{mg_unreg, {m_npc, 4}, mg_ignore, mg_ignore, mg_ignore, {m_npc, 4}}
|
||||
};
|
||||
|
||||
struct Message npca_msgtab = {
|
||||
"NPCA", 0, 0, 0, 0,
|
||||
{mg_unreg, {m_npca, 4}, mg_ignore, mg_ignore, mg_ignore, {m_npca, 4}}
|
||||
};
|
||||
|
||||
struct Message roleplay_msgtab = {
|
||||
"ROLEPLAY", 0, 0, 0, 0,
|
||||
{mg_ignore, mg_ignore, mg_ignore, mg_ignore, {me_roleplay, 4}, mg_ignore}
|
||||
};
|
||||
|
||||
mapi_clist_av1 roleplay_clist[] = { &scene_msgtab, &ambiance_msgtab, &fsay_msgtab, &faction_msgtab, &npc_msgtab, &npca_msgtab, &roleplay_msgtab, NULL };
|
||||
|
||||
DECLARE_MODULE_AV2(roleplay, _modinit, _moddeinit, roleplay_clist, NULL, NULL, NULL, NULL, roleplay_desc);
|
||||
|
||||
static void
|
||||
m_scene(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[])
|
||||
{
|
||||
m_displaymsg(msgbuf_p, source, parv[1], 0, 0, "=Scene=", parv[2]);
|
||||
}
|
||||
|
||||
static void
|
||||
m_fsay(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[])
|
||||
{
|
||||
m_displaymsg(msgbuf_p, source, parv[1], 0, 0, parv[2], parv[3]);
|
||||
}
|
||||
|
||||
static void
|
||||
m_faction(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[])
|
||||
{
|
||||
m_displaymsg(msgbuf_p, source, parv[1], 0, 1, parv[2], parv[3]);
|
||||
}
|
||||
|
||||
static void
|
||||
m_npc(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[])
|
||||
{
|
||||
m_displaymsg(msgbuf_p, source, parv[1], 1, 0, parv[2], parv[3]);
|
||||
}
|
||||
|
||||
static void
|
||||
m_npca(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[])
|
||||
{
|
||||
m_displaymsg(msgbuf_p, source, parv[1], 1, 1, parv[2], parv[3]);
|
||||
}
|
||||
|
||||
static void
|
||||
m_displaymsg(struct MsgBuf *msgbuf_p, client::client &source, const char *channel, int underline, int action, const char *nick, const char *text)
|
||||
{
|
||||
chan::chan *chptr;
|
||||
chan::membership *msptr;
|
||||
char nick2[NICKLEN+1];
|
||||
char nick3[NICKLEN+1];
|
||||
char text3[BUFSIZE];
|
||||
char text2[BUFSIZE];
|
||||
|
||||
rb_strlcpy(nick3, nick, sizeof nick3);
|
||||
|
||||
if(!is_flood_done(source))
|
||||
flood_endgrace(&source);
|
||||
|
||||
if((chptr = chan::get(channel, std::nothrow)) == NULL)
|
||||
{
|
||||
sendto_one_numeric(&source, ERR_NOSUCHCHANNEL,
|
||||
form_str(ERR_NOSUCHCHANNEL), channel);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!(msptr = get(chptr->members, source, std::nothrow)))
|
||||
{
|
||||
sendto_one_numeric(&source, ERR_NOTONCHANNEL,
|
||||
form_str(ERR_NOTONCHANNEL), chptr->name.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(!(chptr->mode.mode & chan::mode::table['N'].type))
|
||||
{
|
||||
sendto_one_numeric(&source, 573, "%s :Roleplay commands are not enabled on this channel.", chptr->name.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(!can_send(chptr, &source, msptr))
|
||||
{
|
||||
sendto_one_numeric(&source, 573, "%s :Cannot send to channel.", chptr->name.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
/* enforce flood stuff on roleplay commands */
|
||||
if(flood_attack_channel(0, &source, chptr))
|
||||
return;
|
||||
|
||||
/* enforce target change on roleplay commands */
|
||||
if(!is_chanop(msptr) && !is_voiced(msptr) && !is(source, umode::OPER) && !tgchange::add_target(source, *chptr))
|
||||
{
|
||||
sendto_one(&source, form_str(ERR_TARGCHANGE),
|
||||
me.name, source.name, chptr->name.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if(underline)
|
||||
snprintf(nick2, sizeof(nick2), "\x1F%s\x1F", strip_unprintable(nick3));
|
||||
else
|
||||
snprintf(nick2, sizeof(nick2), "%s", strip_unprintable(nick3));
|
||||
|
||||
/* don't allow nicks to be empty after stripping
|
||||
* this prevents nastiness like fake factions, etc. */
|
||||
if(EmptyString(nick3))
|
||||
{
|
||||
sendto_one_numeric(&source, 573, "%s :No visible non-stripped characters in nick.", chptr->name.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(text3, sizeof(text3), "%s (%s)", text, source.name);
|
||||
|
||||
if(action)
|
||||
snprintf(text2, sizeof(text2), "\1ACTION %s\1", text3);
|
||||
else
|
||||
snprintf(text2, sizeof(text2), "%s", text3);
|
||||
|
||||
sendto_channel_local(chan::ALL_MEMBERS, chptr, ":%s!%s@npc.fakeuser.invalid PRIVMSG %s :%s", nick2, source.name, channel, text2);
|
||||
sendto_match_servs(&source, "*", CAP_ENCAP, NOCAPS, "ENCAP * ROLEPLAY %s %s :%s",
|
||||
channel, nick2, text2);
|
||||
}
|
||||
|
||||
static void
|
||||
me_roleplay(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[])
|
||||
{
|
||||
chan::chan *chptr;
|
||||
|
||||
/* Don't segfault if we get ROLEPLAY with an invalid channel.
|
||||
* This shouldn't happen but it's best to be on the safe side. */
|
||||
if((chptr = chan::get(parv[1], std::nothrow)) == NULL)
|
||||
return;
|
||||
|
||||
sendto_channel_local(chan::ALL_MEMBERS, chptr, ":%s!%s@npc.fakeuser.invalid PRIVMSG %s :%s", parv[2], source.name, parv[1], parv[3]);
|
||||
}
|
|
@ -1,166 +0,0 @@
|
|||
/*
|
||||
* m_sendbans.c: sends all permanent resvs and xlines to given server
|
||||
*
|
||||
* Copyright (C) 2008 Jilles Tjoelker
|
||||
* Copyright (C) 2008 charybdis 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.
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char sendbands_desc[] =
|
||||
"Adds the ability to send all permanent RESVs and XLINEs to given server";
|
||||
|
||||
static void mo_sendbans(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[]);
|
||||
|
||||
struct Message sendbans_msgtab = {
|
||||
"SENDBANS", 0, 0, 0, 0,
|
||||
{mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_sendbans, 2}}
|
||||
};
|
||||
|
||||
mapi_clist_av1 sendbans_clist[] = {
|
||||
&sendbans_msgtab,
|
||||
NULL
|
||||
};
|
||||
|
||||
DECLARE_MODULE_AV2(sendbans, NULL, NULL, sendbans_clist, NULL, NULL, NULL, NULL, sendbands_desc);
|
||||
|
||||
static const char *expand_xline(const char *mask)
|
||||
{
|
||||
static char buf[512];
|
||||
const char *p;
|
||||
char *q;
|
||||
|
||||
if (!strchr(mask, ' '))
|
||||
return mask;
|
||||
if (strlen(mask) > 250)
|
||||
return NULL;
|
||||
p = mask;
|
||||
q = buf;
|
||||
while (*p != '\0')
|
||||
{
|
||||
if (*p == ' ')
|
||||
*q++ = '\\', *q++ = 's';
|
||||
else
|
||||
*q++ = *p;
|
||||
p++;
|
||||
}
|
||||
*q = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void
|
||||
mo_sendbans(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[])
|
||||
{
|
||||
struct ConfItem *aconf;
|
||||
rb_dlink_node *ptr;
|
||||
int count;
|
||||
const char *target, *mask2;
|
||||
client::client *server_p;
|
||||
struct rb_radixtree_iteration_state state;
|
||||
|
||||
if (!IsOperRemoteBan(&source))
|
||||
{
|
||||
sendto_one(&source, form_str(ERR_NOPRIVS),
|
||||
me.name, source.name, "remoteban");
|
||||
return;
|
||||
}
|
||||
if (!IsOperXline(&source))
|
||||
{
|
||||
sendto_one(&source, form_str(ERR_NOPRIVS),
|
||||
me.name, source.name, "xline");
|
||||
return;
|
||||
}
|
||||
if (!IsOperResv(&source))
|
||||
{
|
||||
sendto_one(&source, form_str(ERR_NOPRIVS),
|
||||
me.name, source.name, "resv");
|
||||
return;
|
||||
}
|
||||
|
||||
target = parv[1];
|
||||
count = 0;
|
||||
RB_DLINK_FOREACH(ptr, global_serv_list.head)
|
||||
{
|
||||
server_p = (client::client *)ptr->data;
|
||||
if (is_me(*server_p))
|
||||
continue;
|
||||
if (match(target, server_p->name))
|
||||
count++;
|
||||
}
|
||||
if (count == 0)
|
||||
{
|
||||
sendto_one_numeric(&source, ERR_NOSUCHSERVER,
|
||||
form_str(ERR_NOSUCHSERVER), target);
|
||||
return;
|
||||
}
|
||||
|
||||
sendto_realops_snomask(sno::GENERAL, L_NETWIDE,
|
||||
"%s!%s@%s is sending resvs and xlines to %s",
|
||||
source.name, source.username, source.host,
|
||||
target);
|
||||
|
||||
RB_DLINK_FOREACH(ptr, resv_conf_list.head)
|
||||
{
|
||||
aconf = (ConfItem *)ptr->data;
|
||||
if (aconf->hold)
|
||||
continue;
|
||||
sendto_match_servs(&source, target,
|
||||
CAP_ENCAP, NOCAPS,
|
||||
"ENCAP %s RESV 0 %s 0 :%s",
|
||||
target, aconf->host, aconf->passwd);
|
||||
}
|
||||
|
||||
void *elem;
|
||||
RB_RADIXTREE_FOREACH(elem, &state, resv_tree)
|
||||
{
|
||||
aconf = (ConfItem *)elem;
|
||||
if (aconf->hold)
|
||||
continue;
|
||||
sendto_match_servs(&source, target,
|
||||
CAP_ENCAP, NOCAPS,
|
||||
"ENCAP %s RESV 0 %s 0 :%s",
|
||||
target, aconf->host, aconf->passwd);
|
||||
}
|
||||
|
||||
RB_DLINK_FOREACH(ptr, xline_conf_list.head)
|
||||
{
|
||||
aconf = (ConfItem *)ptr->data;
|
||||
if (aconf->hold)
|
||||
continue;
|
||||
mask2 = expand_xline(aconf->host);
|
||||
if (mask2 == NULL)
|
||||
{
|
||||
sendto_one_notice(&source, ":Skipping xline [%s]",
|
||||
aconf->host);
|
||||
continue;
|
||||
}
|
||||
sendto_match_servs(&source, target,
|
||||
CAP_ENCAP, NOCAPS,
|
||||
"ENCAP %s XLINE 0 %s 2 :%s",
|
||||
target, mask2, aconf->passwd);
|
||||
}
|
||||
}
|
|
@ -1,145 +0,0 @@
|
|||
/*
|
||||
* ircd-ratbox: A slightly useful ircd.
|
||||
* m_webirc.c: Makes CGI:IRC users appear as coming from their real host
|
||||
*
|
||||
* Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
|
||||
* Copyright (C) 1996-2002 Hybrid Development Team
|
||||
* Copyright (C) 2002-2006 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
/* Usage:
|
||||
* auth {
|
||||
* user = "webirc@<cgiirc ip>"; # if identd used, put ident username instead
|
||||
* password = "<password>"; # encryption possible
|
||||
* spoof = "webirc."
|
||||
* class = "users";
|
||||
* };
|
||||
* Possible flags:
|
||||
* encrypted - password is encrypted (recommended)
|
||||
* kline_exempt - klines on the cgiirc ip are ignored
|
||||
* dlines are checked on the cgiirc ip (of course).
|
||||
* k/d/x lines, auth blocks, user limits, etc are checked using the
|
||||
* real host/ip.
|
||||
* The password should be specified unencrypted in webirc_password in
|
||||
* cgiirc.config
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char webirc_desc[] = "Adds support for the WebIRC system";
|
||||
|
||||
static void mr_webirc(struct MsgBuf *, client::client &, client::client &, int, const char **);
|
||||
|
||||
struct Message webirc_msgtab = {
|
||||
"WEBIRC", 0, 0, 0, 0,
|
||||
{{mr_webirc, 5}, mg_reg, mg_ignore, mg_ignore, mg_ignore, mg_reg}
|
||||
};
|
||||
|
||||
mapi_clist_av1 webirc_clist[] = { &webirc_msgtab, NULL };
|
||||
|
||||
DECLARE_MODULE_AV2(webirc, NULL, NULL, webirc_clist, NULL, NULL, NULL, NULL, webirc_desc);
|
||||
|
||||
/*
|
||||
* mr_webirc - webirc message handler
|
||||
* parv[1] = password
|
||||
* parv[2] = fake username (we ignore this)
|
||||
* parv[3] = fake hostname
|
||||
* parv[4] = fake ip
|
||||
*/
|
||||
static void
|
||||
mr_webirc(struct MsgBuf *msgbuf_p, client::client &client, client::client &source, int parc, const char *parv[])
|
||||
{
|
||||
struct ConfItem *aconf;
|
||||
const char *encr;
|
||||
struct rb_sockaddr_storage addr;
|
||||
|
||||
if ((!strchr(parv[4], '.') && !strchr(parv[4], ':')) ||
|
||||
strlen(parv[4]) + (*parv[4] == ':') >=
|
||||
sizeof(source.sockhost))
|
||||
{
|
||||
sendto_one(&source, "NOTICE * :Invalid IP");
|
||||
return;
|
||||
}
|
||||
|
||||
aconf = find_address_conf(client.host, client.sockhost,
|
||||
is_got_id(client) ? client.username : "webirc",
|
||||
is_got_id(client) ? client.username : "webirc",
|
||||
(struct sockaddr *) &client.localClient->ip,
|
||||
GET_SS_FAMILY(&client.localClient->ip), NULL);
|
||||
if (aconf == NULL || !(aconf->status & CONF_CLIENT))
|
||||
return;
|
||||
if (!IsConfDoSpoofIp(aconf) || irccmp(aconf->info.name, "webirc."))
|
||||
{
|
||||
/* XXX */
|
||||
sendto_one(&source, "NOTICE * :Not a CGI:IRC auth block");
|
||||
return;
|
||||
}
|
||||
if (EmptyString(aconf->passwd))
|
||||
{
|
||||
sendto_one(&source, "NOTICE * :CGI:IRC auth blocks must have a password");
|
||||
return;
|
||||
}
|
||||
|
||||
if (EmptyString(parv[1]))
|
||||
encr = "";
|
||||
else if (IsConfEncrypted(aconf))
|
||||
encr = rb_crypt(parv[1], aconf->passwd);
|
||||
else
|
||||
encr = parv[1];
|
||||
|
||||
if (encr == NULL || strcmp(encr, aconf->passwd))
|
||||
{
|
||||
sendto_one(&source, "NOTICE * :CGI:IRC password incorrect");
|
||||
return;
|
||||
}
|
||||
|
||||
if (rb_inet_pton_sock(parv[4], (struct sockaddr *)&addr) <= 0)
|
||||
{
|
||||
sendto_one(&source, "NOTICE * :Invalid IP");
|
||||
return;
|
||||
}
|
||||
|
||||
if (*parv[4] == ':')
|
||||
{
|
||||
source.sockhost[0] = '0';
|
||||
rb_strlcpy(source.sockhost + 1, parv[4],
|
||||
sizeof(source.sockhost) - 1);
|
||||
}
|
||||
else
|
||||
rb_strlcpy(source.sockhost, parv[4],
|
||||
sizeof(source.sockhost));
|
||||
|
||||
if(strlen(parv[3]) <= HOSTLEN)
|
||||
rb_strlcpy(source.host, parv[3], sizeof(source.host));
|
||||
else
|
||||
rb_strlcpy(source.host, source.sockhost, sizeof(source.host));
|
||||
|
||||
source.localClient->ip = addr;
|
||||
|
||||
/* Check dlines now, klines will be checked on registration */
|
||||
if((aconf = find_dline((struct sockaddr *)&source.localClient->ip,
|
||||
GET_SS_FAMILY(&source.localClient->ip))))
|
||||
{
|
||||
if(!(aconf->status & CONF_EXEMPTDLINE))
|
||||
{
|
||||
exit_client(&client, &source, &me, "D-lined");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
sendto_one(&source, "NOTICE * :CGI:IRC host/IP set to %s %s", parv[3], parv[4]);
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* Stop services kills
|
||||
* Well, it won't stop them all, unless this is loaded on all servers.
|
||||
*
|
||||
* Copyright (C) 2013 Elizabeth Myers. All rights reserved.
|
||||
* Licensed under the WTFPLv2
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char nokill_desc[] = "Prevents operators from killing services";
|
||||
|
||||
static void block_services_kill(void *data);
|
||||
|
||||
mapi_hfn_list_av1 no_kill_services_hfnlist[] = {
|
||||
{ "can_kill", (hookfn) block_services_kill },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
block_services_kill(void *vdata)
|
||||
{
|
||||
hook_data_client_approval *data = (hook_data_client_approval *) vdata;
|
||||
|
||||
if (!my(*data->client))
|
||||
return;
|
||||
|
||||
if (!data->approved)
|
||||
return;
|
||||
|
||||
if (is(*data->target, umode::SERVICE))
|
||||
{
|
||||
sendto_one_numeric(data->client, ERR_ISCHANSERVICE,
|
||||
"KILL %s :Cannot kill a network service",
|
||||
data->target->name);
|
||||
data->approved = 0;
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_MODULE_AV2(no_kill_services, NULL, NULL, NULL, NULL,
|
||||
no_kill_services_hfnlist, NULL, NULL, nokill_desc);
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* Disable LOCOPS (by disallowing any local user setting +l).
|
||||
* -- jilles
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char no_locops_desc[] = "Disables local operators";
|
||||
|
||||
static void h_nl_umode_changed(hook_data_umode_changed *);
|
||||
|
||||
mapi_hfn_list_av1 nl_hfnlist[] = {
|
||||
{ "umode_changed", (hookfn) h_nl_umode_changed },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
DECLARE_MODULE_AV2(no_locops, NULL, NULL, NULL, NULL, nl_hfnlist, NULL, NULL, no_locops_desc);
|
||||
|
||||
static void
|
||||
h_nl_umode_changed(hook_data_umode_changed *hdata)
|
||||
{
|
||||
client::client *source_p = hdata->client;
|
||||
|
||||
if (my(*source_p) && source_p->mode & umode::LOCOPS)
|
||||
{
|
||||
source_p->mode &= ~umode::LOCOPS;
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* Deny opers setting themselves +i unless they are bots (i.e. have
|
||||
* hidden_oper privilege).
|
||||
* -- jilles
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char noi_desc[] =
|
||||
"Disallow operators from setting user mode +i on themselves";
|
||||
|
||||
static void h_noi_umode_changed(hook_data_umode_changed *);
|
||||
|
||||
mapi_hfn_list_av1 noi_hfnlist[] = {
|
||||
{ "umode_changed", (hookfn) h_noi_umode_changed },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
DECLARE_MODULE_AV2(no_oper_invis, NULL, NULL, NULL, NULL, noi_hfnlist, NULL, NULL, noi_desc);
|
||||
|
||||
static void
|
||||
h_noi_umode_changed(hook_data_umode_changed *hdata)
|
||||
{
|
||||
client::client *source_p = hdata->client;
|
||||
|
||||
if (my(*source_p) && is(*source_p, umode::OPER) && !IsOperInvis(source_p) &&
|
||||
is(*source_p, umode::INVISIBLE))
|
||||
{
|
||||
clear(*source_p, umode::INVISIBLE);
|
||||
/* If they tried /umode +i, complain; do not complain
|
||||
* if they opered up while invisible -- jilles */
|
||||
if (hdata->oldumodes & umode::OPER)
|
||||
sendto_one_notice(source_p, ":*** Opers may not set themselves invisible");
|
||||
}
|
||||
}
|
|
@ -1,265 +0,0 @@
|
|||
/*
|
||||
* oper-override for charybdis.
|
||||
*
|
||||
* adds usermode +p and has a timer event that is iterated over to disable
|
||||
* usermode +p after a while...
|
||||
*
|
||||
* you need to have oper:override permission on the opers you want to be
|
||||
* able to use this extension.
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char override_desc[] =
|
||||
"Adds user mode +p, an operator-only user mode that grants temporary privileges to override anything";
|
||||
|
||||
static void check_umode_change(void *data);
|
||||
static void hack_channel_access(void *data);
|
||||
static void hack_can_join(void *data);
|
||||
static void hack_can_kick(void *data);
|
||||
static void hack_can_send(void *data);
|
||||
static void handle_client_exit(void *data);
|
||||
|
||||
mapi_hfn_list_av1 override_hfnlist[] = {
|
||||
{ "umode_changed", (hookfn) check_umode_change },
|
||||
{ "get_channel_access", (hookfn) hack_channel_access },
|
||||
{ "can_join", (hookfn) hack_can_join },
|
||||
{ "can_kick", (hookfn) hack_can_kick },
|
||||
{ "can_send", (hookfn) hack_can_send },
|
||||
{ "client_exit", (hookfn) handle_client_exit },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
umode::mode UMODE_OVERRIDE { 'p' };
|
||||
|
||||
#define CHFL_OVERRIDE 0x0004
|
||||
#define IsOperOverride(x) (HasPrivilege((x), "oper:override"))
|
||||
|
||||
struct OverrideSession {
|
||||
rb_dlink_node node;
|
||||
|
||||
client::client *client;
|
||||
time_t deadline;
|
||||
};
|
||||
|
||||
rb_dlink_list overriding_opers = { NULL, NULL, 0 };
|
||||
|
||||
static void
|
||||
update_session_deadline(client::client *source_p, struct OverrideSession *session_p)
|
||||
{
|
||||
if (session_p == NULL)
|
||||
{
|
||||
rb_dlink_node *n;
|
||||
|
||||
RB_DLINK_FOREACH(n, overriding_opers.head)
|
||||
{
|
||||
struct OverrideSession *s = (OverrideSession *)n->data;
|
||||
|
||||
if (s->client == source_p)
|
||||
{
|
||||
session_p = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (session_p == NULL)
|
||||
{
|
||||
session_p = (OverrideSession *)rb_malloc(sizeof(struct OverrideSession));
|
||||
session_p->client = source_p;
|
||||
}
|
||||
|
||||
session_p->deadline = rb_current_time() + 1800;
|
||||
|
||||
rb_dlinkDelete(&session_p->node, &overriding_opers);
|
||||
rb_dlinkAdd(session_p, &session_p->node, &overriding_opers);
|
||||
}
|
||||
|
||||
static void
|
||||
expire_override_deadlines(void *unused)
|
||||
{
|
||||
rb_dlink_node *n, *tn;
|
||||
|
||||
RB_DLINK_FOREACH_SAFE(n, tn, overriding_opers.head)
|
||||
{
|
||||
struct OverrideSession *session_p = (OverrideSession *)n->data;
|
||||
|
||||
if (session_p->deadline > rb_current_time())
|
||||
break;
|
||||
else if (session_p->deadline < rb_current_time())
|
||||
{
|
||||
const char *parv[4] = {session_p->client->name, session_p->client->name, "-p", NULL};
|
||||
user_mode(session_p->client, session_p->client, 3, parv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
check_umode_change(void *vdata)
|
||||
{
|
||||
hook_data_umode_changed *data = (hook_data_umode_changed *)vdata;
|
||||
client::client *source_p = data->client;
|
||||
|
||||
if (!my(*source_p))
|
||||
return;
|
||||
|
||||
if (data->oldumodes & umode::OPER && !is(*source_p, umode::OPER))
|
||||
source_p->mode &= ~UMODE_OVERRIDE;
|
||||
|
||||
/* didn't change +p umode, we don't need to do anything */
|
||||
if (!((data->oldumodes ^ source_p->mode) & UMODE_OVERRIDE))
|
||||
return;
|
||||
|
||||
if (source_p->mode & UMODE_OVERRIDE)
|
||||
{
|
||||
if (!IsOperOverride(source_p))
|
||||
{
|
||||
sendto_one_notice(source_p, ":*** You need oper:override privilege for +p");
|
||||
source_p->mode &= ~UMODE_OVERRIDE;
|
||||
return;
|
||||
}
|
||||
|
||||
update_session_deadline(source_p, NULL);
|
||||
|
||||
sendto_realops_snomask(sno::GENERAL, L_NETWIDE, "%s has enabled oper-override (+p)",
|
||||
get_oper_name(source_p));
|
||||
}
|
||||
else if (!(source_p->mode & UMODE_OVERRIDE))
|
||||
{
|
||||
rb_dlink_node *n, *tn;
|
||||
|
||||
RB_DLINK_FOREACH_SAFE(n, tn, overriding_opers.head)
|
||||
{
|
||||
struct OverrideSession *session_p = (OverrideSession *)n->data;
|
||||
|
||||
if (session_p->client != source_p)
|
||||
continue;
|
||||
|
||||
sendto_realops_snomask(sno::GENERAL, L_NETWIDE, "%s has disabled oper-override (+p)",
|
||||
get_oper_name(session_p->client));
|
||||
|
||||
rb_dlinkDelete(n, &overriding_opers);
|
||||
rb_free(session_p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
hack_channel_access(void *vdata)
|
||||
{
|
||||
hook_data_channel_approval *data = (hook_data_channel_approval *) vdata;
|
||||
|
||||
if (data->dir == MODE_QUERY)
|
||||
return;
|
||||
|
||||
if (data->approved == chan::CHANOP)
|
||||
return;
|
||||
|
||||
if (data->client->mode & UMODE_OVERRIDE)
|
||||
{
|
||||
update_session_deadline(data->client, NULL);
|
||||
data->approved = CHFL_OVERRIDE;
|
||||
|
||||
/* we only want to report modehacks, which are always non-NULL */
|
||||
if (data->modestr)
|
||||
sendto_realops_snomask(sno::GENERAL, L_NETWIDE, "%s is using oper-override on %s (modehacking: %s)",
|
||||
get_oper_name(data->client), data->chptr->name.c_str(), data->modestr);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
hack_can_join(void *vdata)
|
||||
{
|
||||
hook_data_channel *data = (hook_data_channel *) vdata;
|
||||
|
||||
if (data->approved == 0)
|
||||
return;
|
||||
|
||||
if (data->client->mode & UMODE_OVERRIDE)
|
||||
{
|
||||
update_session_deadline(data->client, NULL);
|
||||
data->approved = 0;
|
||||
|
||||
sendto_realops_snomask(sno::GENERAL, L_NETWIDE, "%s is using oper-override on %s (banwalking)",
|
||||
get_oper_name(data->client), data->chptr->name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
hack_can_kick(void *vdata)
|
||||
{
|
||||
hook_data_channel_approval *data = (hook_data_channel_approval *) vdata;
|
||||
int alevel;
|
||||
|
||||
alevel = get_channel_access(data->client, data->chptr, data->msptr, data->dir, NULL);
|
||||
if (alevel != CHFL_OVERRIDE)
|
||||
return;
|
||||
|
||||
if (data->client->mode & UMODE_OVERRIDE)
|
||||
{
|
||||
update_session_deadline(data->client, NULL);
|
||||
sendto_realops_snomask(sno::GENERAL, L_NETWIDE, "%s is using oper-override on %s (KICK %s)",
|
||||
get_oper_name(data->client), data->chptr->name.c_str(), data->target->name);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
hack_can_send(void *vdata)
|
||||
{
|
||||
hook_data_channel_approval *data = (hook_data_channel_approval *) vdata;
|
||||
|
||||
if (data->dir == MODE_QUERY)
|
||||
return;
|
||||
|
||||
if (data->approved == chan::CAN_SEND_NONOP || data->approved == chan::CAN_SEND_OPV)
|
||||
return;
|
||||
|
||||
if (data->client->mode & UMODE_OVERRIDE)
|
||||
{
|
||||
data->approved = chan::CAN_SEND_NONOP;
|
||||
|
||||
if (my(*data->client))
|
||||
{
|
||||
update_session_deadline(data->client, NULL);
|
||||
sendto_realops_snomask(sno::GENERAL, L_NETWIDE, "%s is using oper-override on %s (forcing message)",
|
||||
get_oper_name(data->client), data->chptr->name.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
handle_client_exit(void *vdata)
|
||||
{
|
||||
hook_data_client_exit *data = (hook_data_client_exit *) vdata;
|
||||
rb_dlink_node *n, *tn;
|
||||
client::client *source_p = data->target;
|
||||
|
||||
RB_DLINK_FOREACH_SAFE(n, tn, overriding_opers.head)
|
||||
{
|
||||
struct OverrideSession *session_p = (OverrideSession *)n->data;
|
||||
|
||||
if (session_p->client != source_p)
|
||||
continue;
|
||||
|
||||
rb_dlinkDelete(n, &overriding_opers);
|
||||
rb_free(session_p);
|
||||
}
|
||||
}
|
||||
|
||||
struct ev_entry *expire_override_deadlines_ev = NULL;
|
||||
|
||||
static int
|
||||
_modinit(void)
|
||||
{
|
||||
expire_override_deadlines_ev = rb_event_add("expire_override_deadlines", expire_override_deadlines, NULL, 60);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_moddeinit(void)
|
||||
{
|
||||
rb_event_delete(expire_override_deadlines_ev);
|
||||
}
|
||||
|
||||
DECLARE_MODULE_AV2(override, _modinit, _moddeinit, NULL, NULL,
|
||||
override_hfnlist, NULL, NULL, override_desc);
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
* restrict unauthenticated users from doing anything as channel op
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char restrict_desc[] =
|
||||
"Restrict unautenticated users from doing anything as channel ops";
|
||||
|
||||
static void hack_channel_access(void *data);
|
||||
|
||||
mapi_hfn_list_av1 restrict_unauthenticated_hfnlist[] = {
|
||||
{ "get_channel_access", (hookfn) hack_channel_access },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
hack_channel_access(void *vdata)
|
||||
{
|
||||
hook_data_channel_approval *data = (hook_data_channel_approval *) vdata;
|
||||
|
||||
if (!my(*data->client))
|
||||
return;
|
||||
|
||||
if (suser(user(*data->client)).empty())
|
||||
data->approved = 0;
|
||||
}
|
||||
|
||||
DECLARE_MODULE_AV2(restrict_unauthenticated, NULL, NULL, NULL, NULL,
|
||||
restrict_unauthenticated_hfnlist, NULL, NULL, restrict_desc);
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* Channel creation notices
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char sno_desc[] =
|
||||
"Adds server notice mask +l that allows operators to receive channel creation notices";
|
||||
|
||||
static int _modinit(void);
|
||||
static void h_scc_channel_join(void *);
|
||||
|
||||
mapi_hfn_list_av1 scc_hfnlist[] = {
|
||||
{ "channel_join", (hookfn) h_scc_channel_join },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
sno::mode SNO_CHANNELCREATE { 'l' };
|
||||
|
||||
DECLARE_MODULE_AV2(sno_channelcreate, _modinit, nullptr, NULL, NULL, scc_hfnlist, NULL, NULL, sno_desc);
|
||||
|
||||
static int
|
||||
_modinit(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
h_scc_channel_join(void *vdata)
|
||||
{
|
||||
hook_data_channel_activity *data = (hook_data_channel_activity *)vdata;
|
||||
const auto chptr(data->chptr);
|
||||
client::client *source_p = data->client;
|
||||
|
||||
/* If they just joined a channel, and it only has one member, then they just created it. */
|
||||
if(size(chptr->members) == 1 && is_chanop(get(chptr->members, *source_p, std::nothrow)))
|
||||
{
|
||||
sendto_realops_snomask(SNO_CHANNELCREATE, L_NETWIDE, "%s is creating new channel %s",
|
||||
source_p->name, chptr->name.c_str());
|
||||
}
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
* Remote client connect/exit notices on snomask +F (far).
|
||||
* To avoid flooding, connects/exits part of netjoins/netsplits are not shown.
|
||||
* Consequently, it is not possible to use these notices to keep track
|
||||
* of all clients.
|
||||
* -- jilles
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char sno_desc[] =
|
||||
"Adds server notice mask +F that allows operators to receive notices for connections on other servers";
|
||||
|
||||
static int _modinit(void);
|
||||
static void _moddeinit(void);
|
||||
static void h_gcn_new_remote_user(client::client *);
|
||||
static void h_gcn_client_exit(hook_data_client_exit *);
|
||||
|
||||
mapi_hfn_list_av1 gcn_hfnlist[] = {
|
||||
{ "new_remote_user", (hookfn) h_gcn_new_remote_user },
|
||||
{ "client_exit", (hookfn) h_gcn_client_exit },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
sno::mode SNO_FARCONNECT { 'F' };
|
||||
|
||||
DECLARE_MODULE_AV2(globalconnexit, _modinit, nullptr, NULL, NULL, gcn_hfnlist, NULL, NULL, sno_desc);
|
||||
|
||||
static int
|
||||
_modinit(void)
|
||||
{
|
||||
/* show the fact that we are showing user information in /version */
|
||||
opers_see_all_users = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
h_gcn_new_remote_user(client::client *source_p)
|
||||
{
|
||||
|
||||
if (!has_sent_eob(*source_p->servptr))
|
||||
return;
|
||||
sendto_realops_snomask_from(SNO_FARCONNECT, L_ALL, source_p->servptr,
|
||||
"Client connecting: %s (%s@%s) [%s] {%s} [%s]",
|
||||
source_p->name, source_p->username, source_p->orighost,
|
||||
show_ip(NULL, source_p) ? source_p->sockhost : "255.255.255.255",
|
||||
"?", source_p->info);
|
||||
}
|
||||
|
||||
static void
|
||||
h_gcn_client_exit(hook_data_client_exit *hdata)
|
||||
{
|
||||
client::client *source_p;
|
||||
|
||||
source_p = hdata->target;
|
||||
|
||||
if (my_connect(*source_p) || !is_client(*source_p))
|
||||
return;
|
||||
if (!has_sent_eob(*source_p->servptr))
|
||||
return;
|
||||
sendto_realops_snomask_from(SNO_FARCONNECT, L_ALL, source_p->servptr,
|
||||
"Client exiting: %s (%s@%s) [%s] [%s]",
|
||||
source_p->name,
|
||||
source_p->username, source_p->host, hdata->comment,
|
||||
show_ip(NULL, source_p) ? source_p->sockhost : "255.255.255.255");
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* Shows notices if remote clients exit with "Bad user info" or
|
||||
* ConfigFileEntry.kline_reason.
|
||||
* Assumes client_exit is enabled so users can't fake these reasons,
|
||||
* and kline_reason is enabled and the same everywhere.
|
||||
* Yes, this is a hack, but it is simple and avoids sending
|
||||
* more data across servers -- jilles
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char sno_desc[] =
|
||||
"Adds server notices for global XLINEs, KLINEs, and DLINEs";
|
||||
|
||||
static void h_gla_client_exit(hook_data_client_exit *);
|
||||
|
||||
mapi_hfn_list_av1 gla_hfnlist[] = {
|
||||
{ "client_exit", (hookfn) h_gla_client_exit },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
DECLARE_MODULE_AV2(globallineactive, NULL, NULL, NULL, NULL, gla_hfnlist, NULL, NULL, sno_desc);
|
||||
|
||||
static void
|
||||
h_gla_client_exit(hook_data_client_exit *hdata)
|
||||
{
|
||||
client::client *source_p;
|
||||
|
||||
source_p = hdata->target;
|
||||
|
||||
if (my_connect(*source_p) || !is_client(*source_p))
|
||||
return;
|
||||
if (!strcmp(hdata->comment, "Bad user info"))
|
||||
{
|
||||
sendto_realops_snomask_from(sno::GENERAL, L_ALL, source_p->servptr,
|
||||
"XLINE active for %s[%s@%s]",
|
||||
source_p->name, source_p->username, source_p->host);
|
||||
}
|
||||
else if (ConfigFileEntry.kline_reason != NULL &&
|
||||
!strcmp(hdata->comment, ConfigFileEntry.kline_reason))
|
||||
{
|
||||
sendto_realops_snomask_from(sno::GENERAL, L_ALL, source_p->servptr,
|
||||
"K/DLINE active for %s[%s@%s]",
|
||||
source_p->name, source_p->username, source_p->host);
|
||||
}
|
||||
else if (!strncmp(hdata->comment, "Temporary K-line ", 17))
|
||||
{
|
||||
sendto_realops_snomask_from(sno::GENERAL, L_ALL, source_p->servptr,
|
||||
"K/DLINE active for %s[%s@%s]",
|
||||
source_p->name, source_p->username, source_p->host);
|
||||
}
|
||||
else if (!strncmp(hdata->comment, "Temporary D-line ", 17))
|
||||
{
|
||||
sendto_realops_snomask_from(sno::GENERAL, L_ALL, source_p->servptr,
|
||||
"K/DLINE active for %s[%s@%s]",
|
||||
source_p->name, source_p->username, source_p->host);
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* Remote client nick change notices.
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char sno_desc[] =
|
||||
"Adds server notices for remote nick changes";
|
||||
|
||||
static int _modinit(void);
|
||||
static void h_gnc_nick_change(hook_data *data);
|
||||
|
||||
mapi_hfn_list_av1 gcn_hfnlist[] = {
|
||||
{ "remote_nick_change", (hookfn) h_gnc_nick_change },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
DECLARE_MODULE_AV2(globalnickchange, _modinit, NULL, NULL, NULL, gcn_hfnlist, NULL, NULL, sno_desc);
|
||||
|
||||
static int
|
||||
_modinit(void)
|
||||
{
|
||||
/* show the fact that we are showing user information in /version */
|
||||
opers_see_all_users = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
h_gnc_nick_change(hook_data *data)
|
||||
{
|
||||
client::client *source_p = data->client;
|
||||
const char *oldnick = (const char *)data->arg1;
|
||||
const char *newnick = (const char *)data->arg2;
|
||||
|
||||
sendto_realops_snomask_from(sno::NCHANGE, L_ALL, source_p->servptr,
|
||||
"Nick change: From %s to %s [%s@%s]",
|
||||
oldnick, newnick, source_p->username, source_p->host);
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* Remote oper up notices.
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char sno_desc[] =
|
||||
"Adds server notices for remote oper up";
|
||||
|
||||
static void h_sgo_umode_changed(void *);
|
||||
|
||||
mapi_hfn_list_av1 sgo_hfnlist[] = {
|
||||
{ "umode_changed", (hookfn) h_sgo_umode_changed },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
DECLARE_MODULE_AV2(sno_globaloper, NULL, NULL, NULL, NULL, sgo_hfnlist, NULL, NULL, sno_desc);
|
||||
|
||||
static void
|
||||
h_sgo_umode_changed(void *vdata)
|
||||
{
|
||||
hook_data_umode_changed *data = (hook_data_umode_changed *)vdata;
|
||||
client::client *source_p = data->client;
|
||||
|
||||
if (my_connect(*source_p) || !has_sent_eob(*source_p->servptr))
|
||||
return;
|
||||
|
||||
if (!(data->oldumodes & umode::OPER) && is(*source_p, umode::OPER))
|
||||
sendto_realops_snomask_from(sno::GENERAL, L_ALL, source_p->servptr,
|
||||
"%s (%s@%s) is now an operator",
|
||||
source_p->name, source_p->username, source_p->host);
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
/*
|
||||
* +W snomask: Displays if a local user has done a WHOIS request on you.
|
||||
* derived from spy_whois_notice.c.
|
||||
*
|
||||
* If #define OPERONLY is removed, then any user can use this snomask
|
||||
* (you need to put ~servnotice in oper_only_umodes for this to work).
|
||||
*/
|
||||
|
||||
/* undefine this to allow anyone to receive whois notifications */
|
||||
#define OPERONLY
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char sno_desc[] =
|
||||
"Adds server notice mask +W that allows "
|
||||
#ifdef OPERONLY
|
||||
"operators"
|
||||
#else
|
||||
"users"
|
||||
#endif
|
||||
" to receive notices for when a WHOIS has been done on them";
|
||||
|
||||
void show_whois(hook_data_client *);
|
||||
|
||||
mapi_hfn_list_av1 whois_hfnlist[] = {
|
||||
{"doing_whois", (hookfn) show_whois},
|
||||
{"doing_whois_global", (hookfn) show_whois},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
sno::mode SNO_WHOIS { 'W' };
|
||||
|
||||
static int
|
||||
init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
DECLARE_MODULE_AV2(sno_whois, init, nullptr, NULL, NULL, whois_hfnlist, NULL, NULL, sno_desc);
|
||||
|
||||
void
|
||||
show_whois(hook_data_client *data)
|
||||
{
|
||||
client::client *source_p = data->client;
|
||||
client::client *target_p = data->target;
|
||||
|
||||
if(my(*target_p) &&
|
||||
#ifdef OPERONLY
|
||||
is(*target_p, umode::OPER) &&
|
||||
#endif
|
||||
(source_p != target_p) &&
|
||||
(target_p->snomask & SNO_WHOIS))
|
||||
{
|
||||
sendto_one_notice(target_p,
|
||||
":*** Notice -- %s (%s@%s) is doing a whois on you [%s]",
|
||||
source_p->name,
|
||||
source_p->username, source_p->host,
|
||||
source_p->servptr->name);
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
/************************************************************************
|
||||
* charybdis: an advanced ircd. extensions/spamfilter.h
|
||||
* Copyright (C) 2016 Jason Volk
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define MODE_SPAMFILTER 'Y'
|
||||
#define STATCHAR_SPAMFILTER 'S'
|
File diff suppressed because it is too large
Load diff
|
@ -1,429 +0,0 @@
|
|||
/************************************************************************
|
||||
* charybdis: an advanced ircd. extensions/spamfilter_nicks.c
|
||||
* Copyright (C) 2016 Jason Volk
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "spamfilter.h"
|
||||
|
||||
using namespace ircd;
|
||||
using chan::membership;
|
||||
using chan::chan;
|
||||
|
||||
|
||||
/* Conf items & defaults */
|
||||
size_t conf_limit = 5;
|
||||
size_t conf_nicklen_min = 4;
|
||||
size_t conf_bloom_size = 1024 * 64;
|
||||
size_t conf_bloom_bits = 16;
|
||||
time_t conf_bloom_refresh = 86400;
|
||||
|
||||
|
||||
/* Bloom filter hashes */
|
||||
static
|
||||
uint64_t bloom_hash_fnv(const char *const str)
|
||||
{
|
||||
return fnv_hash_upper((const unsigned char *)str, conf_bloom_bits);
|
||||
}
|
||||
|
||||
static
|
||||
uint64_t bloom_hash_bernstein(const char *const str)
|
||||
{
|
||||
uint64_t ret = 7681;
|
||||
for(size_t i = 0; str[i]; i++)
|
||||
ret = ret * 33ULL + str[i];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define NUM_HASHES 2
|
||||
uint64_t (*bloom_hashes[NUM_HASHES])(const char *const str) =
|
||||
{
|
||||
bloom_hash_fnv,
|
||||
bloom_hash_bernstein,
|
||||
};
|
||||
|
||||
|
||||
/* Bloom filter state */
|
||||
uint8_t *bloom[NUM_HASHES];
|
||||
uint64_t bloom_salt;
|
||||
size_t bloom_size;
|
||||
size_t bloom_members;
|
||||
time_t bloom_flushed;
|
||||
struct rb_radixtree *chans; // Channels with MODE_SPAMFILTER that participate in the bloom filter
|
||||
|
||||
|
||||
static
|
||||
void bloom_flush(void)
|
||||
{
|
||||
for(size_t i = 0; i < NUM_HASHES; i++)
|
||||
memset(bloom[i], 0x0, bloom_size);
|
||||
|
||||
bloom_flushed = rb_current_time();
|
||||
bloom_members = 0;
|
||||
}
|
||||
|
||||
static
|
||||
void bloom_destroy(void)
|
||||
{
|
||||
for(size_t i = 0; i < NUM_HASHES; i++)
|
||||
{
|
||||
delete bloom[i];
|
||||
bloom[i] = NULL;
|
||||
}
|
||||
|
||||
bloom_members = 0;
|
||||
bloom_size = 0;
|
||||
}
|
||||
|
||||
static
|
||||
void bloom_create(const size_t size)
|
||||
{
|
||||
if(!size)
|
||||
return;
|
||||
|
||||
for(size_t i = 0; i < NUM_HASHES; i++)
|
||||
bloom[i] = new uint8_t[size];
|
||||
|
||||
bloom_size = size;
|
||||
bloom_flush();
|
||||
}
|
||||
|
||||
static
|
||||
void bloom_add(const size_t filter,
|
||||
uint64_t hash)
|
||||
{
|
||||
hash += bloom_salt;
|
||||
hash %= bloom_size * 8UL;
|
||||
bloom[filter][hash / 8UL] |= (1U << (hash % 8UL));
|
||||
}
|
||||
|
||||
static
|
||||
int bloom_test(const size_t filter,
|
||||
uint64_t hash)
|
||||
{
|
||||
hash += bloom_salt;
|
||||
hash %= bloom_size * 8UL;
|
||||
const int bit = hash % 8UL;
|
||||
return (bloom[filter][hash / 8UL] & (1U << bit)) >> bit;
|
||||
}
|
||||
|
||||
static
|
||||
void bloom_add_str(const char *const str)
|
||||
{
|
||||
for(size_t i = 0; i < NUM_HASHES; i++)
|
||||
bloom_add(i, bloom_hashes[i](str));
|
||||
|
||||
bloom_members++;
|
||||
}
|
||||
|
||||
static
|
||||
int bloom_test_str(const char *const str)
|
||||
{
|
||||
unsigned int count = 0;
|
||||
for(size_t i = 0; i < NUM_HASHES; i++)
|
||||
count += bloom_test(i, bloom_hashes[i](str));
|
||||
|
||||
return count >= NUM_HASHES;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int chans_has(const struct chan *const chptr)
|
||||
{
|
||||
return rb_radixtree_retrieve(chans, chptr->name.c_str()) != NULL;
|
||||
}
|
||||
|
||||
static
|
||||
int chans_add(struct chan *const chan)
|
||||
{
|
||||
if(!rb_radixtree_add(chans, chan->name.c_str(), chan))
|
||||
return 0;
|
||||
|
||||
for(const auto &pit : chan->members.global)
|
||||
{
|
||||
const auto &client(pit.first);
|
||||
bloom_add_str(client->name);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int expired(void)
|
||||
{
|
||||
return bloom_flushed + conf_bloom_refresh < rb_current_time();
|
||||
}
|
||||
|
||||
static
|
||||
void reset(void)
|
||||
{
|
||||
if(bloom[0])
|
||||
bloom_flush();
|
||||
|
||||
if(chans)
|
||||
rb_radixtree_destroy(chans, NULL, NULL);
|
||||
|
||||
chans = rb_radixtree_create("chans", irccasecanon);
|
||||
}
|
||||
|
||||
static
|
||||
void resize(const size_t size)
|
||||
{
|
||||
bloom_destroy();
|
||||
reset();
|
||||
bloom_create(size);
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int prob_test_token(const char *const token)
|
||||
{
|
||||
return bloom_test_str(token);
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int real_test_token(const char *const token,
|
||||
struct chan *const chan)
|
||||
{
|
||||
client::client *const client = find_named_client(token);
|
||||
return client && is_member(chan, client);
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void false_positive_message(void)
|
||||
{
|
||||
sendto_realops_snomask(sno::GENERAL, L_ALL,
|
||||
"spamfilter: Nickname bloom filter false positive (size: %zu members: %zu channels: %u flushed: %lu ago)",
|
||||
bloom_size,
|
||||
bloom_members,
|
||||
rb_radixtree_size(chans),
|
||||
rb_current_time() - bloom_flushed);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Always find the length of any multibyte character to advance past.
|
||||
* The unicode space characters of concern are only of length 3.
|
||||
*/
|
||||
static
|
||||
int is_delim(const uint8_t *const ptr,
|
||||
unsigned int *const adv)
|
||||
{
|
||||
/* Some ascii ranges */
|
||||
if((ptr[0] >= 0x20 && ptr[0] <= 0x2F) ||
|
||||
(ptr[0] >= 0x3A && ptr[0] <= 0x40) ||
|
||||
(ptr[0] >= 0x5C && ptr[0] <= 0x60) ||
|
||||
(ptr[0] >= 0x7B && ptr[0] <= 0x7F))
|
||||
return 1;
|
||||
|
||||
/* Unicode below here */
|
||||
const int len = ((ptr[0] & 0x80) == 0x80)+
|
||||
((ptr[0] & 0xC0) == 0xC0)+
|
||||
((ptr[0] & 0xE0) == 0xE0)+
|
||||
((ptr[0] & 0xF0) == 0xF0)+
|
||||
((ptr[0] & 0xF8) == 0xF8)+
|
||||
((ptr[0] & 0xFC) == 0xFC);
|
||||
|
||||
if(len)
|
||||
*adv += len - 1;
|
||||
|
||||
if(len != 3)
|
||||
return 0;
|
||||
|
||||
switch((htonl(*(const uint32_t *)ptr) & 0x1F7F7F00U) >> 8)
|
||||
{
|
||||
case 0x20000:
|
||||
case 0x20001:
|
||||
case 0x20002:
|
||||
case 0x20003:
|
||||
case 0x20004:
|
||||
case 0x20005:
|
||||
case 0x20006:
|
||||
case 0x20007:
|
||||
case 0x20008:
|
||||
case 0x20009:
|
||||
case 0x2000A:
|
||||
case 0x2000B:
|
||||
case 0x2002F:
|
||||
case 0x2005F:
|
||||
case 0x30000:
|
||||
case 0xf3b3f:
|
||||
return 1;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static unsigned int
|
||||
count_nicks(const char *const text,
|
||||
struct chan *const chan)
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
const size_t len = strlen(text);
|
||||
|
||||
for(unsigned int i = 0, j = 0, k = 0; i + 6 < len; i++)
|
||||
{
|
||||
if(!is_delim((const unsigned char *) text+i, &k))
|
||||
{
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(j >= conf_nicklen_min && j <= NICKLEN)
|
||||
{
|
||||
char token[NICKLEN+1];
|
||||
rb_strlcpy(token, text+i-j, j+1);
|
||||
if(prob_test_token(token))
|
||||
{
|
||||
if(rb_likely(real_test_token(token, chan)))
|
||||
ret++;
|
||||
else
|
||||
false_positive_message();
|
||||
}
|
||||
}
|
||||
|
||||
i += k;
|
||||
j = 0;
|
||||
k = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void hook_spamfilter_query(hook_data_privmsg_channel *const hook)
|
||||
{
|
||||
if(hook->approved != 0)
|
||||
return;
|
||||
|
||||
if(!bloom[0])
|
||||
return;
|
||||
|
||||
const unsigned int counted = count_nicks(hook->text, hook->chptr);
|
||||
if(counted < conf_limit)
|
||||
return;
|
||||
|
||||
static char reason[64];
|
||||
snprintf(reason, sizeof(reason), "nicks: counted at least %u names", counted);
|
||||
hook->reason = reason;
|
||||
hook->approved = -1;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void hook_channel_join(hook_data_channel_approval *const data)
|
||||
{
|
||||
namespace mode = ircd::chan::mode;
|
||||
|
||||
if(~data->chptr->mode.mode & mode::table[uint8_t(MODE_SPAMFILTER)].type)
|
||||
return;
|
||||
|
||||
if(!bloom[0])
|
||||
return;
|
||||
|
||||
if(expired())
|
||||
reset();
|
||||
|
||||
if(chans_has(data->chptr))
|
||||
bloom_add_str(data->client->name);
|
||||
else
|
||||
chans_add(data->chptr);
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
int conf_spamfilter_nicks_end(struct TopConf *const tc)
|
||||
{
|
||||
if(conf_bloom_size != bloom_size)
|
||||
resize(conf_bloom_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void set_conf_limit(void *const val) { conf_limit = *(int *)val; }
|
||||
static void set_conf_nicklen_min(void *const val) { conf_nicklen_min = *(int *)val; }
|
||||
static void set_conf_bloom_size(void *const val) { conf_bloom_size = *(int *)val; }
|
||||
static void set_conf_bloom_bits(void *const val) { conf_bloom_bits = *(int *)val; }
|
||||
static void set_conf_bloom_refresh(void *const val) { conf_bloom_refresh = *(time_t *)val; }
|
||||
|
||||
|
||||
struct ConfEntry conf_spamfilter_nicks[] =
|
||||
{
|
||||
{ "limit", CF_INT, set_conf_limit, 0, NULL },
|
||||
{ "nicklen_min", CF_INT, set_conf_nicklen_min, 0, NULL },
|
||||
{ "bloom_size", CF_INT, set_conf_bloom_size, 0, NULL },
|
||||
{ "bloom_bits", CF_INT, set_conf_bloom_bits, 0, NULL },
|
||||
{ "bloom_refresh", CF_TIME, set_conf_bloom_refresh, 0, NULL },
|
||||
{ "\0", 0, NULL, 0, NULL }
|
||||
};
|
||||
|
||||
|
||||
static
|
||||
int modinit(void)
|
||||
{
|
||||
add_top_conf("spamfilter_nicks", NULL, conf_spamfilter_nicks_end, conf_spamfilter_nicks);
|
||||
rb_get_random(&bloom_salt, sizeof(bloom_salt));
|
||||
resize(conf_bloom_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void modfini(void)
|
||||
{
|
||||
bloom_destroy();
|
||||
rb_radixtree_destroy(chans, NULL, NULL);
|
||||
remove_top_conf("spamfilter_nicks");
|
||||
}
|
||||
|
||||
|
||||
mapi_hfn_list_av1 hfnlist[] =
|
||||
{
|
||||
{ "spamfilter_query", (hookfn)hook_spamfilter_query },
|
||||
{ "channel_join", (hookfn)hook_channel_join },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
DECLARE_MODULE_AV1
|
||||
(
|
||||
spamfilter_nicks,
|
||||
modinit,
|
||||
modfini,
|
||||
NULL,
|
||||
NULL,
|
||||
hfnlist,
|
||||
"$Revision: 0 $"
|
||||
);
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* ircd-ratbox: A slightly useful ircd.
|
||||
* spy_admin_notice.c: Sends a notice when someone uses ADMIN.
|
||||
*
|
||||
* Copyright (C) 2002 by the past and present ircd coders, and others.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char spy_desc[] = "Sends a notice when someone uses ADMIN";
|
||||
|
||||
void show_admin(hook_data *);
|
||||
|
||||
mapi_hfn_list_av1 admin_hfnlist[] = {
|
||||
{"doing_admin", (hookfn) show_admin},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
DECLARE_MODULE_AV2(admin_spy, NULL, NULL, NULL, NULL, admin_hfnlist, NULL, NULL, spy_desc);
|
||||
|
||||
void
|
||||
show_admin(hook_data *data)
|
||||
{
|
||||
sendto_realops_snomask(sno::SPY, L_ALL,
|
||||
"admin requested by %s (%s@%s) [%s]",
|
||||
data->client->name, data->client->username,
|
||||
data->client->host, data->client->servptr->name);
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* ircd-ratbox: A slightly useful ircd.
|
||||
* spy_info_notice.c: Sends a notice when someone uses INFO.
|
||||
*
|
||||
* Copyright (C) 2002 by the past and present ircd coders, and others.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char spy_desc[] = "Sends a notice when someone uses INFO";
|
||||
|
||||
void show_info(hook_data *);
|
||||
|
||||
mapi_hfn_list_av1 info_hfnlist[] = {
|
||||
{"doing_info", (hookfn) show_info},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
DECLARE_MODULE_AV2(info_spy, NULL, NULL, NULL, NULL, info_hfnlist, NULL, NULL, spy_desc);
|
||||
|
||||
void
|
||||
show_info(hook_data *data)
|
||||
{
|
||||
sendto_realops_snomask(sno::SPY, L_ALL,
|
||||
"info requested by %s (%s@%s) [%s]",
|
||||
data->client->name, data->client->username,
|
||||
data->client->host, data->client->servptr->name);
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* ircd-ratbox: A slightly useful ircd.
|
||||
* spy_links_notice.c: Sends a notice when someone uses LINKS.
|
||||
*
|
||||
* Copyright (C) 2002 by the past and present ircd coders, and others.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char spy_desc[] = "Sends a notice when someone uses LINKS";
|
||||
|
||||
void show_links(hook_data *);
|
||||
|
||||
mapi_hfn_list_av1 links_hfnlist[] = {
|
||||
{"doing_links", (hookfn) show_links},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
DECLARE_MODULE_AV2(links_spy, NULL, NULL, NULL, NULL, links_hfnlist, NULL, NULL, spy_desc);
|
||||
|
||||
void
|
||||
show_links(hook_data *data)
|
||||
{
|
||||
const char *mask = (const char *)data->arg1;
|
||||
|
||||
sendto_realops_snomask(sno::SPY, L_ALL,
|
||||
"LINKS '%s' requested by %s (%s@%s) [%s]",
|
||||
mask, data->client->name, data->client->username,
|
||||
data->client->host, data->client->servptr->name);
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* ircd-ratbox: A slightly useful ircd.
|
||||
* spy_motd_notice.c: Sends a notice when someone uses MOTD.
|
||||
*
|
||||
* Copyright (C) 2002 by the past and present ircd coders, and others.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char spy_desc[] = "Sends a notice when someone looks at the MOTD";
|
||||
|
||||
void show_motd(hook_data *);
|
||||
|
||||
mapi_hfn_list_av1 motd_hfnlist[] = {
|
||||
{"doing_motd", (hookfn) show_motd},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
DECLARE_MODULE_AV2(motd_spy, NULL, NULL, NULL, NULL, motd_hfnlist, NULL, NULL, spy_desc);
|
||||
|
||||
void
|
||||
show_motd(hook_data *data)
|
||||
{
|
||||
sendto_realops_snomask(sno::SPY, L_ALL,
|
||||
"motd requested by %s (%s@%s) [%s]",
|
||||
data->client->name, data->client->username,
|
||||
data->client->host, data->client->servptr->name);
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
* ircd-ratbox: A slightly useful ircd.
|
||||
* spy_stats_notice.c: Sends a notice when someone uses STATS.
|
||||
*
|
||||
* Copyright (C) 2002 by the past and present ircd coders, and others.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char spy_desc[] = "Sends a notice when someone uses STATS";
|
||||
|
||||
void show_stats(hook_data_int *);
|
||||
|
||||
mapi_hfn_list_av1 stats_hfnlist[] = {
|
||||
{"doing_stats", (hookfn) show_stats},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
DECLARE_MODULE_AV2(stats_spy, NULL, NULL, NULL, NULL, stats_hfnlist, NULL, NULL, spy_desc);
|
||||
|
||||
void
|
||||
show_stats(hook_data_int *data)
|
||||
{
|
||||
char statchar = (char) data->arg2;
|
||||
|
||||
if(statchar == 'L' || statchar == 'l')
|
||||
{
|
||||
const char *name = (const char *)data->arg1;
|
||||
|
||||
if(!EmptyString(name))
|
||||
sendto_realops_snomask(sno::SPY, L_ALL,
|
||||
"STATS %c requested by %s (%s@%s) [%s] on %s",
|
||||
statchar, data->client->name,
|
||||
data->client->username,
|
||||
data->client->host,
|
||||
data->client->servptr->name, name);
|
||||
else
|
||||
sendto_realops_snomask(sno::SPY, L_ALL,
|
||||
"STATS %c requested by %s (%s@%s) [%s]",
|
||||
statchar, data->client->name,
|
||||
data->client->username,
|
||||
data->client->host, data->client->servptr->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
sendto_realops_snomask(sno::SPY, L_ALL,
|
||||
"STATS %c requested by %s (%s@%s) [%s]",
|
||||
statchar, data->client->name, data->client->username,
|
||||
data->client->host, data->client->servptr->name);
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* ircd-ratbox: A slightly useful ircd.
|
||||
* spy_stats_p_notice.c: Sends a notice when someone uses STATS p.
|
||||
*
|
||||
* Copyright (C) 2002 by the past and present ircd coders, and others.
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA
|
||||
*/
|
||||
|
||||
using namespace ircd;
|
||||
|
||||
static const char spy_desc[] = "Sends a notice when someone looks at the operator list";
|
||||
|
||||
void show_stats_p(hook_data *);
|
||||
|
||||
mapi_hfn_list_av1 stats_p_hfnlist[] = {
|
||||
{"doing_stats_p", (hookfn) show_stats_p},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
DECLARE_MODULE_AV2(stats_p_spy, NULL, NULL, NULL, NULL, stats_p_hfnlist, NULL, NULL, spy_desc);
|
||||
|
||||
void
|
||||
show_stats_p(hook_data *data)
|
||||
{
|
||||
sendto_realops_snomask(sno::SPY, L_ALL,
|
||||
"STATS p requested by %s (%s@%s) [%s]",
|
||||
data->client->name, data->client->username,
|
||||
data->client->host, data->client->servptr->name);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue