0
0
Fork 0
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:
Jason Volk 2016-11-29 07:23:38 -08:00
parent 8ee7073e5e
commit b592b69b86
408 changed files with 6634 additions and 295718 deletions

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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();
}

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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);
}

View file

@ -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__ */

View file

@ -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);
}
}

View file

@ -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__ */

View file

@ -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;
}();

View file

@ -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;
}();

View file

@ -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;
}();

View file

@ -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;
}();

View file

@ -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);
}

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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]);
}
}

View file

@ -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);
}

View file

@ -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

View file

@ -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() */

View file

@ -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");
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -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

View file

@ -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);
}

View file

@ -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"

View file

@ -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
#

View file

@ -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)

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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;
}
}

View file

@ -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);
}

View file

@ -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;
}
}

View file

@ -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);
}

View file

@ -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
);

View file

@ -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;
}
}

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -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 */

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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
*/

View file

@ -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);
}
}

View file

@ -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]);
}

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}
}

View file

@ -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]);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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
}

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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]);
}

View file

@ -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);
}
}

View file

@ -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]);
}

View file

@ -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);

View file

@ -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;
}
}

View file

@ -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");
}
}

View file

@ -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);

View file

@ -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);

View file

@ -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());
}
}

View file

@ -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");
}

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}
}

View file

@ -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

View file

@ -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 $"
);

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}
}

View file

@ -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