@@ -168,6 +168,7 @@ void
send_queued_write(struct Client *to)
{
int retlen = 0;
int want_read = 0;

/*
** Once socket is marked dead, we cannot start writing to it,
@@ -183,32 +184,14 @@ send_queued_write(struct Client *to)
{
const struct dbuf_block *first = to->connection->buf_sendq.blocks.head->data;

#ifdef HAVE_LIBCRYPTO
if (to->connection->fd.ssl)
if (tls_isusing(&to->connection->fd.ssl))
{
retlen = SSL_write(to->connection->fd.ssl, first->data + to->connection->buf_sendq.pos, first->size - to->connection->buf_sendq.pos);

/* translate openssl error codes, sigh */
if (retlen < 0)
{
switch (SSL_get_error(to->connection->fd.ssl, retlen))
{
case SSL_ERROR_WANT_READ:
return; /* retry later, don't register for write events */
case SSL_ERROR_WANT_WRITE:
errno = EWOULDBLOCK;
case SSL_ERROR_SYSCALL:
break;
case SSL_ERROR_SSL:
if (errno == EAGAIN)
break;
default:
retlen = errno = 0; /* either an SSL-specific error or EOF */
}
}
retlen = tls_write(&to->connection->fd.ssl, first->data + to->connection->buf_sendq.pos, first->size - to->connection->buf_sendq.pos, &want_read);

if (want_read)
return; /* Retry later, don't register for write events */
}
else
#endif
retlen = send(to->connection->fd.fd, first->data + to->connection->buf_sendq.pos, first->size - to->connection->buf_sendq.pos, 0);

if (retlen <= 0)
@@ -729,7 +712,7 @@ sendto_match_servs(struct Client *source_p, const char *mask, unsigned int cap,
*/
target_p->from->connection->serial = current_serial;

if (!IsCapable(target_p->from, cap))
if (cap && !IsCapable(target_p->from, cap))
continue;

send_message_remote(target_p->from, source_p, buffer);
@@ -25,10 +25,6 @@
*/

#include "stdinc.h"
#ifdef HAVE_LIBCRYPTO
#include <openssl/rsa.h>
#include "rsa.h"
#endif
#include "list.h"
#include "client.h"
#include "event.h"
@@ -758,7 +754,7 @@ serv_connect(struct MaskItem *conf, struct Client *by)
return 1;
}

