2
* $Id: bip.c,v 1.39 2005/04/21 06:58:50 nohar Exp $
4
* This file is part of the bip project
5
* Copyright (C) 2004 2005 Arnaud Cornet and Loïc Gomez
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; either version 2 of the License, or
10
* (at your option) any later version.
11
* See the file "COPYING" for the exact licensing terms.
22
#include <sys/resource.h>
23
#include <sys/types.h>
38
char *conf_log_format;
41
unsigned short conf_port;
44
char *conf_ssl_certfile;
50
/* log options, for sure the trickiest :) */
51
int conf_log = DEFAULT_LOG;
52
int conf_log_system = DEFAULT_LOG_SYSTEM;
53
int conf_log_sync_interval = DEFAULT_LOG_SYNC_INTERVAL;
55
list_t *parse_conf(FILE *file, int *err);
56
void conf_die(bip_t *bip, char *fmt, ...);
57
static char *get_tuple_pvalue(list_t *tuple_l, int lex);
58
void bip_notify(struct link_client *ic, char *fmt, ...);
59
void adm_list_connections(struct link_client *ic, struct user *bu);
60
void free_conf(list_t *l);
63
#define OIDENTD_FILENAME ".oidentd.conf"
66
static void hash_binary(char *hex, unsigned char **password, unsigned int *seed)
72
if (strlen(hex) != 40)
73
fatal("Incorrect password format %s\n", hex);
76
for (i = 0; i < 20; i++) {
77
sscanf(hex + 2 * i, "%02x", &buf);
82
sscanf(hex, "%02x", &buf);
84
sscanf(hex + 2, "%02x", &buf);
86
sscanf(hex + 2 * 2, "%02x", &buf);
88
sscanf(hex + 2 * 3, "%02x", &buf);
94
static int add_server(bip_t *bip, struct server *s, list_t *data)
98
s->port = 6667; /* default port */
100
while ((t = list_remove_first(data))) {
103
MOVE_STRING(s->host, t->pdata);
109
fatal("Config error in server block (%d)", t->type);
111
if (t->tuple_type == TUPLE_STR && t->pdata)
117
conf_die(bip, "Server conf: host not set");
125
extern list_t *root_list;
128
void conf_die(bip_t *bip, char *fmt, ...)
133
char *error = bip_malloc(size);
137
n = vsnprintf(error, size, fmt, ap);
139
if (n > -1 && n < size) {
140
list_add_last(&bip->errors, error);
147
error = bip_realloc(error, size);
150
_mylog(LOG_ERROR, fmt, ap);
154
FILE *conf_global_log_file;
156
static pid_t daemonize(void)
160
fatal("Fork failed");
169
fatal("setsid() failed");
173
fatal("Fork failed");
184
/* This better be the very last action since fatal makes use of
185
* conf_global_log_file */
189
/* RACE CONDITION! */
190
int do_pid_stuff(void)
199
f = fopen(conf_pid_file, "r");
202
if (gethostname(hname, 1023) == -1)
203
fatal("%s %s", "gethostname", strerror(errno));
204
snprintf(longpath, 1023, "%s.%s.%ld", conf_pid_file, hname,
205
(long unsigned int)getpid());
206
if ((fd = open(longpath, O_CREAT|O_WRONLY, S_IWUSR|S_IRUSR)) == -1)
207
fatal("Cannot write to PID file (%s) %s", longpath,
209
if (link(longpath, conf_pid_file) == -1) {
211
if (stat(longpath, &buf) == -1) {
212
if (buf.st_nlink != 2) {
213
f = fopen(conf_pid_file, "r");
227
int c = fscanf(f, "%ld", &p);
230
if (c != 1 || p == 0) {
231
mylog(LOG_INFO, "pid file found but invalid "
232
"data inside. Continuing...\n");
233
if (unlink(conf_pid_file)) {
234
fatal("Cannot delete pid file '%s', "
235
"check permissions.\n",
242
int kr = kill(pid, 0);
243
if (kr == -1 && (errno == ESRCH || errno == EPERM)) {
244
/* that's not bip! */
245
if (unlink(conf_pid_file)) {
246
fatal("Cannot delete pid file '%s', check "
253
mylog(LOG_INFO, "pid file found (pid %ld).", pid);
255
"Another instance of bip is certainly runing.");
256
mylog(LOG_FATAL, "If you are sure this is not the case remove"
257
" %s.", conf_pid_file);
263
#define S_CONF "bip.conf"
265
static void usage(char *name)
268
"Usage: %s [-f config_file] [-h] [-n]\n"
269
" -f config_file: Use config_file as the configuration file\n"
270
" If no config file is given %s will try to open ~/.bip/" S_CONF "\n"
271
" -n: Don't daemonize, log in stderr\n"
272
" -v: Print version and exit\n"
273
" -h: This help\n", name, name);
277
static void version()
280
"Bip IRC Proxy - %s\n"
281
"Copyright © Arnaud Cornet and Loïc Gomez (2004 - 2008)\n"
282
"Distributed under the GNU Public License Version 2\n", BIP_VERSION);
287
void reload_config(int i)
291
_bip->reloading_client = NULL;
294
void rlimit_cpu_reached(int i)
297
mylog(LOG_WARN, "This process has reached the CPU time usage limit. "
298
"It means bip will be killed by the Operating System soon.");
301
void rlimit_bigfile_reached(int i)
304
mylog(LOG_WARN, "A file has reached the max size this process is "
305
"allowed to create. The file will not be written correctly, "
306
"an error message should follow. This is not fatal.");
312
for (list_it_init(&_bip->link_list, &it); list_it_item(&it);
314
struct link *l = list_it_item(&it);
315
struct link_server *ls = l->l_server;
316
if (ls && l->s_state == IRCS_CONNECTED) {
317
write_line_fast(CONN(ls), "QUIT :Coyote finally "
321
unlink(conf_pid_file);
325
static int add_network(bip_t *bip, list_t *data)
332
char *name = get_tuple_pvalue(data, LEX_NAME);
335
conf_die(bip, "Network with no name");
338
n = hash_get(&bip->networks, name);
340
for (i = 0; i < n->serverc; i++)
341
free(n->serverv[i].host);
346
n = bip_calloc(sizeof(struct network), 1);
347
hash_insert(&bip->networks, name, n);
350
while ((t = list_remove_first(data))) {
353
MOVE_STRING(n->name, t->pdata);
361
n->serverv = bip_realloc(n->serverv, (n->serverc + 1)
362
* sizeof(struct server));
364
memset(&n->serverv[n->serverc - 1], 0,
365
sizeof(struct server));
366
r = add_server(bip, &n->serverv[n->serverc - 1],
376
conf_die(bip, "unknown keyword in network statement");
380
if (t->tuple_type == TUPLE_STR && t->pdata)
387
void adm_bip_delconn(bip_t *bip, struct link_client *ic, const char *conn_name)
389
struct user *user = LINK(ic)->user;
392
if (!(l = hash_get(&user->connections, conn_name))) {
393
bip_notify(ic, "cannot find this connection");
397
bip_notify(ic, "deleting");
401
void adm_bip_addconn(bip_t *bip, struct link_client *ic, const char *conn_name,
402
const char *network_name)
404
struct user *user = LINK(ic)->user;
405
struct network *network;
407
/* check name uniqueness */
408
if (hash_get(&user->connections, conn_name)) {
409
bip_notify(ic, "connection name already exists for this user.");
413
/* check we know about this network */
414
network = hash_get(&bip->networks, network_name);
416
bip_notify(ic, "no such network name");
422
l->name = bip_strdup(conn_name);
423
hash_insert(&user->connections, conn_name, l);
424
list_add_last(&bip->link_list, l);
426
l->network = network;
427
l->log = log_new(user, conn_name);
429
l->ssl_check_mode = user->ssl_check_mode;
430
l->untrusted_certs = sk_X509_new_null();
434
#define SCOPY(member) l->member = (LINK(ic)->member ? bip_strdup(LINK(ic)->member) : NULL)
435
#define ICOPY(member) l->member = LINK(ic)->member
440
/* we don't copy server password */
443
ICOPY(ignore_first_nick);
445
SCOPY(no_client_away_msg);
446
/* we don't copy on_connect_send */
448
ICOPY(ssl_check_mode);
452
bip_notify(ic, "connection added, you should soon be able to connect");
455
static int add_connection(bip_t *bip, struct user *user, list_t *data)
457
struct tuple *t, *t2;
459
struct chan_info *ci;
460
char *name = get_tuple_pvalue(data, LEX_NAME);
463
conf_die(bip, "Connection with no name");
466
l = hash_get(&user->connections, name);
469
hash_insert(&user->connections, name, l);
470
list_add_last(&bip->link_list, l);
472
l->log = log_new(user, name);
474
l->ssl_check_mode = user->ssl_check_mode;
475
l->untrusted_certs = sk_X509_new_null();
479
log_reset_all(l->log);
482
while ((t = list_remove_first(data))) {
485
MOVE_STRING(l->name, t->pdata);
488
l->network = hash_get(&bip->networks, t->pdata);
490
conf_die(bip, "Undefined network %s.\n",
496
if (!is_valid_nick(t->pdata)) {
497
conf_die(bip, "Invalid nickname %s.", t->pdata);
500
MOVE_STRING(l->connect_nick, t->pdata);
503
MOVE_STRING(l->username, t->pdata);
506
MOVE_STRING(l->realname, t->pdata);
509
MOVE_STRING(l->s_password, t->pdata);
512
MOVE_STRING(l->vhost, t->pdata);
515
name = get_tuple_pvalue(t->pdata, LEX_NAME);
517
conf_die(bip, "Channel with no name");
521
ci = hash_get(&l->chan_infos, name);
523
ci = chan_info_new();
524
hash_insert(&l->chan_infos, name, ci);
525
/* FIXME: this order is not reloaded */
526
list_add_last(&l->chan_infos_order, ci);
530
while ((t2 = list_remove_first(t->pdata))) {
533
MOVE_STRING(ci->name, t2->pdata);
536
MOVE_STRING(ci->key, t2->pdata);
539
ci->backlog = t2->ndata;
542
if (t2->tuple_type == TUPLE_STR && t2->pdata)
548
case LEX_AUTOJOIN_ON_KICK:
549
l->autojoin_on_kick = t->ndata;
551
case LEX_FOLLOW_NICK:
552
l->follow_nick = t->ndata;
554
case LEX_IGN_FIRST_NICK:
555
l->ignore_first_nick = t->ndata;
557
case LEX_IGNORE_CAPAB:
558
l->ignore_server_capab = t->ndata;
561
MOVE_STRING(l->away_nick, t->pdata);
563
case LEX_NO_CLIENT_AWAY_MSG:
564
MOVE_STRING(l->no_client_away_msg, t->pdata);
566
case LEX_ON_CONNECT_SEND:
567
list_add_last(&l->on_connect_send, t->pdata);
571
case LEX_SSL_CHECK_MODE:
572
if (strcmp(t->pdata, "basic") == 0)
573
l->ssl_check_mode = SSL_CHECK_BASIC;
574
if (strcmp(t->pdata, "ca") == 0)
575
l->ssl_check_mode = SSL_CHECK_CA;
576
if (strcmp(t->pdata, "none") == 0)
577
l->ssl_check_mode = SSL_CHECK_NONE;
580
case LEX_SSL_CHECK_MODE:
581
mylog(LOG_WARN, "Found SSL option whereas bip is "
582
"not built with SSL support.");
586
conf_die(bip, "Unknown keyword in connection "
590
if (t->tuple_type == TUPLE_STR && t->pdata)
594
/* checks that can only be here, or must */
596
conf_die(bip, "Missing network in connection block");
599
if (!l->connect_nick) {
600
if (!user->default_nick) {
601
conf_die(bip, "No nick set and no default nick.");
604
l->connect_nick = bip_strdup(user->default_nick);
607
if (!user->default_username) {
608
conf_die(bip, "No username set and no default "
612
l->username = bip_strdup(user->default_username);
615
if (!user->default_realname) {
616
conf_die(bip, "No realname set and no default "
620
l->realname = bip_strdup(user->default_realname);
627
static char *get_tuple_pvalue(list_t *tuple_l, int lex)
632
for (list_it_init(tuple_l, &it); (t = list_it_item(&it));
640
static int get_tuple_nvalue(list_t *tuple_l, int lex)
645
for (list_it_init(tuple_l, &it); (t = list_it_item(&it));
653
struct historical_directives {
658
int backlog_no_timestamp;
662
static int add_user(bip_t *bip, list_t *data, struct historical_directives *hds)
667
char *name = get_tuple_pvalue(data, LEX_NAME);
668
list_t connection_list, *cl;
670
list_init(&connection_list, NULL);
673
conf_die(bip, "User with no name");
676
u = hash_get(&bip->users, name);
678
u = bip_calloc(sizeof(struct user), 1);
679
hash_insert(&bip->users, name, u);
680
hash_init(&u->connections, HASH_NOCASE);
682
u->backlog = DEFAULT_BACKLOG;
683
u->always_backlog = DEFAULT_ALWAYS_BACKLOG;
684
u->bl_msg_only = DEFAULT_BL_MSG_ONLY;
685
u->backlog_lines = DEFAULT_BACKLOG_LINES;
686
u->backlog_no_timestamp = DEFAULT_BACKLOG_NO_TIMESTAMP;
687
u->blreset_on_talk = DEFAULT_BLRESET_ON_TALK;
688
u->blreset_connection = DEFAULT_BLRESET_CONNECTION;
689
u->bip_use_notice = DEFAULT_BIP_USE_NOTICE;
693
FREE(u->default_nick);
694
FREE(u->default_username);
695
FREE(u->default_realname);
697
FREE(u->ssl_check_store);
698
FREE(u->ssl_client_certfile);
702
u->backlog = hds->backlog;
703
u->always_backlog = hds->always_backlog;
704
u->bl_msg_only = hds->bl_msg_only;
705
u->backlog_lines = hds->backlog_lines;
706
u->backlog_no_timestamp = hds->backlog_no_timestamp;
707
u->blreset_on_talk = hds->blreset_on_talk;
709
while ((t = list_remove_first(data))) {
712
MOVE_STRING(u->name, t->pdata);
718
hash_binary(t->pdata, &u->password, &u->seed);
722
case LEX_DEFAULT_NICK:
723
MOVE_STRING(u->default_nick, t->pdata);
725
case LEX_DEFAULT_USER:
726
MOVE_STRING(u->default_username, t->pdata);
728
case LEX_DEFAULT_REALNAME:
729
MOVE_STRING(u->default_realname, t->pdata);
731
case LEX_ALWAYS_BACKLOG:
732
u->always_backlog = t->ndata;
735
u->backlog = t->ndata;
737
case LEX_BL_MSG_ONLY:
738
u->bl_msg_only = t->ndata;
740
case LEX_BACKLOG_LINES:
741
u->backlog_lines = t->ndata;
743
case LEX_BACKLOG_NO_TIMESTAMP:
744
u->backlog_no_timestamp = t->ndata;
746
case LEX_BLRESET_ON_TALK:
747
u->blreset_on_talk = t->ndata;
749
case LEX_BLRESET_CONNECTION:
750
u->blreset_connection = t->ndata;
752
case LEX_BIP_USE_NOTICE:
753
u->bip_use_notice = t->ndata;
756
list_add_last(&connection_list, t->pdata);
760
case LEX_SSL_CHECK_MODE:
761
if (!strcmp(t->pdata, "basic"))
762
u->ssl_check_mode = SSL_CHECK_BASIC;
763
if (!strcmp(t->pdata, "ca"))
764
u->ssl_check_mode = SSL_CHECK_CA;
765
if (!strcmp(t->pdata, "none"))
766
u->ssl_check_mode = SSL_CHECK_NONE;
770
case LEX_SSL_CHECK_STORE:
771
MOVE_STRING(u->ssl_check_store, t->pdata);
773
case LEX_SSL_CLIENT_CERTFILE:
774
MOVE_STRING(u->ssl_client_certfile, t->pdata);
777
case LEX_SSL_CLIENT_CERTFILE:
778
case LEX_SSL_CHECK_MODE:
779
case LEX_SSL_CHECK_STORE:
780
mylog(LOG_WARN, "Found SSL option whereas bip is "
781
"not built with SSL support.");
785
conf_die(bip, "Uknown keyword in user statement");
788
if (t->tuple_type == TUPLE_STR && t->pdata)
793
conf_die(bip, "Missing password in user block");
797
while ((cl = list_remove_first(&connection_list))) {
798
r = add_connection(bip, u, cl);
808
static int validate_config(bip_t *bip)
810
/* nick username realname or default_{nick,username,realname} in user */
811
hash_iterator_t it, sit, cit;
814
struct chan_info *ci;
817
for (hash_it_init(&bip->users, &it); (user = hash_it_item(&it));
819
for (hash_it_init(&user->connections, &sit);
820
(link = hash_it_item(&sit));
821
hash_it_next(&sit)) {
822
if (!user->default_nick || !user->default_username ||
823
!user->default_realname) {
824
if ((!link->username &&
825
!user->default_username) ||
826
(!link->connect_nick &&
827
!user->default_nick) ||
829
!user->default_realname)) {
830
conf_die(bip, "user %s, "
831
"connection %s: you must defin"
832
"e nick, user and realname.",
833
user->name, link->name);
834
link_kill(bip, link);
840
for (hash_it_init(&link->chan_infos, &cit);
841
(ci = hash_it_item(&cit));
842
hash_it_next(&cit)) {
844
conf_die(bip, "user %s, "
846
"%s: channel must have"
847
"a name.", user->name,
855
if (user->backlog && !conf_log && user->backlog_lines == 0) {
856
conf_die(bip, "If conf_log = false, you must set "
858
"lines to a non-nul value for each user with"
859
"backlog = true. Faulty user is %s",
866
hash_it_init(&bip->users, &it);
868
if (hash_it_item(&it) && !strstr(conf_log_format, "%u"))
869
mylog(LOG_WARN, "log_format does not contain %%u, all users'"
870
" logs will be mixed !");
874
void clear_marks(bip_t *bip)
879
for (list_it_init(&bip->link_list, &lit); list_it_item(&lit);
881
((struct link *)list_it_item(&lit))->in_use = 0;
882
for (hash_it_init(&bip->users, &hit); hash_it_item(&hit);
884
((struct user *)hash_it_item(&hit))->in_use = 0;
887
void user_kill(bip_t *bip, struct user *user)
890
if (!hash_is_empty(&user->connections))
891
fatal("user_kill, user still has connections");
893
free(user->password);
894
MAYFREE(user->default_nick);
895
MAYFREE(user->default_username);
896
MAYFREE(user->default_realname);
899
MAYFREE(user->ssl_check_store);
900
MAYFREE(user->ssl_client_certfile);
905
void sweep(bip_t *bip)
910
for (list_it_init(&bip->link_list, &lit); list_it_item(&lit);
911
list_it_next(&lit)) {
912
struct link *l = ((struct link *)list_it_item(&lit));
914
mylog(LOG_INFO, "Administratively killing %s/%s",
915
l->user->name, l->name);
916
list_remove_if_exists(&bip->conn_list, l);
918
list_it_remove(&lit);
921
for (hash_it_init(&bip->users, &hit); hash_it_item(&hit);
922
hash_it_next(&hit)) {
923
struct user *u = (struct user *)hash_it_item(&hit);
925
hash_it_remove(&hit);
931
int fireup(bip_t *bip, FILE *conf)
936
struct historical_directives hds;
940
while ((l = list_remove_first(&bip->errors)))
942
parse_conf(conf, &err);
944
free_conf(root_list);
949
#define SET_HV(d, n) do {\
950
int __gtv = get_tuple_nvalue(root_list, LEX_##n);\
956
SET_HV(hds.always_backlog, ALWAYS_BACKLOG);
957
SET_HV(hds.backlog, BACKLOG);
958
SET_HV(hds.bl_msg_only, BL_MSG_ONLY);
959
SET_HV(hds.backlog_lines, BACKLOG_LINES);
960
SET_HV(hds.backlog_no_timestamp, BACKLOG_NO_TIMESTAMP);
961
SET_HV(hds.blreset_on_talk, BLRESET_ON_TALK);
964
while ((t = list_remove_first(root_list))) {
966
case LEX_LOG_SYNC_INTERVAL:
967
conf_log_sync_interval = t->ndata;
973
conf_log_system = t->ndata;
976
MOVE_STRING(conf_log_root, t->pdata);
979
MOVE_STRING(conf_log_format, t->pdata);
982
conf_log_level = t->ndata;
985
MOVE_STRING(conf_ip, t->pdata);
988
conf_port = t->ndata;
995
MOVE_STRING(conf_ssl_certfile, t->pdata);
1000
mylog(LOG_WARN, "Found SSL option whereas bip is "
1001
"not built with SSL support.");
1005
MOVE_STRING(conf_pid_file, t->pdata);
1007
case LEX_ALWAYS_BACKLOG:
1008
hds.always_backlog = t->ndata;
1011
hds.backlog = t->ndata;
1013
case LEX_BL_MSG_ONLY:
1014
hds.bl_msg_only = t->ndata;
1016
case LEX_BACKLOG_LINES:
1017
hds.backlog_lines = t->ndata;
1019
case LEX_BACKLOG_NO_TIMESTAMP:
1020
hds.backlog_no_timestamp = t->ndata;
1022
case LEX_BLRESET_ON_TALK:
1023
hds.blreset_on_talk = t->ndata;
1026
r = add_network(bip, t->pdata);
1027
list_free(t->pdata);
1029
goto out_conf_error;
1032
r = add_user(bip, t->pdata, &hds);
1033
list_free(t->pdata);
1035
goto out_conf_error;
1038
conf_die(bip, "Config error in base config (%d)",
1040
goto out_conf_error;
1042
if (t->tuple_type == TUPLE_STR && t->pdata)
1049
if (validate_config(bip)) {
1056
free_conf(root_list);
1061
static void log_file_setup(void)
1065
if (conf_log_system && conf_daemonize) {
1066
if (conf_global_log_file && conf_global_log_file != stderr)
1067
fclose(conf_global_log_file);
1068
snprintf(buf, 4095, "%s/bip.log", conf_log_root);
1069
FILE *f = fopen(buf, "a");
1071
fatal("Can't open %s: %s", buf, strerror(errno));
1072
conf_global_log_file = f;
1074
conf_global_log_file = stderr;
1078
void check_rlimits()
1086
r = getrlimit(RLIMIT_AS, <);
1088
mylog(LOG_ERROR, "getrlimit(): failed with %s",
1091
if (lt.rlim_max != RLIM_INFINITY) {
1092
mylog(LOG_WARN, "virtual memory rlimit active, "
1093
"bip may be KILLED by the system");
1099
r = getrlimit(RLIMIT_CPU, <);
1101
mylog(LOG_ERROR, "getrlimit(): failed with %s",
1104
if (lt.rlim_max != RLIM_INFINITY) {
1105
mylog(LOG_WARN, "CPU rlimit active, bip may "
1106
"be OFTEN KILLED by the system");
1111
r = getrlimit(RLIMIT_FSIZE, <);
1113
mylog(LOG_ERROR, "getrlimit(): failed with %s",
1116
if (lt.rlim_max != RLIM_INFINITY) {
1117
mylog(LOG_WARN, "FSIZE rlimit active, bip will "
1118
"fail to create files of size greater than "
1119
"%d bytes.", (int)lt.rlim_max);
1124
r = getrlimit(RLIMIT_NOFILE, <);
1126
mylog(LOG_ERROR, "getrlimit(): failed with %s",
1129
if (lt.rlim_max != RLIM_INFINITY && lt.rlim_max < 256) {
1130
mylog(LOG_WARN, "opened files count rlimit "
1131
"active, bip will not be allowed to open more "
1132
"than %d files at a time", (int)lt.rlim_max);
1137
r = getrlimit(RLIMIT_STACK, <);
1139
mylog(LOG_ERROR, "getrlimit(): failed with %s",
1142
if (lt.rlim_max != RLIM_INFINITY) {
1143
mylog(LOG_WARN, "stack rlimit active, "
1144
"bip may be KILLED by the system");
1150
mylog(LOG_WARN, "You can check your limits with `ulimit -a'");
1153
int main(int argc, char **argv)
1156
char *confpath = NULL;
1165
conf_ip = bip_strdup("0.0.0.0");
1169
signal(SIGPIPE, SIG_IGN);
1170
signal(SIGHUP, reload_config);
1171
signal(SIGINT, bad_quit);
1172
signal(SIGQUIT, bad_quit);
1173
signal(SIGTERM, bad_quit);
1174
signal(SIGXFSZ, rlimit_bigfile_reached);
1175
signal(SIGXCPU, rlimit_cpu_reached);
1177
conf_log_root = NULL;
1178
conf_log_format = bip_strdup(DEFAULT_LOG_FORMAT);
1179
conf_log_level = DEFAULT_LOG_LEVEL;
1181
conf_global_log_file = stderr;
1182
conf_pid_file = NULL;
1184
conf_ssl_certfile = NULL;
1187
while ((ch = getopt(argc, argv, "hvnf:s:")) != -1) {
1190
confpath = bip_strdup(optarg);
1196
conf_biphome = bip_strdup(optarg);
1212
char *home = NULL; /* oidentd path searching ignores conf_biphome */
1213
home = getenv("HOME");
1215
conf_die(&bip, "no $HOME !, do you live in a trailer ?");
1219
bip.oidentdpath = bip_malloc(strlen(home) + 1 +
1220
strlen(OIDENTD_FILENAME) + 1);
1221
strcpy(bip.oidentdpath, home);
1222
strcat(bip.oidentdpath, "/");
1223
strcat(bip.oidentdpath, OIDENTD_FILENAME);
1227
if (!conf_biphome) {
1228
conf_biphome = bip_malloc(strlen(home) + strlen("/.bip") + 1);
1229
strcpy(conf_biphome, home);
1230
strcat(conf_biphome, "/.bip");
1234
confpath = bip_malloc(strlen(conf_biphome) + 1 +
1235
strlen(S_CONF) + 1);
1236
strcpy(confpath, conf_biphome);
1237
strcat(confpath, "/");
1238
strcat(confpath, S_CONF);
1240
conf = fopen(confpath, "r");
1242
fatal("config file not found");
1244
r = fireup(&bip, conf);
1247
fatal("Not starting: error in config file.");
1249
if (!conf_log_root) {
1251
conf_log_root = bip_malloc(strlen(conf_biphome) +
1253
strcpy(conf_log_root, conf_biphome);
1254
strcat(conf_log_root, ap);
1255
mylog(LOG_INFO, "Default log root: %s", conf_log_root);
1257
if (!conf_pid_file) {
1258
char *pid = "/bip.pid";
1259
conf_pid_file = bip_malloc(strlen(conf_biphome) +
1261
strcpy(conf_pid_file, conf_biphome);
1262
strcat(conf_pid_file, pid);
1263
mylog(LOG_INFO, "Default pid file: %s", conf_pid_file);
1271
if (!conf_ssl_certfile) {
1272
char *ap = "/bip.pem";
1273
conf_ssl_certfile = bip_malloc(strlen(conf_biphome) +
1275
strcpy(conf_ssl_certfile, conf_biphome);
1276
strcat(conf_ssl_certfile, ap);
1277
mylog(LOG_INFO, "Using default SSL certificate file: "
1278
"%s", conf_ssl_certfile);
1281
if ((fd = open(conf_ssl_certfile, O_RDONLY)) == -1)
1282
fatal("Unable to open PEM file %s for reading",
1287
e = stat(conf_ssl_certfile, &fs);
1289
mylog(LOG_WARN, "Unable to check PEM file, stat(%s): "
1290
"%s", conf_ssl_certfile, strerror(errno));
1291
else if ((fs.st_mode & S_IROTH) | (fs.st_mode & S_IWOTH))
1292
mylog(LOG_ERROR, "PEM file %s should not be world "
1293
"readable / writable. Please fix the modes.",
1298
check_dir(conf_log_root, 1);
1299
fd = do_pid_stuff();
1307
snprintf(buf, 29, "%ld\n", (long unsigned int)pid);
1308
write(fd, buf, strlen(buf));
1311
bip.listener = listen_new(conf_ip, conf_port, conf_css);
1313
fatal("Could not create listening socket");
1320
conf = fopen(confpath, "r");
1322
fatal("%s config file not found", confpath);
1326
/* re-open to allow logfile rotate */
1332
#define RET_STR_LEN 256
1333
#define LINE_SIZE_LIM 70
1334
void adm_print_connection(struct link_client *ic, struct link *lnk,
1337
hash_iterator_t lit;
1338
char buf[RET_STR_LEN + 1];
1344
bip_notify(ic, "* %s to %s as \"%s\" (%s!%s) :", lnk->name,
1346
(lnk->realname ? lnk->realname : bu->default_realname),
1347
(lnk->connect_nick ? lnk->connect_nick : bu->default_nick),
1348
(lnk->username ? lnk->username : bu->default_username));
1350
t_written = snprintf(buf, RET_STR_LEN, " Options:");
1351
if (t_written >= RET_STR_LEN)
1353
if (lnk->follow_nick) {
1354
t_written += snprintf(buf + t_written,
1355
RET_STR_LEN - t_written, " follow_nick");
1356
if (t_written >= RET_STR_LEN)
1359
if (lnk->ignore_first_nick) {
1360
t_written += snprintf(buf + t_written,
1361
RET_STR_LEN - t_written, " ignore_first_nick");
1362
if (t_written >= RET_STR_LEN)
1365
if (lnk->away_nick) {
1366
t_written += snprintf(buf + t_written,
1367
RET_STR_LEN - t_written, " away_nick=%s",
1369
if (t_written >= RET_STR_LEN)
1372
if (lnk->no_client_away_msg) {
1373
t_written += snprintf(buf + t_written,
1374
RET_STR_LEN - t_written, " no_client_away_msg=%s",
1375
lnk->no_client_away_msg);
1376
if (t_written >= RET_STR_LEN)
1380
t_written += snprintf(buf + t_written,
1381
RET_STR_LEN - t_written, " vhost=%s",
1383
if (t_written >= RET_STR_LEN)
1386
if (lnk->bind_port) {
1387
t_written += snprintf(buf + t_written,
1388
RET_STR_LEN - t_written, " bind_port=%u",
1390
if (t_written >= RET_STR_LEN)
1393
noroom: /* that means the line is larger that RET_STR_LEN. We're not likely to
1394
even read such a long line */
1395
buf[RET_STR_LEN] = 0;
1396
bip_notify(ic, "%s", buf);
1398
// TODO: on_connect_send
1400
// TODO : check channels struct
1401
t_written = snprintf(buf, RET_STR_LEN, " Channels (* with key, ` no backlog)");
1402
if (t_written >= RET_STR_LEN)
1404
for (hash_it_init(&lnk->chan_infos, &lit); hash_it_item(&lit);
1405
hash_it_next(&lit)) {
1406
struct chan_info *ch = hash_it_item(&lit);
1408
t_written += snprintf(buf + t_written, RET_STR_LEN - t_written, " %s%s%s",
1409
ch->name, (ch->key ? "*" : ""),
1410
(ch->backlog ? "" : "`"));
1411
if (t_written > LINE_SIZE_LIM) {
1412
buf[RET_STR_LEN] = 0;
1413
bip_notify(ic, "%s", buf);
1418
buf[RET_STR_LEN] = 0;
1419
bip_notify(ic, "%s", buf);
1421
t_written = snprintf(buf, RET_STR_LEN, " Status: ");
1422
if (t_written >= RET_STR_LEN)
1424
switch (lnk->s_state) {
1426
t_written += snprintf(buf + t_written, RET_STR_LEN - t_written,
1428
if (t_written >= RET_STR_LEN)
1431
case IRCS_CONNECTING:
1432
t_written += snprintf(buf + t_written, RET_STR_LEN - t_written,
1433
"connecting... attempts: %d, last: %s",
1434
lnk->s_conn_attempt,
1435
hrtime(lnk->last_connection_attempt));
1436
if (t_written >= RET_STR_LEN)
1439
case IRCS_CONNECTED:
1440
t_written += snprintf(buf + t_written, RET_STR_LEN - t_written,
1442
if (t_written >= RET_STR_LEN)
1445
case IRCS_WAS_CONNECTED:
1446
t_written += snprintf(buf + t_written, RET_STR_LEN - t_written,
1447
"disconnected, attempts: %d, last: %s",
1448
lnk->s_conn_attempt,
1449
hrtime(lnk->last_connection_attempt));
1450
if (t_written >= RET_STR_LEN)
1453
case IRCS_RECONNECTING:
1454
t_written += snprintf(buf + t_written, RET_STR_LEN - t_written,
1455
"reconnecting... attempts: %d, last: %s",
1456
lnk->s_conn_attempt,
1457
hrtime(lnk->last_connection_attempt));
1458
if (t_written >= RET_STR_LEN)
1461
case IRCS_TIMER_WAIT:
1462
t_written += snprintf(buf + t_written, RET_STR_LEN - t_written,
1463
"waiting to reconnect, attempts: %d, last: %s",
1464
lnk->s_conn_attempt,
1465
hrtime(lnk->last_connection_attempt));
1466
if (t_written >= RET_STR_LEN)
1470
t_written += snprintf(buf + t_written, RET_STR_LEN - t_written,
1472
if (t_written >= RET_STR_LEN)
1475
// s_conn_attempt recon_timer last_connection_attempt
1478
buf[RET_STR_LEN] = 0;
1479
bip_notify(ic, "%s", buf);
1482
void adm_list_all_links(struct link_client *ic)
1486
bip_notify(ic, "-- All links");
1487
for (list_it_init(&_bip->link_list, &it); list_it_item(&it);
1488
list_it_next(&it)) {
1489
struct link *l = list_it_item(&it);
1491
adm_print_connection(ic, l, NULL);
1493
bip_notify(ic, "-- End of All links");
1496
void adm_list_all_connections(struct link_client *ic)
1500
bip_notify(ic, "-- All connections");
1501
for (hash_it_init(&_bip->users, &it); hash_it_item(&it);
1502
hash_it_next(&it)) {
1503
struct user *u = hash_it_item(&it);
1505
adm_list_connections(ic, u);
1507
bip_notify(ic, "-- End of All connections");
1510
#define STRORNULL(s) ((s) == NULL ? "unset" : (s))
1512
void adm_info_user(struct link_client *ic, const char *name)
1515
char buf[RET_STR_LEN + 1];
1518
bip_notify(ic, "-- User '%s' info", name);
1519
u = hash_get(&_bip->users, name);
1521
bip_notify(ic, "Unknown user");
1525
t_written += snprintf(buf + t_written, RET_STR_LEN - t_written,
1526
"user: %s", u->name);
1527
if (t_written >= RET_STR_LEN)
1530
t_written += snprintf(buf + t_written, RET_STR_LEN - t_written,
1532
if (t_written >= RET_STR_LEN)
1537
buf[RET_STR_LEN] = 0;
1538
bip_notify(ic, "%s", buf);
1541
bip_notify(ic, "SSL check mode '%s', stored into '%s'",
1542
checkmode2text(u->ssl_check_mode),
1543
STRORNULL(u->ssl_check_store));
1544
if (u->ssl_client_certfile)
1545
bip_notify(ic, "SSL client certificate stored into '%s'",
1546
u->ssl_client_certfile);
1548
bip_notify(ic, "Defaults nick: %s, user: %s, realname: %s",
1549
STRORNULL(u->default_nick), STRORNULL(u->default_username),
1550
STRORNULL(u->default_realname));
1552
bip_notify(ic, "Backlog enabled, lines: %d, no timestamp: %s,"
1553
" messages only: %s", u->backlog_lines,
1554
bool2text(u->backlog_no_timestamp),
1555
bool2text(u->bl_msg_only));
1556
bip_notify(ic, "always backlog: %s, reset on talk: %s",
1557
bool2text(u->always_backlog),
1558
bool2text(u->blreset_on_talk));
1560
bip_notify(ic, "Backlog disabled");
1562
adm_list_connections(ic, u);
1563
bip_notify(ic, "-- End of User '%s' info", name);
1566
void adm_list_users(struct link_client *ic)
1569
hash_iterator_t lit;
1570
char buf[RET_STR_LEN + 1];
1575
bip_notify(ic, "-- User list");
1576
for (hash_it_init(&_bip->users, &it); hash_it_item(&it);
1577
hash_it_next(&it)) {
1578
struct user *u = hash_it_item(&it);
1582
buf[RET_STR_LEN] = 0;
1583
t_written += snprintf(buf, RET_STR_LEN, "* %s%s:", u->name,
1584
(u->admin ? "(admin)": ""));
1585
if (t_written >= RET_STR_LEN)
1587
for (hash_it_init(&u->connections, &lit); hash_it_item(&lit);
1588
hash_it_next(&lit)) {
1589
struct link *lnk = hash_it_item(&lit);
1593
t_written += snprintf(buf + t_written,
1594
RET_STR_LEN - t_written, ",");
1595
if (t_written >= RET_STR_LEN)
1599
t_written += snprintf(buf + t_written,
1600
RET_STR_LEN - t_written,
1602
if (t_written >= RET_STR_LEN)
1604
if (t_written > LINE_SIZE_LIM) {
1605
buf[RET_STR_LEN] = 0;
1606
bip_notify(ic, "%s", buf);
1611
buf[RET_STR_LEN] = 0;
1612
bip_notify(ic, "%s", buf);
1614
bip_notify(ic, "-- End of User list");
1617
void adm_list_networks(struct link_client *ic)
1620
char buf[RET_STR_LEN + 1];
1625
bip_notify(ic, "-- Network list (* means SSL):");
1626
for (hash_it_init(&_bip->networks, &it); hash_it_item(&it);
1627
hash_it_next(&it)) {
1628
struct network *n = hash_it_item(&it);
1632
buf[RET_STR_LEN] = 0;
1635
t_written += snprintf(buf, RET_STR_LEN, "- %s*:",
1637
if (t_written >= RET_STR_LEN)
1641
t_written += snprintf(buf, RET_STR_LEN, "- %s:", n->name);
1642
if (t_written >= RET_STR_LEN)
1647
for (i = 0; i < n->serverc; i++) {
1648
struct server *serv = i+n->serverv;
1649
t_written += snprintf(buf + t_written, RET_STR_LEN
1650
- t_written, " %s:%d", serv->host,
1652
if (t_written >= RET_STR_LEN)
1654
if (t_written > LINE_SIZE_LIM) {
1655
buf[RET_STR_LEN] = 0;
1656
bip_notify(ic, "%s", buf);
1661
buf[RET_STR_LEN] = 0;
1662
bip_notify(ic, "%s", buf);
1664
bip_notify(ic, "-- End of Network list");
1667
void adm_list_connections(struct link_client *ic, struct user *bu)
1674
bip_notify(ic, "-- Your connections:");
1675
bu = LINK(ic)->user;
1677
bip_notify(ic, "-- User %s's connections:", bu->name);
1680
for (hash_it_init(&bu->connections, &it); hash_it_item(&it);
1681
hash_it_next(&it)) {
1682
struct link *lnk= hash_it_item(&it);
1683
adm_print_connection(ic, lnk, bu);
1685
bip_notify(ic, "-- End of Connection list");
1689
int link_add_untrusted(struct link_server *ls, X509 *cert)
1693
/* Check whether the cert is already in the stack */
1694
for (i = 0; i < sk_X509_num(LINK(ls)->untrusted_certs); i++) {
1696
sk_X509_value(LINK(ls)->untrusted_certs, i)))
1700
return sk_X509_push(LINK(ls)->untrusted_certs, cert);
1703
int ssl_check_trust(struct link_client *ic)
1705
X509 *trustcert = NULL;
1708
unsigned char fp[EVP_MAX_MD_SIZE];
1709
char fpstr[EVP_MAX_MD_SIZE * 3 + 20];
1713
if(!LINK(ic)->untrusted_certs ||
1714
sk_X509_num(LINK(ic)->untrusted_certs) <= 0)
1717
trustcert = sk_X509_value(LINK(ic)->untrusted_certs, 0);
1718
strcpy(subject, "Subject: ");
1719
strcpy(issuer, "Issuer: ");
1720
strcpy(fpstr, "MD5 fingerprint: ");
1721
X509_NAME_oneline(X509_get_subject_name(trustcert), subject + 9, 256);
1722
X509_NAME_oneline(X509_get_issuer_name(trustcert), issuer + 9, 256);
1724
X509_digest(trustcert, EVP_md5(), fp, &fplen);
1725
for(i = 0; i < (int)fplen; i++)
1726
sprintf(fpstr + 17 + (i * 3), "%02X%c",
1727
fp[i], (i == (int)fplen - 1) ? '\0' : ':');
1729
WRITE_LINE2(CONN(ic), P_SERV, "NOTICE", "TrustEm",
1730
"This server SSL certificate was not "
1731
"accepted because it is not in your store "
1732
"of trusted certificates:");
1734
WRITE_LINE2(CONN(ic), P_SERV, "NOTICE", "TrustEm", subject);
1735
WRITE_LINE2(CONN(ic), P_SERV, "NOTICE", "TrustEm", issuer);
1736
WRITE_LINE2(CONN(ic), P_SERV, "NOTICE", "TrustEm", fpstr);
1738
WRITE_LINE2(CONN(ic), P_SERV, "NOTICE", "TrustEm",
1739
"WARNING: if you've already trusted a "
1740
"certificate for this server before, that "
1741
"probably means it has changed.");
1743
WRITE_LINE2(CONN(ic), P_SERV, "NOTICE", "TrustEm",
1744
"If so, YOU MAY BE SUBJECT OF A "
1745
"MAN-IN-THE-MIDDLE ATTACK! PLEASE DON'T TRUST "
1746
"THIS CERTIFICATE IF YOU'RE NOT SURE THIS IS "
1749
WRITE_LINE2(CONN(ic), P_SERV, "NOTICE", "TrustEm",
1750
"Type /QUOTE BIP TRUST OK to trust this "
1751
"certificate, /QUOTE BIP TRUST NO to discard it.");
1757
static int ssl_trust_next_cert(struct link_client *ic)
1762
static int ssl_discard_next_cert(struct link_client *ic)
1770
int adm_trust(struct link_client *ic, struct line *line)
1772
if (ic->allow_trust != 1) {
1773
mylog(LOG_ERROR, "User attempted TRUST command without "
1774
"being allowed to!");
1775
unbind_from_link(ic);
1779
if(!LINK(ic)->untrusted_certs ||
1780
sk_X509_num(LINK(ic)->untrusted_certs) <= 0) {
1781
/* shouldn't have been asked to /QUOTE BIP TRUST but well... */
1782
WRITE_LINE2(CONN(ic), P_SERV, "NOTICE", "TrustEm",
1783
"No untrusted certificates.");
1784
return ERR_PROTOCOL;
1787
if (irc_line_count(line) != 3)
1788
return ERR_PROTOCOL;
1790
if (irc_line_elem_case_equals(line, 2, "OK")) {
1791
/* OK, attempt to trust the cert! */
1792
BIO *bio = BIO_new_file(LINK(ic)->user->ssl_check_store, "a+");
1793
X509 *trustcert = sk_X509_shift(LINK(ic)->untrusted_certs);
1795
if(!bio || !trustcert ||
1796
PEM_write_bio_X509(bio, trustcert) <= 0)
1797
write_line_fast(CONN(ic), ":irc.bip.net NOTICE pouet "
1798
":==== Error while trusting test!\r\n");
1800
write_line_fast(CONN(ic), ":irc.bip.net NOTICE pouet "
1801
":==== Certificate now trusted.\r\n");
1804
X509_free(trustcert);
1805
} else if (irc_line_elem_case_equals(line, 2, "NO")) {
1806
/* NO, discard the cert! */
1807
write_line_fast(CONN(ic), ":irc.bip.net NOTICE pouet "
1808
":==== Certificate discarded.\r\n");
1810
X509_free(sk_X509_shift(LINK(ic)->untrusted_certs));
1812
return ERR_PROTOCOL;
1814
if (!ssl_check_trust(ic)) {
1815
write_line_fast(CONN(ic), ":irc.bip.net NOTICE pouet "
1816
":No more certificates waiting awaiting "
1817
"user trust, thanks!\r\n");
1818
write_line_fast(CONN(ic), ":irc.bip.net NOTICE pouet "
1819
":If the certificate is trusted, bip should "
1820
"be able to connect to the server on the "
1821
"next retry. Please wait a while and try "
1822
"connecting your client again.\r\n");
1824
LINK(ic)->recon_timer = 1; /* Speed up reconnection... */
1825
unbind_from_link(ic);
1832
void _bip_notify(struct link_client *ic, char *fmt, va_list ap)
1837
if (LINK(ic)->l_server)
1838
nick = LINK(ic)->l_server->nick;
1840
nick = LINK(ic)->prev_nick;
1842
vsnprintf(str, 4095, fmt, ap);
1844
WRITE_LINE2(CONN(ic), P_IRCMASK, (LINK(ic)->user->bip_use_notice ?
1845
"NOTICE" : "PRIVMSG"), nick, str);
1848
void bip_notify(struct link_client *ic, char *fmt, ...)
1853
_bip_notify(ic, fmt, ap);
1857
void adm_blreset(struct link_client *ic)
1859
log_reset_all(LINK(ic)->log);
1860
bip_notify(ic, "backlog resetted for this network.");
1863
void adm_blreset_store(struct link_client *ic, const char *store)
1865
log_reset_store(LINK(ic)->log, store);
1866
bip_notify(ic, "backlog resetted for %s.", store);
1869
void adm_follow_nick(struct link_client *ic, const char *val)
1871
struct link *link = LINK(ic);
1872
if (strcasecmp(val, "TRUE") == 0) {
1873
link->follow_nick = 1;
1874
bip_notify(ic, "follow_nick is now true.");
1876
link->follow_nick = 0;
1877
bip_notify(ic, "follow_nick is now false.");
1881
void adm_ignore_first_nick(struct link_client *ic, const char *val)
1883
struct link *link = LINK(ic);
1884
if (strcasecmp(val, "TRUE") == 0) {
1885
link->ignore_first_nick = 1;
1886
bip_notify(ic, "ignore_first_nick is now true.");
1888
link->ignore_first_nick = 0;
1889
bip_notify(ic, "ignore_first_nick is now false.");
1893
void set_on_connect_send(struct link_client *ic, char *val)
1895
struct link *link = LINK(ic);
1899
list_add_last(&link->on_connect_send, bip_strdup(val));
1900
bip_notify(ic, "added to on_connect_send.");
1902
s = list_remove_last(&link->on_connect_send);
1905
bip_notify(ic, "last on_connect_send string deleted.");
1909
#define ON_CONNECT_MAX_STRSIZE 1024
1910
void adm_on_connect_send(struct link_client *ic, struct line *line,
1911
unsigned int privmsg)
1913
char buf[ON_CONNECT_MAX_STRSIZE];
1918
set_on_connect_send(ic, NULL);
1922
if (irc_line_includes(line, 2))
1925
for (i = privmsg + 2; i < irc_line_count(line); i++) {
1927
t_written += snprintf(buf,
1928
ON_CONNECT_MAX_STRSIZE - 1 - t_written,
1929
" %s", irc_line_elem(line, i));
1930
if (t_written >= ON_CONNECT_MAX_STRSIZE)
1933
t_written = snprintf(buf, ON_CONNECT_MAX_STRSIZE - 1,
1934
"%s", irc_line_elem(line, i));
1935
if (t_written >= ON_CONNECT_MAX_STRSIZE)
1940
buf[ON_CONNECT_MAX_STRSIZE - 1] = 0;
1941
set_on_connect_send(ic, buf);
1944
bip_notify(ic, "on connect send string too big, truncated");
1948
void adm_away_nick(struct link_client *ic, const char *val)
1950
struct link *link = LINK(ic);
1951
if (link->away_nick) {
1952
free(link->away_nick);
1953
link->away_nick = NULL;
1956
link->away_nick = bip_strdup(val);
1957
bip_notify(ic, "away_nick set.");
1959
bip_notify(ic, "away_nick cleared.");
1963
void adm_bip_help(struct link_client *ic, int admin, const char *subhelp)
1965
if (subhelp == NULL) {
1967
bip_notify(ic, "/BIP RELOAD # Re-read bip "
1968
"configuration and apply changes.");
1969
bip_notify(ic, "/BIP INFO user <username> "
1970
"# show a user's configuration");
1971
bip_notify(ic, "/BIP LIST networks|users|connections|"
1972
"all_links|all_connections");
1973
bip_notify(ic, "/BIP ADD_CONN <connection name> "
1975
bip_notify(ic, "/BIP DEL_CONN <connection name>");
1977
bip_notify(ic, "/BIP LIST networks|connections");
1979
bip_notify(ic, "/BIP JUMP # jump to next server (in same "
1981
bip_notify(ic, "/BIP BLRESET [channel|query]# reset backlog "
1982
"(this connection only). Add -q flag and the "
1983
"operation is quiet. You can specify a channel "
1984
"or a nick to reset only this channel/query.");
1985
bip_notify(ic, "/BIP HELP [subhelp] # show this help...");
1986
bip_notify(ic, "## Temporary changes for this connection:");
1987
bip_notify(ic, "/BIP FOLLOW_NICK|IGNORE_FIRST_NICK TRUE|FALSE");
1988
bip_notify(ic, "/BIP ON_CONNECT_SEND <str> # Adds a string to "
1990
bip_notify(ic, "/BIP ON_CONNECT_SEND # Clears on_connect_send");
1991
bip_notify(ic, "/BIP AWAY_NICK <nick> # Set away nick");
1992
bip_notify(ic, "/BIP AWAY_NICK # clear away nick");
1993
bip_notify(ic, "/BIP BACKLOG [n] # backlog text of the n last "
1995
} else if (admin && strcasecmp(subhelp, "RELOAD") == 0) {
1996
bip_notify(ic, "/BIP RELOAD (admin only) :");
1997
bip_notify(ic, " Reloads bip configuration file and apply "
1999
bip_notify(ic, " Please note that changes to 'user' or "
2000
"'realname' will not be applied without a JUMP.");
2001
} else if (admin && strcasecmp(subhelp, "INFO") == 0) {
2002
bip_notify(ic, "/BIP INFO USER <user> (admin only) :");
2003
bip_notify(ic, " Show <user>'s current configuration.");
2004
bip_notify(ic, " That means it may be different from the "
2005
"configuration stored in bip.conf");
2006
} else if (admin && strcasecmp(subhelp, "ADD_CONN") == 0) {
2007
bip_notify(ic, "/BIP ADD_CONN <connection name> <network> "
2009
bip_notify(ic, " Add a connection named <connection name> to "
2010
"the network <network> to your connection list");
2011
bip_notify(ic, " <network> should already exist in bip's "
2013
} else if (admin && strcasecmp(subhelp, "DEL_CONN") == 0) {
2014
bip_notify(ic, "/BIP DEL_CONN <connection name> (admin only) "
2016
bip_notify(ic, " Remove the connection named <connection "
2017
"name> from your connection list.");
2018
bip_notify(ic, " Removing a connection will cause "
2019
"its disconnection.");
2020
} else if (strcasecmp(subhelp, "JUMP") == 0) {
2021
bip_notify(ic, "/BIP JUMP :");
2022
bip_notify(ic, " Jump to next server in current network.");
2023
} else if (strcasecmp(subhelp, "BLRESET") == 0) {
2024
bip_notify(ic, "/BIP BLRESET :");
2025
bip_notify(ic, " Reset backlog on this network.");
2026
} else if (strcasecmp(subhelp, "FOLLOW_NICK") == 0) {
2027
bip_notify(ic, "/BIP FOLLOW_NICK TRUE|FALSE :");
2028
bip_notify(ic, " Change the value of the follow_nick option "
2029
"for this connection.");
2030
bip_notify(ic, " If set to true, when you change nick, "
2031
"BIP stores the new nickname as the new default "
2033
bip_notify(ic, " Thus, if you are disconnected from the "
2034
"server, BIP will restore the correct nickname.");
2035
} else if (strcasecmp(subhelp, "IGNORE_FIRST_NICK") == 0) {
2036
bip_notify(ic, "/BIP IGNORE_FIRST_NICK TRUE|FALSE :");
2037
bip_notify(ic, " Change the value of the ignore_first_nick "
2038
"option for this connection.");
2039
bip_notify(ic, " If set to TRUE, BIP will ignore the nickname"
2040
"sent by the client upon connect.");
2041
bip_notify(ic, " Further nickname changes will be processed "
2043
} else if (strcasecmp(subhelp, "ON_CONNECT_SEND") == 0) {
2044
bip_notify(ic, "/BIP ON_CONNECT_SEND [some text] :");
2045
bip_notify(ic, " BIP will send the text as is to the server "
2046
"upon connection.");
2047
bip_notify(ic, " You can call this command more than once.");
2048
bip_notify(ic, " If [some text] is empty, this command will "
2049
"remove any on_connect_send defined for this connection.");
2050
} else if (strcasecmp(subhelp, "AWAY_NICK") == 0) {
2051
bip_notify(ic, "/BIP AWAY_NICK [some_nick] :");
2052
bip_notify(ic, " If [some_nick] is set, BIP will change "
2053
"nickname to [some_nick] if there are no more client "
2055
bip_notify(ic, " If [some_nick] is empty, this command will "
2056
"unset current connection's away_nick.");
2057
} else if (strcasecmp(subhelp, "LIST") == 0) {
2058
bip_notify(ic, "/BIP LIST <section> :");
2059
bip_notify(ic, " List information from a these sections :");
2060
bip_notify(ic, " - networks: list all available networks");
2061
bip_notify(ic, " - connections: list all your configured "
2062
"connections and their state.");
2064
bip_notify(ic, " - users: list all users (admin)");
2065
bip_notify(ic, " - all_links: list all connected "
2066
"sockets from and to BIP (admin)");
2067
bip_notify(ic, " - all_connections: list all users' "
2068
"configured connections (admin)");
2071
bip_notify(ic, "-- No sub-help for '%s'", subhelp);
2075
int adm_bip(bip_t *bip, struct link_client *ic, struct line *line, int privmsg)
2077
int admin = LINK(ic)->user->admin;
2080
char *linestr, *elemstr;
2084
if (irc_line_count(line) != 3)
2087
linestr = irc_line_pop(line);
2090
/* all elem size <= linestr size */
2091
elemstr = bip_malloc(strlen(linestr) + 1);
2093
while((eptr = strstr(ptr, " "))) {
2099
memcpy(elemstr, ptr, slen);
2101
irc_line_append(line, elemstr);
2104
eptr = ptr + strlen(ptr);
2107
memcpy(elemstr, ptr, slen);
2109
irc_line_append(line, elemstr);
2115
if (!irc_line_includes(line, privmsg + 1))
2118
mylog(LOG_INFO, "/BIP %s from %s", irc_line_elem(line, privmsg + 1),
2119
LINK(ic)->user->name);
2120
if (strcasecmp(irc_line_elem(line, privmsg + 1), "RELOAD") == 0) {
2122
bip_notify(ic, "-- You're not allowed to reload bip");
2125
bip_notify(ic, "-- Reloading bip...");
2126
bip->reloading_client = ic;
2128
} else if (strcasecmp(irc_line_elem(line, privmsg + 1), "LIST") == 0) {
2129
if (irc_line_count(line) != privmsg + 3) {
2130
bip_notify(ic, "-- LIST command needs one argument");
2134
if (admin && strcasecmp(irc_line_elem(line, privmsg + 2),
2137
} else if (strcasecmp(irc_line_elem(line, privmsg + 2),
2139
adm_list_networks(ic);
2140
} else if (strcasecmp(irc_line_elem(line, privmsg + 2),
2141
"connections") == 0) {
2142
adm_list_connections(ic, NULL);
2143
} else if (admin && strcasecmp(irc_line_elem(line, privmsg + 2),
2144
"all_connections") == 0) {
2145
adm_list_all_connections(ic);
2146
} else if (admin && strcasecmp(irc_line_elem(line, privmsg + 2),
2147
"all_links") == 0) {
2148
adm_list_all_links(ic);
2150
bip_notify(ic, "-- Invalid LIST request");
2152
} else if (strcasecmp(irc_line_elem(line, privmsg + 1), "INFO") == 0) {
2153
if (!irc_line_includes(line, privmsg + 2)) {
2154
bip_notify(ic, "-- INFO command needs at least one "
2159
if (admin && irc_line_elem_case_equals(line, privmsg + 2,
2161
if (irc_line_count(line) == privmsg + 4) {
2163
irc_line_elem(line, privmsg + 3));
2165
bip_notify(ic, "-- INFO USER command needs one"
2172
bip_notify(ic, "-- Invalid INFO request");
2174
} else if (irc_line_elem_case_equals(line, privmsg + 1, "JUMP")) {
2175
if (LINK(ic)->l_server) {
2176
WRITE_LINE1(CONN(LINK(ic)->l_server), NULL, "QUIT",
2178
connection_close(CONN(LINK(ic)->l_server));
2180
bip_notify(ic, "-- Jumping to next server");
2181
} else if (irc_line_elem_case_equals(line, privmsg + 1, "BLRESET")) {
2182
if (irc_line_includes(line, privmsg + 2)) {
2183
if (irc_line_elem_equals(line, privmsg + 2, "-q")) {
2184
if (irc_line_includes(line, privmsg + 3)) {
2185
log_reset_store(LINK(ic)->log,
2189
log_reset_all(LINK(ic)->log);
2192
adm_blreset_store(ic, irc_line_elem(line,
2198
} else if (irc_line_elem_case_equals(line, privmsg + 1, "HELP")) {
2199
if (irc_line_count(line) == privmsg + 2)
2200
adm_bip_help(ic, admin, NULL);
2201
else if (irc_line_count(line) == privmsg + 3)
2202
adm_bip_help(ic, admin,
2203
irc_line_elem(line, privmsg + 2));
2206
"-- HELP command needs at most one argument");
2207
} else if (irc_line_elem_case_equals(line, privmsg + 1, "FOLLOW_NICK")) {
2208
if (irc_line_count(line) != privmsg + 3) {
2210
"-- FOLLOW_NICK command needs one argument");
2213
adm_follow_nick(ic, irc_line_elem(line, privmsg + 2));
2214
} else if (irc_line_elem_case_equals(line, privmsg + 1,
2215
"IGNORE_FIRST_NICK")) {
2216
if (irc_line_count(line) != privmsg + 3) {
2217
bip_notify(ic, "-- IGNORE_FIRST_NICK "
2218
"command needs one argument");
2221
adm_ignore_first_nick(ic, irc_line_elem(line, privmsg + 2));
2222
} else if (irc_line_elem_case_equals(line, privmsg + 1,
2223
"ON_CONNECT_SEND")) {
2224
if (irc_line_count(line) == privmsg + 2) {
2225
adm_on_connect_send(ic, NULL, 0);
2226
} else if (irc_line_includes(line, privmsg + 2)) {
2227
adm_on_connect_send(ic, line, privmsg);
2229
bip_notify(ic, "-- ON_CONNECT_SEND command needs at "
2230
"least one argument");
2232
} else if (irc_line_elem_case_equals(line, privmsg + 1, "AWAY_NICK")) {
2233
if (irc_line_count(line) == privmsg + 2) {
2234
adm_away_nick(ic, NULL);
2235
} else if (irc_line_count(line) == privmsg + 3) {
2236
adm_away_nick(ic, irc_line_elem(line, privmsg + 2));
2238
bip_notify(ic, "-- AWAY_NICK command needs zero or one"
2241
} else if (irc_line_elem_case_equals(line, privmsg + 1, "BACKLOG")) {
2242
if (irc_line_count(line) == privmsg + 2) {
2243
irc_cli_backlog(ic, 0);
2244
} else if (irc_line_count(line) == privmsg + 3) {
2245
int hours = atoi(irc_line_elem(line, privmsg + 2));
2246
irc_cli_backlog(ic, hours);
2248
bip_notify(ic, "-- BACKLOG takes 0 or one argument");
2250
} else if (admin && irc_line_elem_case_equals(line, privmsg + 1,
2252
if (irc_line_count(line) != privmsg + 4) {
2253
bip_notify(ic, "/BIP ADD_CONN <connection name> "
2256
adm_bip_addconn(bip, ic,
2257
irc_line_elem(line, privmsg + 2),
2258
irc_line_elem(line, privmsg + 3));
2260
} else if (admin && irc_line_elem_case_equals(line, privmsg + 1,
2262
if (irc_line_count(line) != privmsg + 3) {
2263
bip_notify(ic, "/BIP DEL_CONN <connection name>");
2265
adm_bip_delconn(bip, ic,
2266
irc_line_elem(line, privmsg + 2));
2269
bip_notify(ic, "Unknown command.");
2274
void free_conf(list_t *l)
2279
for (list_it_init(l, &li); (t = list_it_item(&li)); list_it_next(&li)) {
2280
switch (t->tuple_type) {
2287
free_conf(t->pdata);
2290
fatal("internal error free_conf");