commit
b68b0dc71d
5
NEWS
5
NEWS
@ -1,3 +1,8 @@
|
||||
29-10-2007: Certificate validation change. In "basic" mode, expired
|
||||
certificates are now accepted as long as they are in store (therefore trusted).
|
||||
This makes the basic mode be more SSH like. Some extreme security zealots might
|
||||
want to be warned.
|
||||
|
||||
02-09-2007: as of now log parameters go in the user {} statment. This brakes
|
||||
every config and there is no backwrads compatibility as of now.
|
||||
Lots of internal changes, expect crashes.
|
||||
|
1
TODO
1
TODO
@ -1,3 +1,4 @@
|
||||
- check conn_list usage: esp wrt list_remove and closes
|
||||
- uid, gid
|
||||
- keep invites when detached ?
|
||||
- allow global (or per net ?) IP filtering
|
||||
|
@ -226,7 +226,12 @@ The password. It \fBMUST\fP be generated with \fBbimkpw\fP or it'll not work.
|
||||
Tells whether BIP should check the server SSL certificate and against what.
|
||||
Can be \fBnone\fP for no check at all, \fBca\fP to check if the cert is signed
|
||||
by a Certificate Authority in repository, or \fBbasic\fP to check if cert
|
||||
exists in repository. The repository is defined by \fBssl_check_store\fP.
|
||||
exists in repository. The repository is defined by \fBssl_check_store\fP. This
|
||||
allows a "ssh-like" private key generation scheme. Note that in basic mode:
|
||||
.br
|
||||
- expired certificates that are in the store are considered valid.
|
||||
.br
|
||||
- CA-signed certificates are considered valid even if not in store.
|
||||
|
||||
.TP
|
||||
\fBssl_check_store\fP (default: \fBnot set\fP)
|
||||
|
@ -37,7 +37,7 @@ log_level = 3;
|
||||
# %m -> 2 digit month
|
||||
# %d -> 2 digit day
|
||||
# %c -> destination (#chan, privates, ...)
|
||||
#log_format = "%n/%Y-%m/%c.%d.log";
|
||||
#log_format = "%u/%n/%Y-%m/%c.%d.log";
|
||||
|
||||
# Sets the frequency (in seconds) of log syncing (real write to kernel)
|
||||
#log_sync_interval = 5;
|
||||
|
13
scripts/bip-take-snapshot
Executable file
13
scripts/bip-take-snapshot
Executable file
@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
prefix=bip-$(date +%y%m%d)
|
||||
|
||||
if [ ! -d src ] ; then
|
||||
echo "Please run me in bip sources root." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
git-archive --format=tar --prefix=$prefix/ HEAD | gzip -c > ../$prefix.tar.gz
|
||||
|
377
src/bip.c
377
src/bip.c
@ -17,6 +17,7 @@
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include "irc.h"
|
||||
@ -48,7 +49,7 @@ int conf_log = DEFAULT_LOG;
|
||||
int conf_log_system = DEFAULT_LOG_SYSTEM;
|
||||
int conf_log_sync_interval = DEFAULT_LOG_SYNC_INTERVAL;
|
||||
|
||||
list_t *parse_conf(FILE *file);
|
||||
list_t *parse_conf(FILE *file, int *err);
|
||||
static void conf_die(char *fmt, ...);
|
||||
#ifdef HAVE_LIBSSL
|
||||
int adm_trust(struct link_client *ic, struct line *line);
|
||||
@ -56,6 +57,7 @@ int adm_trust(struct link_client *ic, struct line *line);
|
||||
static char *get_tuple_value(list_t *tuple_l, int lex);
|
||||
void bip_notify(struct link_client *ic, char *fmt, ...);
|
||||
void adm_list_connections(struct link_client *ic, struct user *bu);
|
||||
void free_conf(list_t *l);
|
||||
|
||||
static void hash_binary(char *hex, unsigned char **password, unsigned int *seed)
|
||||
{
|
||||
@ -94,7 +96,7 @@ static int add_server(struct server *s, list_t *data)
|
||||
while ((t = list_remove_first(data))) {
|
||||
switch (t->type) {
|
||||
case LEX_HOST:
|
||||
s->host = t->pdata;
|
||||
MOVE_STRING(s->host, t->pdata);
|
||||
break;
|
||||
case LEX_PORT:
|
||||
s->port = t->ndata;
|
||||
@ -102,6 +104,9 @@ static int add_server(struct server *s, list_t *data)
|
||||
default:
|
||||
fatal("Config error in server block (%d)", t->type);
|
||||
}
|
||||
if (t->tuple_type == TUPLE_STR && t->pdata)
|
||||
free(t->pdata);
|
||||
free(t);
|
||||
}
|
||||
if (!s->host) {
|
||||
free(s);
|
||||
@ -115,23 +120,12 @@ static int add_server(struct server *s, list_t *data)
|
||||
|
||||
extern list_t *root_list;
|
||||
int yyparse();
|
||||
int conf_error;
|
||||
char conf_errstr[ERRBUFSZ];
|
||||
|
||||
static void conf_start(void)
|
||||
{
|
||||
conf_error = 0;
|
||||
}
|
||||
|
||||
static void conf_die(char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
|
||||
vsnprintf(conf_errstr, ERRBUFSZ, fmt, ap);
|
||||
conf_errstr[ERRBUFSZ - 1] = 0;
|
||||
conf_error = 1;
|
||||
|
||||
_mylog(LOG_ERROR, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
@ -307,8 +301,9 @@ static int add_network(bip_t *bip, list_t *data)
|
||||
struct tuple *t;
|
||||
struct network *n;
|
||||
int i;
|
||||
int r;
|
||||
|
||||
char *name = get_tuple_value(data, LEX_NAME);
|
||||
char *name = get_tuple_pvalue(data, LEX_NAME);
|
||||
|
||||
if (name == NULL) {
|
||||
conf_die("Network with no name");
|
||||
@ -340,29 +335,103 @@ static int add_network(bip_t *bip, list_t *data)
|
||||
n->serverv = realloc(n->serverv, (n->serverc + 1)
|
||||
* sizeof(struct server));
|
||||
n->serverc++;
|
||||
add_server(&n->serverv[n->serverc - 1], t->pdata);
|
||||
memset(&n->serverv[n->serverc - 1], 0,
|
||||
sizeof(struct server));
|
||||
r = add_server(&n->serverv[n->serverc - 1], t->pdata);
|
||||
if (!r) {
|
||||
n->serverc--;
|
||||
return 0;
|
||||
}
|
||||
free(t->pdata);
|
||||
t->pdata = NULL;
|
||||
break;
|
||||
default:
|
||||
conf_die("unknown keyword in network statement");
|
||||
if (t->type == TUPLE_STR)
|
||||
free(t->pdata);
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
if (t->type == TUPLE_STR && t->pdata)
|
||||
if (t->tuple_type == TUPLE_STR && t->pdata)
|
||||
free(t->pdata);
|
||||
free(t);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void adm_bip_delconn(bip_t *bip, struct link_client *ic, char *conn_name)
|
||||
{
|
||||
struct user *user = LINK(ic)->user;
|
||||
struct link *l;
|
||||
|
||||
if (!hash_get(&user->connections, conn_name)) {
|
||||
adm_reply(ic, "cannot find this connection");
|
||||
return;
|
||||
}
|
||||
|
||||
l = hash_get(&user->connections, conn_name);
|
||||
link_kill(bip, l);
|
||||
adm_reply(ic, "deleted");
|
||||
}
|
||||
|
||||
void adm_bip_addconn(bip_t *bip, struct link_client *ic, char *conn_name,
|
||||
char *network_name)
|
||||
{
|
||||
struct user *user = LINK(ic)->user;
|
||||
struct network *network;
|
||||
|
||||
/* check name uniqueness */
|
||||
if (hash_get(&user->connections, conn_name)) {
|
||||
adm_reply(ic, "connection name already exists for this user.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* check we know about this network */
|
||||
network = hash_get(&bip->networks, network_name);
|
||||
if (!network) {
|
||||
adm_reply(ic, "no such network name");
|
||||
return;
|
||||
}
|
||||
|
||||
struct link *l;
|
||||
l = irc_link_new();
|
||||
l->name = strdup(conn_name);
|
||||
hash_insert(&user->connections, conn_name, l);
|
||||
list_add_last(&bip->link_list, l);
|
||||
l->user = user;
|
||||
l->network = network;
|
||||
l->log = log_new(user, conn_name);
|
||||
#ifdef HAVE_LIBSSL
|
||||
l->ssl_check_mode = user->ssl_check_mode;
|
||||
l->untrusted_certs = sk_X509_new_null();
|
||||
#endif
|
||||
|
||||
|
||||
#define SCOPY(member) l->member = (LINK(ic)->member ? strdup(LINK(ic)->member) : NULL)
|
||||
#define ICOPY(member) l->member = LINK(ic)->member
|
||||
|
||||
SCOPY(connect_nick);
|
||||
SCOPY(username);
|
||||
SCOPY(realname);
|
||||
/* we don't copy server password */
|
||||
SCOPY(vhost);
|
||||
ICOPY(follow_nick);
|
||||
ICOPY(ignore_first_nick);
|
||||
SCOPY(away_nick);
|
||||
SCOPY(no_client_away_msg);
|
||||
/* we don't copy on_connect_send */
|
||||
#ifdef HAVE_LIBSSL
|
||||
ICOPY(ssl_check_mode);
|
||||
#endif
|
||||
#undef SCOPY
|
||||
#undef ICOPY
|
||||
adm_reply(ic, "connection added, you should soon be able to connect");
|
||||
}
|
||||
|
||||
static int add_connection(bip_t *bip, struct user *user, list_t *data)
|
||||
{
|
||||
struct tuple *t, *t2;
|
||||
struct link *l;
|
||||
struct chan_info *ci;
|
||||
char *name = get_tuple_value(data, LEX_NAME);
|
||||
char *name = get_tuple_pvalue(data, LEX_NAME);
|
||||
|
||||
if (name == NULL) {
|
||||
conf_die("Connection with no name");
|
||||
@ -380,7 +449,6 @@ static int add_connection(bip_t *bip, struct user *user, list_t *data)
|
||||
l->untrusted_certs = sk_X509_new_null();
|
||||
#endif
|
||||
} else {
|
||||
#warning "CODEME (user switch..)"
|
||||
l->network = NULL;
|
||||
log_reinit_all(l->log);
|
||||
}
|
||||
@ -416,8 +484,20 @@ static int add_connection(bip_t *bip, struct user *user, list_t *data)
|
||||
MOVE_STRING(l->vhost, t->pdata);
|
||||
break;
|
||||
case LEX_CHANNEL:
|
||||
ci = calloc(sizeof(struct chan_info), 1);
|
||||
name = get_tuple_pvalue(t->pdata, LEX_NAME);
|
||||
if (name == NULL) {
|
||||
conf_die("Channel with no name");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ci = hash_get(&l->chan_infos, name);
|
||||
if (!ci) {
|
||||
ci = chan_info_new();
|
||||
hash_insert(&l->chan_infos, name, ci);
|
||||
/* FIXME: this order is not reloaded */
|
||||
list_add_last(&l->chan_infos_order, ci);
|
||||
ci->backlog = 1;
|
||||
}
|
||||
|
||||
while ((t2 = list_remove_first(t->pdata))) {
|
||||
switch (t2->type) {
|
||||
@ -431,11 +511,11 @@ static int add_connection(bip_t *bip, struct user *user, list_t *data)
|
||||
ci->backlog = t2->ndata;
|
||||
break;
|
||||
}
|
||||
if (t2->tuple_type == TUPLE_STR && t2->pdata)
|
||||
free(t2->pdata);
|
||||
free(t2);
|
||||
}
|
||||
list_free(t->pdata);
|
||||
|
||||
hash_insert(&l->chan_infos, ci->name, ci);
|
||||
list_add_last(&l->chan_infos_order, ci);
|
||||
break;
|
||||
case LEX_FOLLOW_NICK:
|
||||
l->follow_nick = t->ndata;
|
||||
@ -451,6 +531,7 @@ static int add_connection(bip_t *bip, struct user *user, list_t *data)
|
||||
break;
|
||||
case LEX_ON_CONNECT_SEND:
|
||||
list_add_last(&l->on_connect_send, t->pdata);
|
||||
t->pdata = NULL;
|
||||
break;
|
||||
#ifdef HAVE_LIBSSL
|
||||
case LEX_SSL_CHECK_MODE:
|
||||
@ -458,15 +539,13 @@ static int add_connection(bip_t *bip, struct user *user, list_t *data)
|
||||
l->ssl_check_mode = SSL_CHECK_BASIC;
|
||||
if (strcmp(t->pdata, "ca") == 0)
|
||||
l->ssl_check_mode = SSL_CHECK_CA;
|
||||
free(t->pdata);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
conf_die("unknown keyword in connection statement");
|
||||
if (t->type == TUPLE_STR)
|
||||
free(t->pdata);
|
||||
return 0;
|
||||
}
|
||||
if (t->type == TUPLE_STR && t->pdata)
|
||||
if (t->tuple_type == TUPLE_STR && t->pdata)
|
||||
free(t->pdata);
|
||||
free(t);
|
||||
}
|
||||
@ -488,10 +567,12 @@ static int add_connection(bip_t *bip, struct user *user, list_t *data)
|
||||
conf_die("No realname set and no default realname.");
|
||||
l->realname = strdup(user->default_realname);
|
||||
}
|
||||
|
||||
l->in_use = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static char *get_tuple_value(list_t *tuple_l, int lex)
|
||||
static char *get_tuple_pvalue(list_t *tuple_l, int lex)
|
||||
{
|
||||
struct tuple *t;
|
||||
list_iterator_t it;
|
||||
@ -504,13 +585,35 @@ static char *get_tuple_value(list_t *tuple_l, int lex)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int add_user(bip_t *bip, list_t *data)
|
||||
static int get_tuple_nvalue(list_t *tuple_l, int lex)
|
||||
{
|
||||
struct tuple *t;
|
||||
list_iterator_t it;
|
||||
|
||||
for (list_it_init(tuple_l, &it); (t = list_it_item(&it));
|
||||
list_it_next(&it)) {
|
||||
if (t->type == lex)
|
||||
return t->ndata;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct historical_directives {
|
||||
int always_backlog;
|
||||
int backlog;
|
||||
int bl_msg_only;
|
||||
int backlog_lines;
|
||||
int backlog_no_timestamp;
|
||||
int blreset_on_talk;
|
||||
};
|
||||
|
||||
static int add_user(bip_t *bip, list_t *data, struct historical_directives *hds)
|
||||
{
|
||||
int r;
|
||||
struct tuple *t;
|
||||
struct user *u;
|
||||
|
||||
char *name = get_tuple_value(data, LEX_NAME);
|
||||
char *name = get_tuple_pvalue(data, LEX_NAME);
|
||||
|
||||
if (name == NULL) {
|
||||
conf_die("User with no name");
|
||||
@ -540,6 +643,13 @@ static int add_user(bip_t *bip, list_t *data)
|
||||
#endif
|
||||
}
|
||||
|
||||
u->backlog = hds->backlog;
|
||||
u->always_backlog = hds->always_backlog;
|
||||
u->bl_msg_only = hds->bl_msg_only;
|
||||
u->backlog_lines = hds->backlog_lines;
|
||||
u->backlog_no_timestamp = hds->backlog_no_timestamp;
|
||||
u->blreset_on_talk = hds->blreset_on_talk;
|
||||
|
||||
while ((t = list_remove_first(data))) {
|
||||
switch (t->type) {
|
||||
case LEX_NAME:
|
||||
@ -551,6 +661,7 @@ static int add_user(bip_t *bip, list_t *data)
|
||||
case LEX_PASSWORD:
|
||||
hash_binary(t->pdata, &u->password, &u->seed);
|
||||
free(t->pdata);
|
||||
t->pdata = NULL;
|
||||
break;
|
||||
case LEX_DEFAULT_NICK:
|
||||
MOVE_STRING(u->default_nick, t->pdata);
|
||||
@ -585,6 +696,7 @@ static int add_user(bip_t *bip, list_t *data)
|
||||
case LEX_CONNECTION:
|
||||
r = add_connection(bip, u, t->pdata);
|
||||
free(t->pdata);
|
||||
t->pdata = NULL;
|
||||
if (!r)
|
||||
return 0;
|
||||
break;
|
||||
@ -595,16 +707,17 @@ static int add_user(bip_t *bip, list_t *data)
|
||||
if (!strncmp(t->pdata, "ca", 2))
|
||||
u->ssl_check_mode = SSL_CHECK_CA;
|
||||
free(t->pdata);
|
||||
t->pdata = NULL;
|
||||
break;
|
||||
case LEX_SSL_CHECK_STORE:
|
||||
u->ssl_check_store = t->pdata;
|
||||
MOVE_STRING(u->ssl_check_store, t->pdata);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
conf_die("Uknown keyword in user statement");
|
||||
break;
|
||||
return 0;
|
||||
}
|
||||
if (t->type == TUPLE_STR && t->pdata)
|
||||
if (t->tuple_type == TUPLE_STR && t->pdata)
|
||||
free(t->pdata);
|
||||
free(t);
|
||||
}
|
||||
@ -613,6 +726,7 @@ static int add_user(bip_t *bip, list_t *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
u->in_use = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -649,7 +763,6 @@ static int validate_config(bip_t *bip)
|
||||
link->name);
|
||||
#endif
|
||||
|
||||
//conf_die("user: ... net: ... can i has nick/user/rael");
|
||||
r = 0;
|
||||
|
||||
for (hash_it_init(&link->chan_infos, &cit);
|
||||
@ -672,21 +785,99 @@ static int validate_config(bip_t *bip)
|
||||
}
|
||||
}
|
||||
|
||||
if (strstr(conf_log_format, "\%u") == NULL)
|
||||
mylog(LOG_WARN, "log_format doesn't contain \%u, all users'"
|
||||
" logs will be mixed !");
|
||||
return r;
|
||||
}
|
||||
|
||||
void clear_marks(bip_t *bip)
|
||||
{
|
||||
list_iterator_t lit;
|
||||
hash_iterator_t hit;
|
||||
|
||||
for (list_it_init(&bip->link_list, &lit); list_it_item(&lit);
|
||||
list_it_next(&lit))
|
||||
((struct link *)list_it_item(&lit))->in_use = 0;
|
||||
for (hash_it_init(&bip->users, &hit); hash_it_item(&hit);
|
||||
hash_it_next(&hit))
|
||||
((struct user *)hash_it_item(&hit))->in_use = 0;
|
||||
}
|
||||
|
||||
void user_kill(bip_t *bip, struct user *user)
|
||||
{
|
||||
(void)bip;
|
||||
if (!hash_is_empty(&user->connections))
|
||||
fatal("user_kill, user still has connections");
|
||||
free(user->name);
|
||||
free(user->password);
|
||||
MAYFREE(user->default_nick);
|
||||
MAYFREE(user->default_username);
|
||||
MAYFREE(user->default_realname);
|
||||
|
||||
#ifdef HAVE_LIBSSL
|
||||
MAYFREE(user->ssl_check_store);
|
||||
#endif
|
||||
free(user);
|
||||
}
|
||||
|
||||
void sweep(bip_t *bip)
|
||||
{
|
||||
list_iterator_t lit;
|
||||
hash_iterator_t hit;
|
||||
|
||||
for (list_it_init(&bip->link_list, &lit); list_it_item(&lit);
|
||||
list_it_next(&lit)) {
|
||||
struct link *l = ((struct link *)list_it_item(&lit));
|
||||
if (!l->in_use) {
|
||||
mylog(LOG_INFO, "Administratively killing %s/%s",
|
||||
l->user->name, l->name);
|
||||
link_kill(bip, l);
|
||||
list_remove_if_exists(&bip->conn_list, l);
|
||||
list_it_remove(&lit);
|
||||
}
|
||||
}
|
||||
for (hash_it_init(&bip->users, &hit); hash_it_item(&hit);
|
||||
hash_it_next(&hit)) {
|
||||
struct user *u = (struct user *)hash_it_item(&hit);
|
||||
if (!u->in_use) {
|
||||
hash_it_remove(&hit);
|
||||
user_kill(bip, u);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int fireup(bip_t *bip, FILE *conf)
|
||||
{
|
||||
int r;
|
||||
struct tuple *t;
|
||||
list_t *l;
|
||||
int err = 0;
|
||||
struct historical_directives hds;
|
||||
|
||||
conf_start();
|
||||
|
||||
l = parse_conf(conf);
|
||||
if (conf_error)
|
||||
clear_marks(bip);
|
||||
parse_conf(conf, &err);
|
||||
if (err) {
|
||||
free_conf(root_list);
|
||||
root_list = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
while ((t = list_remove_first(l))) {
|
||||
#define SET_HV(d, n) do {\
|
||||
int __gtv = get_tuple_nvalue(root_list, LEX_##n);\
|
||||
if (__gtv != -1) \
|
||||
d = __gtv;\
|
||||
else\
|
||||
d = DEFAULT_##n;\
|
||||
} while(0);
|
||||
SET_HV(hds.always_backlog, ALWAYS_BACKLOG);
|
||||
SET_HV(hds.backlog, BACKLOG);
|
||||
SET_HV(hds.bl_msg_only, BL_MSG_ONLY);
|
||||
SET_HV(hds.backlog_lines, BACKLOG_LINES);
|
||||
SET_HV(hds.backlog_no_timestamp, BACKLOG_NO_TIMESTAMP);
|
||||
SET_HV(hds.blreset_on_talk, BLRESET_ON_TALK);
|
||||
#undef SET_HV
|
||||
|
||||
while ((t = list_remove_first(root_list))) {
|
||||
switch (t->type) {
|
||||
case LEX_LOG_SYNC_INTERVAL:
|
||||
conf_log_sync_interval = t->ndata;
|
||||
@ -718,44 +909,41 @@ int fireup(bip_t *bip, FILE *conf)
|
||||
case LEX_PID_FILE:
|
||||
MOVE_STRING(conf_pid_file, t->pdata);
|
||||
break;
|
||||
case LEX_NETWORK:
|
||||
add_network(bip, t->pdata);
|
||||
list_free(t->pdata);
|
||||
break;
|
||||
case LEX_USER:
|
||||
add_user(bip, t->pdata);
|
||||
list_free(t->pdata);
|
||||
break;
|
||||
|
||||
#warning deprecated but we still need to support these
|
||||
#if 0
|
||||
case LEX_ALWAYS_BACKLOG:
|
||||
conf_always_backlog = t->ndata;
|
||||
hds.always_backlog = t->ndata;
|
||||
break;
|
||||
case LEX_BACKLOG:
|
||||
conf_backlog = t->ndata;
|
||||
hds.backlog = t->ndata;
|
||||
break;
|
||||
case LEX_BL_MSG_ONLY:
|
||||
conf_bl_msg_only = t->ndata;
|
||||
hds.bl_msg_only = t->ndata;
|
||||
break;
|
||||
case LEX_BACKLOG_LINES:
|
||||
conf_backlog_lines = t->ndata;
|
||||
hds.backlog_lines = t->ndata;
|
||||
break;
|
||||
case LEX_BACKLOG_NO_TIMESTAMP:
|
||||
conf_backlog_no_timestamp = t->ndata;
|
||||
hds.backlog_no_timestamp = t->ndata;
|
||||
break;
|
||||
case LEX_BLRESET_ON_TALK:
|
||||
conf_blreset_on_talk = t->ndata;
|
||||
hds.blreset_on_talk = t->ndata;
|
||||
break;
|
||||
case LEX_NETWORK:
|
||||
r = add_network(bip, t->pdata);
|
||||
list_free(t->pdata);
|
||||
if (!r)
|
||||
goto out_conf_error;
|
||||
break;
|
||||
case LEX_USER:
|
||||
r = add_user(bip, t->pdata, &hds);
|
||||
list_free(t->pdata);
|
||||
if (!r)
|
||||
goto out_conf_error;
|
||||
break;
|
||||
/* end of deprectated */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
default:
|
||||
conf_die("Config error in base config (%d)", t->type);
|
||||
goto out_conf_error;
|
||||
}
|
||||
if (t->type == TUPLE_STR && t->pdata)
|
||||
if (t->tuple_type == TUPLE_STR && t->pdata)
|
||||
free(t->pdata);
|
||||
free(t);
|
||||
}
|
||||
@ -763,14 +951,20 @@ int fireup(bip_t *bip, FILE *conf)
|
||||
root_list = NULL;
|
||||
|
||||
validate_config(bip);
|
||||
sweep(bip);
|
||||
return 1;
|
||||
|
||||
out_conf_error:
|
||||
free_conf(root_list);
|
||||
root_list = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void log_file_setup(void)
|
||||
{
|
||||
char buf[4096];
|
||||
|
||||
if (conf_log_system) {
|
||||
if (conf_log_system && conf_daemonize) {
|
||||
if (conf_global_log_file && conf_global_log_file != stderr)
|
||||
fclose(conf_global_log_file);
|
||||
snprintf(buf, 4095, "%s/bip.log", conf_log_root);
|
||||
@ -881,7 +1075,7 @@ int main(int argc, char **argv)
|
||||
signal(SIGXCPU, rlimit_cpu_reached);
|
||||
|
||||
conf_log_root = NULL;
|
||||
conf_log_format = DEFAULT_LOG_FORMAT;
|
||||
conf_log_format = strdup(DEFAULT_LOG_FORMAT);
|
||||
conf_log_level = DEFAULT_LOG_LEVEL;
|
||||
conf_daemonize = 1;
|
||||
conf_global_log_file = stderr;
|
||||
@ -932,13 +1126,10 @@ int main(int argc, char **argv)
|
||||
fatal("%s config file not found", confpath);
|
||||
}
|
||||
|
||||
|
||||
r = fireup(&bip, conf);
|
||||
fclose(conf);
|
||||
if (!r) {
|
||||
fatal("%s", conf_errstr);
|
||||
exit(28);
|
||||
}
|
||||
if (!r)
|
||||
fatal("Not starting: error in config file.");
|
||||
|
||||
if (!conf_biphome) {
|
||||
char *home = getenv("HOME");
|
||||
@ -1000,9 +1191,6 @@ int main(int argc, char **argv)
|
||||
fatal("Could not create listening socket");
|
||||
|
||||
for (;;) {
|
||||
if (conf_error)
|
||||
mylog(LOG_ERROR, "conf error: %s", conf_errstr);
|
||||
|
||||
irc_main(&bip);
|
||||
|
||||
sighup = 0;
|
||||
@ -1641,11 +1829,13 @@ void adm_bip_help(struct link_client *ic, int admin)
|
||||
"configuration");
|
||||
bip_notify(ic, "/BIP LIST networks|users|connections|all_links"
|
||||
"|all_connections");
|
||||
bip_notify(ic, "/BIP ADD_CONN <connection name> <network>");
|
||||
bip_notify(ic, "/BIP DEL_CONN <connection name>");
|
||||
} else {
|
||||
bip_notify(ic, "/BIP LIST networks|connections");
|
||||
}
|
||||
bip_notify(ic, "/BIP JUMP # jump to next server (in same network)");
|
||||
bip_notify(ic, "/BIP BLRESET # reset backlog (this connection only)");
|
||||
bip_notify(ic, "/BIP BLRESET # reset backlog (this connection only). Add -q flag and the operation is quiet.");
|
||||
#ifdef HAVE_LIBSSL
|
||||
bip_notify(ic, "/BIP TRUST # trust this server certificate");
|
||||
#endif
|
||||
@ -1659,14 +1849,15 @@ void adm_bip_help(struct link_client *ic, int admin)
|
||||
bip_notify(ic, "/BIP AWAY_NICK # clear away nick");
|
||||
}
|
||||
|
||||
int adm_bip(struct link_client *ic, struct line *line, unsigned int privmsg)
|
||||
int adm_bip(bip_t *bip, struct link_client *ic, struct line *line,
|
||||
unsigned int privmsg)
|
||||
{
|
||||
int admin = LINK(ic)->user->admin;
|
||||
|
||||
if (line->elemc < privmsg + 2)
|
||||
return OK_FORGET;
|
||||
|
||||
mylog(LOG_STD, "/BIP %s from %s", line->elemv[privmsg + 1],
|
||||
mylog(LOG_INFO, "/BIP %s from %s", line->elemv[privmsg + 1],
|
||||
LINK(ic)->user->name);
|
||||
if (strcasecmp(line->elemv[privmsg + 1], "RELOAD") == 0) {
|
||||
if (!admin) {
|
||||
@ -1736,7 +1927,12 @@ int adm_bip(struct link_client *ic, struct line *line, unsigned int privmsg)
|
||||
}
|
||||
bip_notify(ic, "-- Jumping to next server");
|
||||
} else if (strcasecmp(line->elemv[privmsg + 1], "BLRESET") == 0) {
|
||||
if (line->elemc == privmsg + 3 &&
|
||||
strcmp(line->elemv[privmsg + 2], "-q") == 0) {
|
||||
log_reinit_all(LINK(ic)->log);
|
||||
} else {
|
||||
adm_blreset(ic);
|
||||
}
|
||||
} else if (strcasecmp(line->elemv[privmsg + 1], "HELP") == 0) {
|
||||
adm_bip_help(ic, admin);
|
||||
} else if (strcasecmp(line->elemv[privmsg + 1], "FOLLOW_NICK") == 0) {
|
||||
@ -1771,6 +1967,22 @@ int adm_bip(struct link_client *ic, struct line *line, unsigned int privmsg)
|
||||
bip_notify(ic, "-- AWAY_NICK command needs zero or one"
|
||||
" argument");
|
||||
}
|
||||
} else if (admin &&
|
||||
strcasecmp(line->elemv[privmsg + 1], "ADD_CONN") == 0) {
|
||||
if (line->elemc != privmsg + 4) {
|
||||
adm_reply(ic, "/BIP ADD_CONN <connection name> "
|
||||
"<network name>");
|
||||
} else {
|
||||
adm_bip_addconn(bip, ic, line->elemv[privmsg + 2],
|
||||
line->elemv[privmsg + 3]);
|
||||
}
|
||||
} else if (admin &&
|
||||
strcasecmp(line->elemv[privmsg + 1], "DEL_CONN") == 0) {
|
||||
if (line->elemc != privmsg + 3) {
|
||||
adm_reply(ic, "/BIP DEL_CONN <connection name>");
|
||||
} else {
|
||||
adm_bip_delconn(bip, ic, line->elemv[privmsg + 2]);
|
||||
}
|
||||
#ifdef HAVE_LIBSSL
|
||||
} else if (strcasecmp(line->elemv[privmsg + 1], "TRUST") == 0) {
|
||||
return adm_trust(ic, line);
|
||||
@ -1785,12 +1997,14 @@ void free_conf(list_t *l)
|
||||
{
|
||||
struct tuple *t;
|
||||
list_iterator_t li;
|
||||
|
||||
for (list_it_init(l, &li); (t = list_it_item(&li)); list_it_next(&li)) {
|
||||
switch (t->tuple_type) {
|
||||
case TUPLE_STR:
|
||||
free(t->pdata); /* no break, for the style */
|
||||
printf("freeconf: %s\n", (char *)t->pdata);
|
||||
free(t->pdata);
|
||||
break;
|
||||
case TUPLE_INT:
|
||||
free(t);
|
||||
break;
|
||||
case TUPLE_LIST:
|
||||
free_conf(t->pdata);
|
||||
@ -1799,5 +2013,8 @@ void free_conf(list_t *l)
|
||||
fatal("internal error free_conf");
|
||||
break;
|
||||
}
|
||||
free(t);
|
||||
}
|
||||
free(l);
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,8 @@
|
||||
#ifdef HAVE_LIBSSL
|
||||
int adm_trust(struct link_client *ic, struct line *line);
|
||||
#endif
|
||||
int adm_bip(struct link_client *ic, struct line *line, unsigned int privmsg);
|
||||
int adm_bip(bip_t *bip, struct link_client *ic, struct line *line,
|
||||
unsigned int privmsg);
|
||||
int ssl_check_trust(struct link_client *ic);
|
||||
void adm_blreset(struct link_client *ic);
|
||||
void bip_notify(struct link_client *ic, char *fmt, ...);
|
||||
|
25
src/conf.y
25
src/conf.y
@ -19,9 +19,7 @@
|
||||
extern int yylex (void);
|
||||
extern char *yytext;
|
||||
extern int linec;
|
||||
extern int conf_error;
|
||||
#define ERRBUFSZ 80
|
||||
extern char conf_errstr[ERRBUFSZ];
|
||||
int conf_error;
|
||||
|
||||
int yywrap()
|
||||
{
|
||||
@ -30,9 +28,7 @@ int yywrap()
|
||||
|
||||
int yyerror()
|
||||
{
|
||||
snprintf(conf_errstr, ERRBUFSZ, "Parse error near %s, line %d\n",
|
||||
yytext, linec + 1);
|
||||
conf_errstr[ERRBUFSZ - 1] = 0;
|
||||
mylog(LOG_ERROR, "Parse error near %s, line %d\n", yytext, linec + 1);
|
||||
conf_error = 1;
|
||||
return 1;
|
||||
}
|
||||
@ -114,6 +110,23 @@ command:
|
||||
| LEX_LOG_SYNC_INTERVAL LEX_EQ LEX_INT { $$ = tuple_i_new(
|
||||
LEX_LOG_SYNC_INTERVAL, $3); }
|
||||
| LEX_PID_FILE LEX_EQ LEX_STRING { $$ = tuple_s_new(LEX_PID_FILE, $3); }
|
||||
/* deprecated */
|
||||
| LEX_BACKLOG_LINES LEX_EQ LEX_INT {
|
||||
$$ = tuple_i_new(LEX_BACKLOG_LINES, $3);
|
||||
}
|
||||
| LEX_BACKLOG_NO_TIMESTAMP LEX_EQ LEX_BOOL {
|
||||
$$ = tuple_i_new(LEX_BACKLOG_NO_TIMESTAMP, $3);
|
||||
}
|
||||
| LEX_BACKLOG LEX_EQ LEX_BOOL { $$ = tuple_i_new(LEX_BACKLOG, $3); }
|
||||
| LEX_BLRESET_ON_TALK LEX_EQ LEX_BOOL {
|
||||
$$ = tuple_i_new(LEX_BLRESET_ON_TALK, $3);
|
||||
}
|
||||
| LEX_BL_MSG_ONLY LEX_EQ LEX_BOOL {
|
||||
$$ = tuple_i_new(LEX_BL_MSG_ONLY, $3);
|
||||
}
|
||||
| LEX_ALWAYS_BACKLOG LEX_EQ LEX_BOOL { $$ = tuple_i_new(
|
||||
LEX_ALWAYS_BACKLOG, $3); }
|
||||
/* /deprecated */
|
||||
| LEX_NETWORK LEX_LBRA network LEX_RBRA { $$ = tuple_l_new(LEX_NETWORK,
|
||||
$3); }
|
||||
| LEX_USER LEX_LBRA user LEX_RBRA { $$ = tuple_l_new(LEX_USER, $3); }
|
||||
|
@ -52,7 +52,7 @@ void connection_close(connection_t *cn)
|
||||
{
|
||||
mylog(LOG_DEBUG, "Connection close asked. FD:%d ",
|
||||
(long)cn->handle);
|
||||
if (cn->connected != CONN_DISCONN) {
|
||||
if (cn->connected != CONN_DISCONN && cn->connected != CONN_ERROR) {
|
||||
cn->connected = CONN_DISCONN;
|
||||
if (close(cn->handle) == -1)
|
||||
mylog(LOG_WARN, "Error on socket close: %s",
|
||||
@ -873,7 +873,8 @@ static void create_socket(char *dsthostname, char *dstport, char *srchostname,
|
||||
|
||||
err = getaddrinfo(dsthostname, dstport, &hint, &cdata->dst);
|
||||
if (err) {
|
||||
mylog(LOG_ERROR, "getaddrinfo(dst): %s", gai_strerror(err));
|
||||
mylog(LOG_ERROR, "getaddrinfo(%s): %s", dsthostname,
|
||||
gai_strerror(err));
|
||||
connecting_data_free(cdata);
|
||||
cdata = NULL;
|
||||
return;
|
||||
@ -1010,8 +1011,10 @@ connection_t *accept_new(connection_t *cn)
|
||||
|
||||
mylog(LOG_DEBUG, "Trying to accept new client on %d", cn->handle);
|
||||
err = accept(cn->handle, &sa, &sa_len);
|
||||
if (err < 0)
|
||||
if (err < 0) {
|
||||
mylog(LOG_ERROR, "accept failed: %s", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
socket_set_nonblock(err);
|
||||
|
||||
conn = connection_init(cn->anti_flood, cn->ssl, cn->timeout, 0);
|
||||
@ -1175,14 +1178,20 @@ static int bip_ssl_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
|
||||
(err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY ||
|
||||
err == X509_V_ERR_CERT_UNTRUSTED ||
|
||||
err == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE ||
|
||||
err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)) {
|
||||
err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
|
||||
err == X509_V_ERR_CERT_HAS_EXPIRED)) {
|
||||
|
||||
if (X509_STORE_get_by_subject(ctx, X509_LU_X509,
|
||||
X509_get_subject_name(err_cert), &xobj) > 0 &&
|
||||
!X509_cmp(xobj.data.x509, err_cert)) {
|
||||
|
||||
mylog(LOG_INFO, "Basic mode; peer certificate found "
|
||||
"in store, accepting it!");
|
||||
if (err == X509_V_ERR_CERT_HAS_EXPIRED)
|
||||
mylog(LOG_INFO, "Basic mode; Accepting "
|
||||
"*expired* peer certificate "
|
||||
"found in store.");
|
||||
else
|
||||
mylog(LOG_INFO, "Basic mode; Accepting peer "
|
||||
"certificate found in store.");
|
||||
|
||||
result = 1;
|
||||
err = X509_V_OK;
|
||||
|
124
src/irc.c
124
src/irc.c
@ -49,14 +49,14 @@ void oidentd_dump(list_t *connl);
|
||||
|
||||
void irc_client_free(struct link_client *cli);
|
||||
extern int conf_log_sync_interval;
|
||||
extern int conf_error;
|
||||
extern char conf_errstr[];
|
||||
|
||||
void write_user_list(connection_t *c, char *dest);
|
||||
|
||||
static void irc_copy_cli(struct link_client *src, struct link_client *dest,
|
||||
struct line *line);
|
||||
static void irc_cli_make_join(struct link_client *ic);
|
||||
static void server_setup_reconnect_timer(struct link *link);
|
||||
int irc_cli_bip(bip_t *bip, struct link_client *ic, struct line *line);
|
||||
|
||||
#define LAGOUT_TIME 480
|
||||
#define LAGCHECK_TIME (90)
|
||||
@ -377,11 +377,16 @@ int irc_dispatch_server(bip_t *bip, struct link_server *server,
|
||||
size_t nicklen = strlen(server->nick);
|
||||
char *newnick = malloc(nicklen + 2);
|
||||
strcpy(newnick, server->nick);
|
||||
if (strlen(server->nick) < 9)
|
||||
if (strlen(server->nick) < 9) {
|
||||
strcat(newnick, "`");
|
||||
else if (newnick[8] != '`') {
|
||||
} else if (newnick[7] != '`') {
|
||||
if (newnick[8] != '`') {
|
||||
newnick[8] = '`';
|
||||
newnick[9] = 0;
|
||||
} else {
|
||||
newnick[7] = '`';
|
||||
newnick[9] = 0;
|
||||
}
|
||||
} else {
|
||||
newnick[8] = rand() * ('z' - 'a') / RAND_MAX +
|
||||
'a';
|
||||
@ -601,9 +606,9 @@ void unbind_from_link(struct link_client *ic)
|
||||
fatal("realloc");
|
||||
}
|
||||
|
||||
int irc_cli_bip(struct link_client *ic, struct line *line)
|
||||
int irc_cli_bip(bip_t *bip, struct link_client *ic, struct line *line)
|
||||
{
|
||||
return adm_bip(ic, line, 0);
|
||||
return adm_bip(bip, ic, line, 0);
|
||||
}
|
||||
|
||||
#define PASS_SEP ':'
|
||||
@ -853,13 +858,14 @@ static int irc_cli_quit(struct link_client *ic, struct line *line)
|
||||
return OK_CLOSE;
|
||||
}
|
||||
|
||||
static int irc_cli_privmsg(struct link_client *ic, struct line *line)
|
||||
static int irc_cli_privmsg(bip_t *bip, struct link_client *ic,
|
||||
struct line *line)
|
||||
{
|
||||
if (line->elemc >= 3)
|
||||
log_cli_privmsg(LINK(ic)->log, LINK(ic)->l_server->nick,
|
||||
line->elemv[1], line->elemv[2]);
|
||||
if (strcmp(line->elemv[1], "-bip") == 0)
|
||||
return adm_bip(ic, line, 1);
|
||||
return adm_bip(bip, ic, line, 1);
|
||||
|
||||
if (LINK(ic)->user->blreset_on_talk)
|
||||
log_reinit_all(LINK(ic)->log);
|
||||
@ -1047,7 +1053,6 @@ static int irc_dispatch_trust_client(struct link_client *ic, struct line *line)
|
||||
}
|
||||
#endif
|
||||
|
||||
int irc_cli_bip(struct link_client *ic, struct line *line);
|
||||
static int irc_dispatch_client(bip_t *bip, struct link_client *ic,
|
||||
struct line *line)
|
||||
{
|
||||
@ -1066,7 +1071,7 @@ static int irc_dispatch_client(bip_t *bip, struct link_client *ic,
|
||||
"before sending commands\r\n");
|
||||
r = OK_FORGET;
|
||||
} else if (strcasecmp(line->elemv[0], "BIP") == 0) {
|
||||
r = irc_cli_bip(ic, line);
|
||||
r = irc_cli_bip(bip, ic, line);
|
||||
} else if (strcmp(line->elemv[0], "JOIN") == 0) {
|
||||
r = irc_cli_join(ic, line);
|
||||
} else if (strcmp(line->elemv[0], "PART") == 0) {
|
||||
@ -1076,7 +1081,7 @@ static int irc_dispatch_client(bip_t *bip, struct link_client *ic,
|
||||
} else if (strcmp(line->elemv[0], "QUIT") == 0) {
|
||||
r = irc_cli_quit(ic, line);
|
||||
} else if (strcmp(line->elemv[0], "PRIVMSG") == 0) {
|
||||
r = irc_cli_privmsg(ic, line);
|
||||
r = irc_cli_privmsg(bip, ic, line);
|
||||
} else if (strcmp(line->elemv[0], "NOTICE") == 0) {
|
||||
r = irc_cli_notice(ic, line);
|
||||
} else if (strcmp(line->elemv[0], "WHO") == 0) {
|
||||
@ -1425,11 +1430,6 @@ static void channel_free(struct channel *c)
|
||||
if (c->create_ts)
|
||||
free(c->create_ts);
|
||||
|
||||
/*
|
||||
char *l;
|
||||
while ((l = (char *)list_remove_first(&c->bans)))
|
||||
free(l);
|
||||
*/
|
||||
hash_iterator_t hi;
|
||||
for (hash_it_init(&c->nicks, &hi); hash_it_item(&hi); hash_it_next(&hi))
|
||||
nick_free(hash_it_item(&hi));
|
||||
@ -1475,7 +1475,7 @@ static int irc_part(struct link_server *server, struct line *line)
|
||||
free(s_nick);
|
||||
|
||||
log_part(LINK(server)->log, line->origin, s_chan,
|
||||
line->elemc == 3 ? line->elemv[2]:NULL);
|
||||
line->elemc == 3 ? line->elemv[2] : NULL);
|
||||
|
||||
nick_free(nick);
|
||||
return OK_COPY;
|
||||
@ -1894,7 +1894,6 @@ void server_cleanup(struct link_server *server)
|
||||
CONN(server) = NULL;
|
||||
}
|
||||
irc_lag_init(server);
|
||||
|
||||
}
|
||||
|
||||
void irc_client_close(struct link_client *ic)
|
||||
@ -1918,6 +1917,22 @@ void irc_client_close(struct link_client *ic)
|
||||
}
|
||||
}
|
||||
|
||||
static void server_setup_reconnect_timer(struct link *link)
|
||||
{
|
||||
int timer = 0;
|
||||
|
||||
if (link->last_connection_attempt &&
|
||||
time(NULL) - link->last_connection_attempt
|
||||
< CONN_INTERVAL) {
|
||||
timer = RECONN_TIMER * (link->s_conn_attempt);
|
||||
if (timer > RECONN_TIMER_MAX)
|
||||
timer = RECONN_TIMER_MAX;
|
||||
}
|
||||
mylog(LOG_ERROR, "%s dead, reconnecting in %d seconds", link->name,
|
||||
timer);
|
||||
link->recon_timer = timer;
|
||||
}
|
||||
|
||||
static void irc_close(struct link_any *l)
|
||||
{
|
||||
if (CONN(l)) {
|
||||
@ -1926,28 +1941,16 @@ static void irc_close(struct link_any *l)
|
||||
}
|
||||
if (TYPE(l) == IRC_TYPE_SERVER) {
|
||||
/* TODO: free link_server as a whole */
|
||||
int timer = 0;
|
||||
struct link_server *is = (struct link_server *)l;
|
||||
|
||||
if (LINK(is)->s_state == IRCS_CONNECTED)
|
||||
irc_notify_disconnection(is);
|
||||
else
|
||||
LINK(is)->s_conn_attempt++;
|
||||
irc_server_shutdown(is);
|
||||
log_disconnected(LINK(is)->log);
|
||||
|
||||
server_next(LINK(is));
|
||||
server_cleanup(is);
|
||||
if (LINK(is)->last_connection_attempt &&
|
||||
time(NULL) - LINK(is)->last_connection_attempt
|
||||
< CONN_INTERVAL) {
|
||||
timer = RECONN_TIMER * (LINK(is)->s_conn_attempt);
|
||||
if (timer > RECONN_TIMER_MAX)
|
||||
timer = RECONN_TIMER_MAX;
|
||||
}
|
||||
mylog(LOG_ERROR, "%s dead, reconnecting in %d seconds",
|
||||
LINK(l)->name, timer);
|
||||
LINK(is)->recon_timer = timer;
|
||||
server_setup_reconnect_timer(LINK(is));
|
||||
|
||||
LINK(is)->l_server = NULL;
|
||||
irc_server_free((struct link_server *)is);
|
||||
@ -1987,10 +1990,21 @@ struct link_server *irc_server_new(struct link *link, connection_t *conn)
|
||||
|
||||
void irc_server_free(struct link_server *s)
|
||||
{
|
||||
if (CONN(s))
|
||||
connection_free(CONN(s));
|
||||
if (s->nick)
|
||||
free(s->nick);
|
||||
if (s->user_mode)
|
||||
free(s->user_mode);
|
||||
|
||||
hash_iterator_t hi;
|
||||
for (hash_it_init(&s->channels, &hi); hash_it_item(&hi);
|
||||
hash_it_next(&hi)) {
|
||||
struct channel *chan = hash_it_item(&hi);
|
||||
channel_free(chan);
|
||||
|
||||
}
|
||||
|
||||
free(s);
|
||||
}
|
||||
|
||||
@ -1999,6 +2013,8 @@ connection_t *irc_server_connect(struct link *link)
|
||||
struct link_server *ls;
|
||||
connection_t *conn;
|
||||
|
||||
link->s_conn_attempt++;
|
||||
|
||||
mylog(LOG_INFO, "Connecting user '%s' to network '%s' using server "
|
||||
"%s:%d", link->user->name, link->name,
|
||||
link->network->serverv[link->cur_server].host,
|
||||
@ -2015,6 +2031,11 @@ connection_t *irc_server_connect(struct link *link)
|
||||
CONNECT_TIMEOUT);
|
||||
if (!conn)
|
||||
fatal("connection_new");
|
||||
if (conn->handle == -1) {
|
||||
mylog(LOG_INFO, "Cannot connect.");
|
||||
connection_free(conn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ls = irc_server_new(link, conn);
|
||||
conn->user_data = ls;
|
||||
@ -2105,10 +2126,7 @@ void oidentd_dump(list_t *connl)
|
||||
content = (char *)malloc(stats.st_size + 1);
|
||||
|
||||
if (content == NULL){
|
||||
mylog(LOG_WARN, "oidentd_dump : malloc failed, "
|
||||
"returning");
|
||||
fclose(f);
|
||||
free(filename);
|
||||
fatal("out of memory");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2154,6 +2172,7 @@ void oidentd_dump(list_t *connl)
|
||||
content[stats.st_size - 1] != '\n')
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
free(content);
|
||||
}
|
||||
|
||||
for (list_it_init(connl, &it); list_it_item(&it); list_it_next(&it)) {
|
||||
@ -2261,8 +2280,10 @@ void bip_tick(bip_t *bip)
|
||||
} else {
|
||||
if (link->recon_timer == 0) {
|
||||
connection_t *conn;
|
||||
conn = irc_server_connect(link);
|
||||
link->last_connection_attempt = time(NULL);
|
||||
conn = irc_server_connect(link);
|
||||
if (!conn)
|
||||
server_setup_reconnect_timer(link);
|
||||
} else {
|
||||
link->recon_timer--;
|
||||
}
|
||||
@ -2374,8 +2395,11 @@ void irc_main(bip_t *bip)
|
||||
{
|
||||
int timeleft = 1000;
|
||||
|
||||
/* XXX: This one MUST be first */
|
||||
/* TODO: maybe not anymore, check */
|
||||
/*
|
||||
* If the list is empty, we are starting. Otherwise we are reloading,
|
||||
* and conn_list is kept accross reloads.
|
||||
*/
|
||||
if (list_is_empty(&bip->conn_list))
|
||||
list_add_first(&bip->conn_list, bip->listener);
|
||||
|
||||
while (!sighup) {
|
||||
@ -2401,10 +2425,6 @@ void irc_main(bip_t *bip)
|
||||
bip_on_event(bip, conn);
|
||||
list_free(ready);
|
||||
}
|
||||
while (list_remove_first(&bip->conn_list))
|
||||
;
|
||||
while (list_remove_first(&bip->link_list))
|
||||
;
|
||||
while (list_remove_first(&bip->connecting_client_list))
|
||||
;
|
||||
return;
|
||||
@ -2421,12 +2441,6 @@ void irc_client_free(struct link_client *cli)
|
||||
free(cli);
|
||||
}
|
||||
|
||||
/*
|
||||
void irc_server_free(struct link_server *is)
|
||||
{
|
||||
free(is);
|
||||
}
|
||||
*/
|
||||
struct link *irc_link_new()
|
||||
{
|
||||
struct link *link;
|
||||
@ -2443,11 +2457,18 @@ struct link *irc_link_new()
|
||||
|
||||
void link_kill(bip_t *bip, struct link *link)
|
||||
{
|
||||
list_remove(&bip->conn_list, CONN(link->l_server));
|
||||
server_cleanup(link->l_server);
|
||||
irc_server_free(link->l_server);
|
||||
while (link->l_clientc) {
|
||||
struct link_client *lc = link->l_clientv[0];
|
||||
list_remove(&bip->conn_list, CONN(lc));
|
||||
unbind_from_link(lc);
|
||||
irc_client_free(lc);
|
||||
}
|
||||
|
||||
hash_remove(&link->user->connections, link->name);
|
||||
free(link->name);
|
||||
irc_close((struct link_any *)link->l_server);
|
||||
while (link->l_clientc)
|
||||
irc_close((struct link_any *)link->l_clientv[0]);
|
||||
log_free(link->log);
|
||||
MAYFREE(link->prev_nick);
|
||||
MAYFREE(link->cli_nick);
|
||||
@ -2473,5 +2494,6 @@ void link_kill(bip_t *bip, struct link *link)
|
||||
#ifdef HAVE_LIBSSL
|
||||
sk_X509_free(link->untrusted_certs);
|
||||
#endif
|
||||
free(link);
|
||||
}
|
||||
|
||||
|
@ -91,6 +91,7 @@ struct user {
|
||||
#endif
|
||||
|
||||
hash_t connections;
|
||||
int in_use; /* for mark and sweep on reload */
|
||||
};
|
||||
|
||||
struct network
|
||||
@ -158,6 +159,7 @@ struct link {
|
||||
int ssl_check_mode;
|
||||
STACK_OF(X509) *untrusted_certs;
|
||||
#endif
|
||||
int in_use; /* for mark and sweep on reload */
|
||||
};
|
||||
|
||||
struct link_connection {
|
||||
|
13
src/lex.l
13
src/lex.l
@ -16,10 +16,10 @@
|
||||
int linec = 0;
|
||||
#define YY_NO_UNPUT
|
||||
#include "util.h"
|
||||
extern int conf_error;
|
||||
extern list_t *root_list;
|
||||
void yyparse(void);
|
||||
void free_conf(list_t*);
|
||||
extern int conf_error;
|
||||
|
||||
#if 0
|
||||
/* SPANK ME WITH A SHOVEL */
|
||||
@ -30,15 +30,14 @@ void dummy_lex_FFS(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
list_t *parse_conf(FILE *file)
|
||||
list_t *parse_conf(FILE *file, int *err)
|
||||
{
|
||||
YY_BUFFER_STATE in = yy_create_buffer(file, YY_BUF_SIZE);
|
||||
yy_switch_to_buffer(in);
|
||||
conf_error = 0;
|
||||
yyparse();
|
||||
if (conf_error) {
|
||||
free_conf(root_list);
|
||||
return NULL;
|
||||
}
|
||||
yy_delete_buffer(in);
|
||||
*err = conf_error;
|
||||
return root_list;
|
||||
}
|
||||
%}
|
||||
@ -113,6 +112,6 @@ list_t *parse_conf(FILE *file)
|
||||
"{" { return LEX_LBRA; }
|
||||
"}" { return LEX_RBRA; }
|
||||
";" { return LEX_SEMICOLON; }
|
||||
. { printf("Parse error line %d, unknown character '%s'\n", linec + 1, yytext);
|
||||
. { mylog(LOG_ERROR, "Parse error in config file line %d, unknown character '%s'\n", linec + 1, yytext);
|
||||
return LEX_BUNCH; }
|
||||
%%
|
||||
|
59
src/log.c
59
src/log.c
@ -288,6 +288,7 @@ logfilegroup_t *log_find_file(log_t *logdata, char *destination)
|
||||
char *filename = NULL;
|
||||
time_t t;
|
||||
struct tm *ltime;
|
||||
struct link *l;
|
||||
|
||||
if (!ischannel(*destination))
|
||||
destination = "privates";
|
||||
@ -312,6 +313,24 @@ logfilegroup_t *log_find_file(log_t *logdata, char *destination)
|
||||
lfg = hash_get(&logdata->logfgs, destination);
|
||||
if (!lfg)
|
||||
fatal("internal log_find_file");
|
||||
/* ok we are allocating a new lfg now, let's set it up for
|
||||
* backlogging if applicable */
|
||||
if (!logdata->user)
|
||||
fatal("log_find_file: no user associated to logdata");
|
||||
if (!logdata->network)
|
||||
fatal("log_find_file: no network id associated to "
|
||||
"logdata");
|
||||
l = hash_get(&logdata->user->connections, logdata->network);
|
||||
if (!l)
|
||||
fatal("log_beautify: no connection associated to "
|
||||
"logdata");
|
||||
struct chan_info *ci = hash_get(&l->chan_infos, destination);
|
||||
if (ci && !ci->backlog) {
|
||||
lfg->track_backlog = 0;
|
||||
} else {
|
||||
lfg->track_backlog = 1;
|
||||
}
|
||||
|
||||
if (filename)
|
||||
free(filename);
|
||||
return lfg;
|
||||
@ -362,6 +381,8 @@ logfilegroup_t *log_find_file(log_t *logdata, char *destination)
|
||||
|
||||
/*
|
||||
* Da log routines
|
||||
* There are a lot of snprintf's here without enforcing the last \0 in the
|
||||
* buffer, but _log_write takes care of this for us.
|
||||
*/
|
||||
void log_join(log_t *logdata, char *ircmask, char *channel)
|
||||
{
|
||||
@ -374,9 +395,14 @@ void log_join(log_t *logdata, char *ircmask, char *channel)
|
||||
void log_part(log_t *logdata, char *ircmask, char *channel,
|
||||
char *message)
|
||||
{
|
||||
if (message)
|
||||
snprintf(logdata->buffer, LOGLINE_MAXLEN,
|
||||
"%s -!- %s has left %s [%s]", timestamp(), ircmask,
|
||||
channel, message);
|
||||
else
|
||||
snprintf(logdata->buffer, LOGLINE_MAXLEN,
|
||||
"%s -!- %s has left %s", timestamp(), ircmask,
|
||||
channel);
|
||||
log_write(logdata, channel, logdata->buffer);
|
||||
}
|
||||
|
||||
@ -634,7 +660,10 @@ void log_client_connected(log_t *logdata)
|
||||
void log_advance_backlogs(log_t* ld, logfilegroup_t *lfg)
|
||||
{
|
||||
int c;
|
||||
(void)ld;
|
||||
|
||||
if (!lfg->track_backlog)
|
||||
return;
|
||||
|
||||
if (!ld->user->backlog || ld->user->backlog_lines == 0)
|
||||
return;
|
||||
|
||||
@ -683,6 +712,9 @@ int log_has_backlog(log_t *logdata, char *destination)
|
||||
if (lfg->memlog)
|
||||
return !list_is_empty(lfg->memlog);
|
||||
|
||||
if (!lfg->track_backlog)
|
||||
return 0;
|
||||
|
||||
logfile_t *lf;
|
||||
lf = list_get_first(&lfg->file_group);
|
||||
if (lf != list_get_last(&lfg->file_group))
|
||||
@ -735,20 +767,6 @@ char *log_beautify(log_t *logdata, char *buf, char *dest)
|
||||
lots = p - sots;
|
||||
p++;
|
||||
|
||||
if (!logdata->user)
|
||||
fatal("log_beautify: no user associated to logdata");
|
||||
if (!logdata->network)
|
||||
fatal("log_beautify: no network id associated to logdata");
|
||||
l = hash_get(&logdata->user->connections, logdata->network);
|
||||
if (!l)
|
||||
fatal("log_beautify: no connection associated to logdata");
|
||||
ci = hash_get(&l->chan_infos, dest);
|
||||
if (ci && !ci->backlog) {
|
||||
mylog(LOG_DEBUG, "Skipping unwanted channel %s for backlog",
|
||||
dest);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strncmp(p, "-!-", 3) == 0) {
|
||||
if (logdata->user->bl_msg_only)
|
||||
return NULL;
|
||||
@ -900,6 +918,9 @@ char *log_backread(log_t *logdata, char *destination, int *skip)
|
||||
if (!lfg)
|
||||
return NULL;
|
||||
|
||||
if (!lfg->track_backlog)
|
||||
return NULL;
|
||||
|
||||
if (!logdata->backlogging) {
|
||||
logdata->backlogging = 1;
|
||||
mylog(LOG_DEBUG, "backlogging!");
|
||||
@ -1171,7 +1192,7 @@ log_t *log_new(struct user *user, char *network)
|
||||
fatal("out of memory");
|
||||
logdata->connected = 0;
|
||||
if (!log_all_logs)
|
||||
log_all_logs = list_new(NULL);
|
||||
log_all_logs = list_new(list_ptr_cmp);
|
||||
list_add_last(log_all_logs, logdata);
|
||||
return logdata;
|
||||
}
|
||||
@ -1182,12 +1203,16 @@ void log_free(log_t *log)
|
||||
logfilegroup_t *lfg;
|
||||
logfile_t *lf;
|
||||
|
||||
list_remove(log_all_logs, log);
|
||||
|
||||
free(log->network);
|
||||
free(log->buffer);
|
||||
|
||||
for (hash_it_init(&log->logfgs, &it); (lfg = hash_it_item(&it));
|
||||
hash_it_next(&it)) {
|
||||
log_reset(lfg);
|
||||
if ((lf = list_remove_first(&lfg->file_group)))
|
||||
logfile_free(lf);
|
||||
free(lf);
|
||||
}
|
||||
hash_clean(&log->logfgs);
|
||||
free(log);
|
||||
|
@ -46,6 +46,7 @@ typedef struct logfilegroup
|
||||
list_t *memlog;
|
||||
int memc;
|
||||
list_iterator_t backlog_it;
|
||||
int track_backlog;
|
||||
} logfilegroup_t;
|
||||
|
||||
typedef struct log {
|
||||
|
100
src/util.c
100
src/util.c
@ -42,7 +42,7 @@ int is_valid_nick(char *str)
|
||||
while (*tmp != '\0' && (isalnum(*tmp) || *tmp == '-' || *tmp == '[' ||
|
||||
*tmp == ']' || *tmp == '\\' || *tmp == '`' ||
|
||||
*tmp == '^' || *tmp == '{' || *tmp == '}' ||
|
||||
*tmp == '|'))
|
||||
*tmp == '|' || *tmp == '_' ))
|
||||
tmp++;
|
||||
return (*tmp == '\0');
|
||||
}
|
||||
@ -118,6 +118,9 @@ void _mylog(int level, char *fmt, va_list ap)
|
||||
{
|
||||
char *prefix;
|
||||
|
||||
if (!conf_log_system)
|
||||
return;
|
||||
|
||||
if (level > conf_log_level)
|
||||
return;
|
||||
|
||||
@ -126,7 +129,7 @@ void _mylog(int level, char *fmt, va_list ap)
|
||||
prefix = "FATAL: ";
|
||||
break;
|
||||
case LOG_DEBUGVERB:
|
||||
prefix = "DEBUG: ";
|
||||
prefix = "DEBUGVERB: ";
|
||||
break;
|
||||
case LOG_DEBUG:
|
||||
prefix = "DEBUG: ";
|
||||
@ -157,9 +160,6 @@ void mylog(int level, char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (!conf_log_system)
|
||||
return;
|
||||
|
||||
va_start(ap, fmt);
|
||||
_mylog(level, fmt, ap);
|
||||
va_end(ap);
|
||||
@ -308,28 +308,6 @@ void *list_remove_last(list_t *list)
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
static void *list_remove_item(list_t *l, struct list_item *li)
|
||||
{
|
||||
void *ret = li->ptr;
|
||||
if (!li->prev) {
|
||||
if (l->first != li)
|
||||
fatal("list_remove_item");
|
||||
l->first = li->next;
|
||||
} else
|
||||
li->prev->next = li->next;
|
||||
|
||||
if (!li->next) {
|
||||
if (l->last != li)
|
||||
fatal("list_remove_item");
|
||||
l->last = li->prev;
|
||||
} else
|
||||
li->next->prev = li->prev;
|
||||
free(li);
|
||||
return ret;
|
||||
}
|
||||
*/
|
||||
|
||||
void *list_remove_if_exists(list_t *list, void *ptr)
|
||||
{
|
||||
list_iterator_t li;
|
||||
@ -383,12 +361,19 @@ void list_it_init(list_t *list, list_iterator_t *ti)
|
||||
{
|
||||
ti->list = list;
|
||||
ti->cur = list->first;
|
||||
ti->next = NULL;
|
||||
}
|
||||
|
||||
void list_it_next(list_iterator_t *ti)
|
||||
{
|
||||
if (ti->cur)
|
||||
if (ti->cur) {
|
||||
if (ti->next)
|
||||
fatal("list_it_next: inconsistent interator state");
|
||||
ti->cur = ti->cur->next;
|
||||
} else if (ti->next) {
|
||||
ti->cur = ti->next;
|
||||
ti->next = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void *list_it_item(list_iterator_t *ti)
|
||||
@ -415,7 +400,8 @@ void *list_it_remove(list_iterator_t *li)
|
||||
|
||||
void *ptr = li->cur->ptr;
|
||||
struct list_item *item = li->cur;
|
||||
li->cur = li->cur->next;
|
||||
li->next = li->cur->next;
|
||||
li->cur = NULL;
|
||||
free(item);
|
||||
return ptr;
|
||||
}
|
||||
@ -555,50 +541,73 @@ void *hash_remove(hash_t *hash, char *key)
|
||||
return ptr;
|
||||
}
|
||||
|
||||
int hash_is_empty(hash_t *h)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (!list_is_empty(&h->lists[i]))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void hash_it_init(hash_t *h, hash_iterator_t *hi)
|
||||
{
|
||||
memset(hi, 0, sizeof(hash_iterator_t));
|
||||
hi->hash = h;
|
||||
|
||||
while (list_is_empty(&h->lists[hi->list]) && hi->list < 256)
|
||||
while (hi->list < 256 && list_is_empty(&h->lists[hi->list]))
|
||||
hi->list++;
|
||||
if (hi->list < 256)
|
||||
hi->cur = h->lists[hi->list].first;
|
||||
else
|
||||
hi->cur = NULL;
|
||||
list_it_init(&h->lists[hi->list], &hi->lit);
|
||||
}
|
||||
|
||||
void hash_it_next(hash_iterator_t *hi)
|
||||
{
|
||||
hash_t *hash = hi->hash;
|
||||
|
||||
hi->cur = hi->cur->next;
|
||||
while (!hi->cur) {
|
||||
list_it_next(&hi->lit);
|
||||
if (!list_it_item(&hi->lit)) {
|
||||
do {
|
||||
hi->list++;
|
||||
if (hi->list == 256) {
|
||||
hi->cur = NULL;
|
||||
if (hi->list == 256)
|
||||
return;
|
||||
}
|
||||
hi->cur = hash->lists[hi->list].first;
|
||||
} while (list_is_empty(&hi->hash->lists[hi->list]));
|
||||
list_it_init(&hi->hash->lists[hi->list], &hi->lit);
|
||||
}
|
||||
}
|
||||
|
||||
void *hash_it_item(hash_iterator_t *h)
|
||||
{
|
||||
if (!h->cur)
|
||||
struct hash_item *hi;
|
||||
|
||||
hi = list_it_item(&h->lit);
|
||||
if (!hi)
|
||||
return NULL;
|
||||
struct hash_item *hi = h->cur->ptr;
|
||||
return hi->item;
|
||||
}
|
||||
|
||||
char *hash_it_key(hash_iterator_t *h)
|
||||
{
|
||||
if (!h->cur)
|
||||
struct hash_item *hi;
|
||||
hi = list_it_item(&h->lit);
|
||||
if (!hi)
|
||||
return NULL;
|
||||
struct hash_item *hi = h->cur->ptr;
|
||||
return hi->key;
|
||||
}
|
||||
|
||||
void *hash_it_remove(hash_iterator_t *hi)
|
||||
{
|
||||
struct hash_item *hitem;
|
||||
void *ptr;
|
||||
|
||||
hitem = list_it_remove(&hi->lit);
|
||||
|
||||
ptr = hitem->item;
|
||||
free(hitem->key);
|
||||
free(hitem);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void hash_dump(hash_t *h)
|
||||
{
|
||||
hash_iterator_t it;
|
||||
@ -625,4 +634,3 @@ int ischannel(char p)
|
||||
{
|
||||
return (p == '#' || p == '&' || p == '+' || p == '!');
|
||||
}
|
||||
|
||||
|
10
src/util.h
10
src/util.h
@ -15,6 +15,7 @@
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/* Warning: must be in order, 0 = less output */
|
||||
#define LOG_STD -1
|
||||
@ -30,9 +31,11 @@
|
||||
#define HASH_DEFAULT 0
|
||||
|
||||
void mylog(int level, char *fmt, ...);
|
||||
void _mylog(int level, char *fmt, va_list ap);
|
||||
void fatal(char *fmt, ...);
|
||||
char *timestamp(void);
|
||||
struct list_item;
|
||||
struct hash_item;
|
||||
|
||||
typedef struct list {
|
||||
struct list_item *first;
|
||||
@ -43,16 +46,17 @@ typedef struct list {
|
||||
typedef struct list_iterator {
|
||||
list_t *list;
|
||||
struct list_item *cur;
|
||||
struct list_item *next;
|
||||
} list_iterator_t;
|
||||
|
||||
/* our hash is also a list */
|
||||
typedef struct hash {
|
||||
list_t lists[256];
|
||||
} hash_t;
|
||||
|
||||
typedef struct hash_iterator {
|
||||
int list;
|
||||
struct list_item *cur;
|
||||
list_iterator_t lit;
|
||||
struct hash_item *cur;
|
||||
hash_t *hash;
|
||||
} hash_iterator_t;
|
||||
|
||||
@ -102,10 +106,12 @@ void hash_insert(hash_t *hash, char *key, void *ptr);
|
||||
void *hash_get(hash_t *, char *key);
|
||||
void *hash_remove(hash_t *hash, char *key);
|
||||
void *hash_remove_if_exists(hash_t *hash, char *key);
|
||||
int hash_is_empty(hash_t *h);
|
||||
void hash_it_init(hash_t *hash, hash_iterator_t *i);
|
||||
void hash_it_next(hash_iterator_t *hi);
|
||||
void *hash_it_item(hash_iterator_t *h);
|
||||
char *hash_it_key(hash_iterator_t *h);
|
||||
void *hash_it_remove(hash_iterator_t *li);
|
||||
|
||||
int is_valid_nick(char *str);
|
||||
int is_valid_username(char *str);
|
||||
|
Loading…
Reference in New Issue
Block a user