#ifdef HAVE_LIBCRYPTO
#ifdef HAVE_TLS
static void
finish_ssl_server_handshake(struct Client *client_p)
{
@@ -807,84 +803,59 @@ static void
ssl_server_handshake(fde_t *fd, void *data)
{
struct Client *client_p = data;
X509 *cert = NULL;
int ret = 0;
const char *sslerr = NULL;

if ((ret = SSL_connect(client_p->connection->fd.ssl)) <= 0)
tls_handshake_status_t ret = tls_handshake(&client_p->connection->fd.ssl, TLS_ROLE_CLIENT, &sslerr);
if (ret != TLS_HANDSHAKE_DONE)
{
if ((CurrentTime - client_p->connection->firsttime) > CONNECTTIMEOUT)
{
exit_client(client_p, "Timeout during SSL handshake");
exit_client(client_p, "Timeout during TLS handshake");
return;
}

switch (SSL_get_error(client_p->connection->fd.ssl, ret))
switch (ret)
{
case SSL_ERROR_WANT_WRITE:
case TLS_HANDSHAKE_WANT_WRITE:
comm_setselect(&client_p->connection->fd, COMM_SELECT_WRITE,
ssl_server_handshake, client_p, CONNECTTIMEOUT);
return;
case SSL_ERROR_WANT_READ:
case TLS_HANDSHAKE_WANT_READ:
comm_setselect(&client_p->connection->fd, COMM_SELECT_READ,
ssl_server_handshake, client_p, CONNECTTIMEOUT);
return;
default:
{
const char *sslerr = ERR_error_string(ERR_get_error(), NULL);
sendto_realops_flags(UMODE_SERVNOTICE, L_ALL, SEND_NOTICE,
"Error connecting to %s: %s", client_p->name,
sslerr ? sslerr : "unknown SSL error");
exit_client(client_p, "Error during SSL handshake");
sslerr ? sslerr : "unknown TLS error");
exit_client(client_p, "Error during TLS handshake");
return;
}
}
}

comm_settimeout(&client_p->connection->fd, 0, NULL, NULL);

if ((cert = SSL_get_peer_certificate(client_p->connection->fd.ssl)))
{
int res = SSL_get_verify_result(client_p->connection->fd.ssl);
char buf[EVP_MAX_MD_SIZE * 2 + 1] = "";
unsigned char md[EVP_MAX_MD_SIZE] = "";

if (res == X509_V_OK || res == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN ||
res == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE ||
res == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
{
unsigned int n = 0;

if (X509_digest(cert, ConfigServerInfo.message_digest_algorithm, md, &n))
{
binary_to_hex(md, buf, n);
client_p->certfp = xstrdup(buf);
}
}
else
ilog(LOG_TYPE_IRCD, "Server %s!%s@%s gave bad SSL client certificate: %d",
client_p->name, client_p->username, client_p->host, res);
X509_free(cert);
}
if (!tls_verify_cert(&client_p->connection->fd.ssl, ConfigServerInfo.message_digest_algorithm, &client_p->certfp))
ilog(LOG_TYPE_IRCD, "Server %s!%s@%s gave bad TLS client certificate",
client_p->name, client_p->username, client_p->host);

finish_ssl_server_handshake(client_p);
}

static void
ssl_connect_init(struct Client *client_p, const struct MaskItem *conf, fde_t *fd)
{
if ((client_p->connection->fd.ssl = SSL_new(ConfigServerInfo.client_ctx)) == NULL)
if (!tls_new(&client_p->connection->fd.ssl, fd->fd, TLS_ROLE_CLIENT))
{
ilog(LOG_TYPE_IRCD, "SSL_new() ERROR! -- %s",
ERR_error_string(ERR_get_error(), NULL));
SetDead(client_p);
exit_client(client_p, "SSL_new failed");
exit_client(client_p, "TLS context initialization failed");
return;
}

SSL_set_fd(fd->ssl, fd->fd);

if (!EmptyString(conf->cipher_list))
SSL_set_cipher_list(client_p->connection->fd.ssl, conf->cipher_list);
tls_set_ciphers(&client_p->connection->fd.ssl, conf->cipher_list);

ssl_server_handshake(NULL, client_p);
}
@@ -949,7 +920,7 @@ serv_connect_callback(fde_t *fd, int status, void *data)
/* Next, send the initial handshake */
SetHandshake(client_p);

#ifdef HAVE_LIBCRYPTO
#ifdef HAVE_TLS
if (IsConfSSL(conf))
{
ssl_connect_init(client_p, conf, fd);
@@ -0,0 +1,328 @@
/*
* ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
*
* Copyright (c) 2015 Attila Molnar <attilamolnar@hush.com>
* Copyright (c) 2015 Adam <Adam@anope.org>
* Copyright (c) 2015-2016 ircd-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 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/

/*! \file tls_gnutls.c
* \brief Includes all GnuTLS-specific TLS functions
* \version $Id$
*/

#include "stdinc.h"
#include "tls.h"
#include "conf.h"
#include "log.h"
#include "misc.h"
#include "memory.h"

#ifdef HAVE_TLS_GNUTLS

void
tls_init(void)
{
}

static void
tls_free_cred(tls_context_t cred)
{
gnutls_priority_deinit(cred->priorities);
gnutls_dh_params_deinit(cred->dh_params);
gnutls_certificate_free_credentials(cred->x509_cred);

gnutls_global_deinit();

xfree(cred);
}

int
tls_new_cred(void)
{
int ret;
struct gnutls_context *context;

if (!ConfigServerInfo.ssl_certificate_file || !ConfigServerInfo.rsa_private_key_file)
return 0;

context = xcalloc(sizeof(*context));

gnutls_global_init();

ret = gnutls_certificate_allocate_credentials(&context->x509_cred);
if (ret != GNUTLS_E_SUCCESS)
{
ilog(LOG_TYPE_IRCD, "ERROR: Could not initialize the TLS credentials -- %s", gnutls_strerror(ret));
xfree(context);
return 0;
}

/* TBD: set ciphers based on serverinfo::ssl_cipher_list */

gnutls_priority_init(&context->priorities, "NORMAL:%SERVER_PRECEDENCE:!VERS-SSL3.0", NULL);

ret = gnutls_certificate_set_x509_key_file(context->x509_cred, ConfigServerInfo.ssl_certificate_file, ConfigServerInfo.rsa_private_key_file, GNUTLS_X509_FMT_PEM);
if (ret != GNUTLS_E_SUCCESS)
{
ilog(LOG_TYPE_IRCD, "Could not set TLS keys -- %s", gnutls_strerror(ret));

gnutls_certificate_free_credentials(context->x509_cred);
gnutls_priority_deinit(context->priorities);
xfree(context);
return 0;
}

gnutls_dh_params_init(&context->dh_params);

if (ConfigServerInfo.ssl_dh_param_file)
{
gnutls_datum_t data;

ret = gnutls_load_file(ConfigServerInfo.ssl_dh_param_file, &data);

if (ret != GNUTLS_E_SUCCESS)
ilog(LOG_TYPE_IRCD, "Ignoring serverinfo::ssl_dh_param_file -- unable to load file -- %s", gnutls_strerror(ret));
else
{
ret = gnutls_dh_params_import_pkcs3(context->dh_params, &data, GNUTLS_X509_FMT_PEM);

if (ret != GNUTLS_E_SUCCESS)
ilog(LOG_TYPE_IRCD, "Ignoring serverinfo::ssl_dh_param_file -- unable to import dh params -- %s", gnutls_strerror(ret));

gnutls_free(data.data);
}
}

gnutls_certificate_set_dh_params(context->x509_cred, context->dh_params);

if (ConfigServerInfo.ssl_message_digest_algorithm == NULL)
ConfigServerInfo.message_digest_algorithm = GNUTLS_DIG_SHA256;
else
{
ConfigServerInfo.message_digest_algorithm = gnutls_digest_get_id(ConfigServerInfo.ssl_message_digest_algorithm);

if (ConfigServerInfo.message_digest_algorithm == GNUTLS_DIG_UNKNOWN)
{
ConfigServerInfo.message_digest_algorithm = GNUTLS_DIG_SHA256;
ilog(LOG_TYPE_IRCD, "Ignoring serverinfo::ssl_message_digest_algorithm -- unknown message digest algorithm");
}
}

if (ConfigServerInfo.tls_ctx && --ConfigServerInfo.tls_ctx->refs == 0)
tls_free_cred(ConfigServerInfo.tls_ctx);

ConfigServerInfo.tls_ctx = context;
++context->refs;

return 1;
}

const char *
tls_get_cipher(const tls_data_t *tls_data)
{
static char buffer[IRCD_BUFSIZE];

snprintf(buffer, sizeof(buffer), "%s-%s-%s-%s",
gnutls_protocol_get_name(gnutls_protocol_get_version(tls_data->session)),
gnutls_kx_get_name(gnutls_kx_get(tls_data->session)),
gnutls_cipher_get_name(gnutls_cipher_get(tls_data->session)),
gnutls_mac_get_name(gnutls_mac_get(tls_data->session)));

return buffer;
}

int
tls_isusing(tls_data_t *tls_data)
{
return tls_data->session != NULL;
}

void
tls_free(tls_data_t *tls_data)
{
gnutls_deinit(tls_data->session);
}

int
tls_read(tls_data_t *tls_data, char *buf, size_t bufsize, int *want_write)
{
int length = gnutls_record_recv(tls_data->session, buf, bufsize);

if (length <= 0)
{
switch (length)
{
case GNUTLS_E_AGAIN:
case GNUTLS_E_INTERRUPTED:
errno = EWOULDBLOCK;
return -1;
case 0: /* Closed */
default: /* Other error */
/* XXX can gnutls_strerror(length) if <0 for gnutls's idea of the reason */
return 0;
}
}

return length;
}

int
tls_write(tls_data_t *tls_data, const char *buf, size_t bufsize, int *want_read)
{
int length = gnutls_record_send(tls_data->session, buf, bufsize);

if (length <= 0)
{
switch (length)
{
case GNUTLS_E_AGAIN:
case GNUTLS_E_INTERRUPTED:
case 0:
errno = EWOULDBLOCK;
return -1;
default:
return 0;
}
}

return length;
}

void
tls_shutdown(tls_data_t *tls_data)
{
gnutls_bye(tls_data->session, GNUTLS_SHUT_WR);

if (--tls_data->context->refs == 0)
tls_free_cred(tls_data->context);
}

int
tls_new(tls_data_t *tls_data, int fd, tls_role_t role)
{
gnutls_init(&tls_data->session, role == TLS_ROLE_SERVER ? GNUTLS_SERVER : GNUTLS_CLIENT);

tls_data->context = ConfigServerInfo.tls_ctx;
++tls_data->context->refs;

gnutls_priority_set(tls_data->session, tls_data->context->priorities);
gnutls_credentials_set(tls_data->session, GNUTLS_CRD_CERTIFICATE, tls_data->context->x509_cred);
gnutls_dh_set_prime_bits(tls_data->session, 1024);
gnutls_transport_set_int(tls_data->session, fd);

if (role == TLS_ROLE_SERVER)
/* Request client certificate if any. */
gnutls_certificate_server_set_request(tls_data->session, GNUTLS_CERT_REQUEST);

return 1;
}

int
tls_set_ciphers(tls_data_t *tls_data, const char *cipher_list)
{
int ret;
const char *prioerror;

gnutls_priority_deinit(tls_data->context->priorities);

ret = gnutls_priority_init(&tls_data->context->priorities, cipher_list, &prioerror);
if (ret != GNUTLS_E_SUCCESS)
{
/* GnuTLS did not understand the user supplied string, log and fall back to the default priorities */
ilog(LOG_TYPE_IRCD, "Failed to set GnuTLS priorities to \"%s\": %s Syntax error at position %u, falling back to default (NORMAL:%%SERVER_PRECEDENCE:!VERS-SSL3.0)",
cipher_list, gnutls_strerror(ret), (unsigned int)(prioerror - cipher_list));
gnutls_priority_init(&tls_data->context->priorities, "NORMAL:%SERVER_PRECEDENCE:!VERS-SSL3.0", NULL);
return 0;
}

return 1;
}

tls_handshake_status_t
tls_handshake(tls_data_t *tls_data, tls_role_t role, const char **errstr)
{
int ret = gnutls_handshake(tls_data->session);

if (ret >= 0)
return TLS_HANDSHAKE_DONE;

if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)
{
/* Handshake needs resuming later, read() or write() would have blocked. */

if (gnutls_record_get_direction(tls_data->session) == 0)
{
/* gnutls_handshake() wants to read() again. */
return TLS_HANDSHAKE_WANT_READ;
}
else
{
/* gnutls_handshake() wants to write() again. */
return TLS_HANDSHAKE_WANT_WRITE;
}
}
else
{
const char *error = gnutls_strerror(ret);

if (errstr)
*errstr = error;

return TLS_HANDSHAKE_ERROR;
}
}

int
tls_verify_cert(tls_data_t *tls_data, tls_md_t digest, char **fingerprint)
{
int ret;
gnutls_x509_crt_t cert;
const gnutls_datum_t *cert_list;
unsigned int cert_list_size = 0;
unsigned char digestbuf[TLS_GNUTLS_MAX_HASH_SIZE];
size_t digest_size = sizeof(digestbuf);
char buf[TLS_GNUTLS_MAX_HASH_SIZE * 2 + 1];

cert_list = gnutls_certificate_get_peers(tls_data->session, &cert_list_size);
if (!cert_list)
return 1; /* No certificate */

ret = gnutls_x509_crt_init(&cert);
if (ret != GNUTLS_E_SUCCESS)
return 1;

ret = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
if (ret != GNUTLS_E_SUCCESS)
goto info_done_dealloc;

ret = gnutls_x509_crt_get_fingerprint(cert, digest, digestbuf, &digest_size);
if (ret != GNUTLS_E_SUCCESS)
goto info_done_dealloc;

binary_to_hex(digestbuf, buf, digest_size);
*fingerprint = xstrdup(buf);

gnutls_x509_crt_deinit(cert);
return 1;

info_done_dealloc:
gnutls_x509_crt_deinit(cert);
return 0;
}
#endif /* HAVE_TLS_GNUTLS */
@@ -0,0 +1,96 @@
/*
* ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
*
* Copyright (c) 2015 Attila Molnar <attilamolnar@hush.com>
* Copyright (c) 2015 Adam <Adam@anope.org>
* Copyright (c) 2015-2016 ircd-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 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/

/*! \file tls_none.c
* \brief Dummy file for no TLS support
* \version $Id$
*/

#include "stdinc.h"
#include "tls.h"

#ifndef HAVE_TLS

void
tls_init(void)
{
}

int
tls_new_cred(void)
{
return 0;
}

const char *
tls_get_cipher(const tls_data_t *tls_data)
{
return NULL;
}

int
tls_isusing(tls_data_t *tls_data)
{
return 0;
}

void
tls_free(tls_data_t *tls_data)
{
}

int
tls_read(tls_data_t *tls_data, char *buf, size_t bufsize, int *want_write)
{
return -1;
}

int
tls_write(tls_data_t *tls_data, const char *buf, size_t bufsize, int *want_read)
{
return -1;
}

void
tls_shutdown(tls_data_t *tls_data)
{
}

int
tls_new(tls_data_t *tls_data, int fd, tls_role_t role)
{
return 0;
}

int
tls_set_ciphers(tls_data_t *tls_data, const char *cipher_list)
{
return 0;
}

int
tls_verify_cert(tls_data_t *tls_data, tls_md_t digest, char **fingerprint)
{
return 0;
}
#endif /* HAVE_TLS */

Large diffs are not rendered by default.

@@ -49,6 +49,7 @@
#include "parse.h"
#include "watch.h"
#include "isupport.h"
#include "tls.h"

static char umode_buffer[IRCD_BUFSIZE];

@@ -211,7 +212,7 @@ introduce_client(struct Client *source_p)
dlink_node *node = NULL;
char ubuf[IRCD_BUFSIZE] = "";

if (MyClient(source_p))
if (MyConnect(source_p))
send_umode(source_p, source_p, 0, ubuf);
else
send_umode(NULL, source_p, 0, ubuf);
@@ -256,14 +257,12 @@ user_welcome(struct Client *source_p)
{
static const char built_date[] = __DATE__ " at " __TIME__;

#ifdef HAVE_LIBCRYPTO
if (HasFlag(source_p, FLAGS_SSL))
{
AddUMode(source_p, UMODE_SSL);
sendto_one_notice(source_p, &me, ":*** Connected securely via %s",
ssl_get_cipher(source_p->connection->fd.ssl));
tls_get_cipher(&source_p->connection->fd.ssl));
}
#endif

sendto_one_numeric(source_p, &me, RPL_WELCOME, ConfigServerInfo.network_name,
source_p->name);
@@ -50,8 +50,8 @@ const char *infotext[] =
"of people, all of us.",
"",
"Anyone is welcome to contribute to this effort. You are encouraged",
"to participate in the Hybrid mailing list. To subscribe to the",
"Hybrid List, use this link:",
"to participate in the ircd-hybrid mailing list. To subscribe to the",
"ircd-hybrid list, use this link:",
" https://lists.ircd-hybrid.org/mailman/listinfo/hybrid",
"",
"The core team as of this major release:",
@@ -65,7 +65,7 @@ const char *infotext[] =
"Wohali, Joan Touzet <joant@ieee.org>",
"",
"The following people have contributed blood, sweat, and/or code to",
"recent releases of Hybrid, in nick alphabetical order:",
"recent releases of ircd-hybrid, in nick alphabetical order:",
"",
"A1kmm, Andrew Miller <a1kmm@mware.virtualave.net>",
"Adam, Adam <Adam@anope.org>",
@@ -73,7 +73,7 @@ watch_count_memory(unsigned int *const count, size_t *const bytes)
(*bytes) = *count * sizeof(struct Watch);
}

/*! \brief Notifies all clients that have client_p's nick name on
/*! \brief Notifies all clients that have client_p's name on
* their watch list.
* \param client_p Pointer to Client struct
* \param reply Numeric to send. Either RPL_LOGON or RPL_LOGOFF
@@ -87,7 +87,7 @@ watch_check_hash(const struct Client *client_p, const enum irc_numerics reply)
assert(IsClient(client_p));

if ((watch = watch_find_hash(client_p->name)) == NULL)
return; /* This nick isn't on watch */
return; /* This name isn't on watch */

/* Update the time of last change to item */
watch->lasttime = CurrentTime;
@@ -99,7 +99,7 @@ watch_check_hash(const struct Client *client_p, const enum irc_numerics reply)
watch->lasttime, client_p->info);
}

/*! \brief Looks up the watch table for a given nick
/*! \brief Looks up the watch table for a given name
* \param name Nick name to look up
*/
struct Watch *
@@ -111,32 +111,32 @@ watch_find_hash(const char *name)
{
struct Watch *watch = node->data;

if (!irccmp(watch->nick, name))
if (!irccmp(watch->name, name))
return watch;
}

return NULL;
}

/*! \brief Adds a watch entry to client_p's watch list
* \param nick Nick name to add
* \param name Nick name to add
* \param client_p Pointer to Client struct
*/
void
watch_add_to_hash_table(const char *nick, struct Client *client_p)
watch_add_to_hash_table(const char *name, struct Client *client_p)
{
struct Watch *watch = NULL;
dlink_node *node = NULL;

/* If found NULL (no header for this nick), make one... */
if ((watch = watch_find_hash(nick)) == NULL)
/* If found NULL (no header for this name), make one... */
if ((watch = watch_find_hash(name)) == NULL)
{
watch = mp_pool_get(watch_pool);

watch->lasttime = CurrentTime;
strlcpy(watch->nick, nick, sizeof(watch->nick));
strlcpy(watch->name, name, sizeof(watch->name));

dlinkAdd(watch, &watch->node, &watchTable[strhash(watch->nick)]);
dlinkAdd(watch, &watch->node, &watchTable[strhash(watch->name)]);
}
else
{
@@ -153,20 +153,20 @@ watch_add_to_hash_table(const char *nick, struct Client *client_p)
}

/*! \brief Removes a single entry from client_p's watch list
* \param nick Nick name to remove
* \param name Name to remove
* \param client_p Pointer to Client struct
*/
void
watch_del_from_hash_table(const char *nick, struct Client *client_p)
watch_del_from_hash_table(const char *name, struct Client *client_p)
{
struct Watch *watch = NULL;
dlink_node *node = NULL;

if ((watch = watch_find_hash(nick)) == NULL)
return; /* No header found for that nick. i.e. it's not being watched */
if ((watch = watch_find_hash(name)) == NULL)
return; /* No header found for that name. i.e. it's not being watched */

if ((node = dlinkFind(&watch->watched_by, client_p)) == NULL)
return; /* This nick isn't being watched by client_p */
return; /* This name isn't being watched by client_p */

dlinkDelete(node, &watch->watched_by);
free_dlink_node(node);
@@ -177,8 +177,8 @@ watch_del_from_hash_table(const char *nick, struct Client *client_p)
/* In case this header is now empty of notices, remove it */
if (watch->watched_by.head == NULL)
{
assert(dlinkFind(&watchTable[strhash(watch->nick)], watch));
dlinkDelete(&watch->node, &watchTable[strhash(watch->nick)]);
assert(dlinkFind(&watchTable[strhash(watch->name)], watch));
dlinkDelete(&watch->node, &watchTable[strhash(watch->name)]);
mp_pool_release(watch);
}
}
@@ -205,8 +205,8 @@ watch_del_watch_list(struct Client *client_p)
/* If this leaves a header without notifies, remove it. */
if (watch->watched_by.head == NULL)
{
assert(dlinkFind(&watchTable[strhash(watch->nick)], watch));
dlinkDelete(&watch->node, &watchTable[strhash(watch->nick)]);
assert(dlinkFind(&watchTable[strhash(watch->name)], watch));
dlinkDelete(&watch->node, &watchTable[strhash(watch->name)]);

mp_pool_release(watch);
}
@@ -97,6 +97,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ac_define_dir.m4 \
$(top_srcdir)/m4/ax_arg_enable_assert.m4 \
$(top_srcdir)/m4/ax_arg_enable_debugging.m4 \
$(top_srcdir)/m4/ax_arg_enable_warnings.m4 \
$(top_srcdir)/m4/ax_arg_gnutls.m4 \
$(top_srcdir)/m4/ax_arg_ioloop_mechanism.m4 \
$(top_srcdir)/m4/ax_arg_libgeoip.m4 \
$(top_srcdir)/m4/ax_arg_openssl.m4 \