~ubuntu-branches/ubuntu/trusty/bip/trusty-proposed

« back to all changes in this revision

Viewing changes to .pc/CVE-2012-0806.patch/src/bip.c

  • Committer: Package Import Robot
  • Author(s): Pierre-Louis Bonicoli
  • Date: 2012-01-23 21:14:41 UTC
  • Revision ID: package-import@ubuntu.com-20120123211441-pv0czw8ufkuhjm1p
Tags: 0.8.8-2
Fix CVE-2012-0806: buffer overflow.
Thanks to Julien Tinnes for reporting it. 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Id: bip.c,v 1.39 2005/04/21 06:58:50 nohar Exp $
 
3
 *
 
4
 * This file is part of the bip project
 
5
 * Copyright (C) 2004 2005 Arnaud Cornet and Loïc Gomez
 
6
 *
 
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.
 
12
 */
 
13
 
 
14
#include "config.h"
 
15
#include <stdlib.h>
 
16
#include <stdio.h>
 
17
#include <unistd.h>
 
18
#include <signal.h>
 
19
#include <stdarg.h>
 
20
#include <string.h>
 
21
#include <sys/time.h>
 
22
#include <sys/resource.h>
 
23
#include <sys/types.h>
 
24
#include <sys/stat.h>
 
25
#include <fcntl.h>
 
26
#include "irc.h"
 
27
#include "conf.h"
 
28
#include "tuple.h"
 
29
#include "log.h"
 
30
#include "bip.h"
 
31
#include "line.h"
 
32
#include "version.h"
 
33
#include "defaults.h"
 
34
 
 
35
int sighup = 0;
 
36
 
 
37
char *conf_log_root;
 
38
char *conf_log_format;
 
39
int conf_log_level;
 
40
char *conf_ip;
 
41
unsigned short conf_port;
 
42
int conf_css;
 
43
#ifdef HAVE_LIBSSL
 
44
char *conf_ssl_certfile;
 
45
#endif
 
46
int conf_daemonize;
 
47
char *conf_pid_file;
 
48
char *conf_biphome;
 
49
 
 
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;
 
54
 
 
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 bipuser *bu);
 
60
void free_conf(list_t *l);
 
61
 
 
62
#ifdef HAVE_OIDENTD
 
63
#define OIDENTD_FILENAME ".oidentd.conf"
 
64
#endif
 
65
 
 
66
static void hash_binary(char *hex, unsigned char **password, unsigned int *seed)
 
67
{
 
68
        unsigned char *md5;
 
69
        unsigned int buf;
 
70
        int i;
 
71
 
 
72
        if (strlen(hex) != 40)
 
73
                fatal("Incorrect password format %s\n", hex);
 
74
 
 
75
        md5 = bip_malloc(20);
 
76
        for (i = 0; i < 20; i++) {
 
77
                sscanf(hex + 2 * i, "%02x", &buf);
 
78
                md5[i] = buf;
 
79
        }
 
80
 
 
81
        *seed = 0;
 
82
        sscanf(hex, "%02x", &buf);
 
83
        *seed |= buf << 24;
 
84
        sscanf(hex + 2, "%02x", &buf);
 
85
        *seed |= buf << 16;
 
86
        sscanf(hex + 2 * 2, "%02x", &buf);
 
87
        *seed |= buf << 8;
 
88
        sscanf(hex + 2 * 3, "%02x", &buf);
 
89
        *seed |= buf;
 
90
 
 
91
        *password = md5;
 
92
}
 
93
 
 
94
static int add_server(bip_t *bip, struct server *s, list_t *data)
 
95
{
 
96
        struct tuple *t;
 
97
 
 
98
        s->port = 6667; /* default port */
 
99
 
 
100
        while ((t = list_remove_first(data))) {
 
101
                switch (t->type) {
 
102
                case LEX_HOST:
 
103
                        MOVE_STRING(s->host, t->pdata);
 
104
                        break;
 
105
                case LEX_PORT:
 
106
                        s->port = t->ndata;
 
107
                        break;
 
108
                default:
 
109
                        fatal("Config error in server block (%d)", t->type);
 
110
                }
 
111
                if (t->tuple_type == TUPLE_STR && t->pdata)
 
112
                        free(t->pdata);
 
113
                free(t);
 
114
        }
 
115
        if (!s->host) {
 
116
                free(s);
 
117
                conf_die(bip, "Server conf: host not set");
 
118
                return 0;
 
119
        }
 
120
        return 1;
 
121
}
 
122
 
 
123
#define ERRBUFSZ 128
 
124
 
 
125
extern list_t *root_list;
 
126
int yyparse();
 
127
 
 
128
void conf_die(bip_t *bip, char *fmt, ...)
 
129
{
 
130
        va_list ap;
 
131
        int size = ERRBUFSZ;
 
132
        int n;
 
133
        char *error = bip_malloc(size);
 
134
 
 
135
        for (;;) {
 
136
                va_start(ap, fmt);
 
137
                n = vsnprintf(error, size, fmt, ap);
 
138
                va_end(ap);
 
139
                if (n > -1 && n < size) {
 
140
                        list_add_last(&bip->errors, error);
 
141
                        break;
 
142
                }
 
143
                if (n > -1)
 
144
                        size = n + 1;
 
145
                else
 
146
                        size *= 2;
 
147
                error = bip_realloc(error, size);
 
148
        }
 
149
        va_start(ap, fmt);
 
150
        _mylog(LOG_ERROR, fmt, ap);
 
151
        va_end(ap);
 
152
}
 
153
 
 
154
FILE *conf_global_log_file;
 
155
 
 
156
static pid_t daemonize(void)
 
157
{
 
158
        switch (fork()) {
 
159
        case -1:
 
160
                fatal("Fork failed");
 
161
                break;
 
162
        case 0:
 
163
                break;
 
164
        default:
 
165
                _exit(0);
 
166
        }
 
167
 
 
168
        if (setsid() < 0)
 
169
                fatal("setsid() failed");
 
170
 
 
171
        switch (fork()) {
 
172
        case -1:
 
173
                fatal("Fork failed");
 
174
                break;
 
175
        case 0:
 
176
                break;
 
177
        default:
 
178
                _exit(0);
 
179
        }
 
180
 
 
181
        close(0);
 
182
        close(1);
 
183
        close(2);
 
184
        /* This better be the very last action since fatal makes use of
 
185
         * conf_global_log_file */
 
186
        return getpid();
 
187
}
 
188
 
 
189
/* RACE CONDITION! */
 
190
int do_pid_stuff(void)
 
191
{
 
192
        char hname[1024];
 
193
        char longpath[1024];
 
194
        FILE *f;
 
195
        int fd;
 
196
 
 
197
try_again:
 
198
        fd = -1;
 
199
        f = fopen(conf_pid_file, "r");
 
200
        if (f)
 
201
                goto pid_is_there;
 
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,
 
208
                                strerror(errno));
 
209
        if (link(longpath, conf_pid_file) ==  -1) {
 
210
                struct stat buf;
 
211
                if (stat(longpath, &buf) == -1) {
 
212
                        if (buf.st_nlink != 2) {
 
213
                                f = fopen(conf_pid_file, "r");
 
214
                                goto pid_is_there;
 
215
                        }
 
216
                }
 
217
        }
 
218
        unlink(longpath);
 
219
        return fd;
 
220
pid_is_there:
 
221
        {
 
222
                pid_t pid;
 
223
                long unsigned int p;
 
224
                if (fd != -1)
 
225
                        close(fd);
 
226
                if (f) {
 
227
                        int c = fscanf(f, "%ld", &p);
 
228
                        fclose(f);
 
229
                        pid = 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",
 
236
                                                        conf_pid_file);
 
237
                                }
 
238
                                goto try_again;
 
239
                        }
 
240
                } else
 
241
                        pid = 0;
 
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 "
 
247
                                                "permissions.\n",
 
248
                                                conf_pid_file);
 
249
                        }
 
250
                        goto try_again;
 
251
                }
 
252
                if (pid)
 
253
                        mylog(LOG_INFO, "pid file found (pid %ld).", pid);
 
254
                mylog(LOG_FATAL,
 
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);
 
258
                exit(2);
 
259
        }
 
260
        return 0;
 
261
}
 
262
 
 
263
#define S_CONF "bip.conf"
 
264
 
 
265
static void usage(char *name)
 
266
{
 
267
        printf(
 
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);
 
274
        exit(1);
 
275
}
 
276
 
 
277
static void version()
 
278
{
 
279
        printf(
 
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);
 
283
}
 
284
 
 
285
bip_t *_bip;
 
286
 
 
287
void reload_config(int i)
 
288
{
 
289
        (void)i;
 
290
        sighup = 1;
 
291
        _bip->reloading_client = NULL;
 
292
}
 
293
 
 
294
void rlimit_cpu_reached(int i)
 
295
{
 
296
        (void)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.");
 
299
}
 
300
 
 
301
void rlimit_bigfile_reached(int i)
 
302
{
 
303
        (void)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.");
 
307
}
 
308
 
 
309
void bad_quit(int i)
 
310
{
 
311
        list_iterator_t it;
 
312
        for (list_it_init(&_bip->link_list, &it); list_it_item(&it);
 
313
                        list_it_next(&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 "
 
318
                                        "caught me\r\n");
 
319
                }
 
320
        }
 
321
        unlink(conf_pid_file);
 
322
        exit(i);
 
323
}
 
324
 
 
325
static int add_network(bip_t *bip, list_t *data)
 
326
{
 
327
        struct tuple *t;
 
328
        struct network *n;
 
329
        int i;
 
330
        int r;
 
331
 
 
332
        char *name = get_tuple_pvalue(data, LEX_NAME);
 
333
 
 
334
        if (name == NULL) {
 
335
                conf_die(bip, "Network with no name");
 
336
                return 0;
 
337
        }
 
338
        n = hash_get(&bip->networks, name);
 
339
        if (n) {
 
340
                for (i = 0; i < n->serverc; i++)
 
341
                        free(n->serverv[i].host);
 
342
                free(n->serverv);
 
343
                n->serverv = NULL;
 
344
                n->serverc = 0;
 
345
        } else {
 
346
                n = bip_calloc(sizeof(struct network), 1);
 
347
                hash_insert(&bip->networks, name, n);
 
348
        }
 
349
 
 
350
        while ((t = list_remove_first(data))) {
 
351
                switch (t->type) {
 
352
                case LEX_NAME:
 
353
                        MOVE_STRING(n->name, t->pdata);
 
354
                        break;
 
355
#ifdef HAVE_LIBSSL
 
356
                case LEX_SSL:
 
357
                        n->ssl = t->ndata;
 
358
                        break;
 
359
#endif
 
360
                case LEX_SERVER:
 
361
                        n->serverv = bip_realloc(n->serverv, (n->serverc + 1)
 
362
                                                * sizeof(struct server));
 
363
                        n->serverc++;
 
364
                        memset(&n->serverv[n->serverc - 1], 0,
 
365
                                        sizeof(struct server));
 
366
                        r = add_server(bip, &n->serverv[n->serverc - 1],
 
367
                                        t->pdata);
 
368
                        if (!r) {
 
369
                                n->serverc--;
 
370
                                return 0;
 
371
                        }
 
372
                        free(t->pdata);
 
373
                        t->pdata = NULL;
 
374
                        break;
 
375
                default:
 
376
                        conf_die(bip, "unknown keyword in network statement");
 
377
                        return 0;
 
378
                        break;
 
379
                }
 
380
                if (t->tuple_type == TUPLE_STR && t->pdata)
 
381
                        free(t->pdata);
 
382
                free(t);
 
383
        }
 
384
        return 1;
 
385
}
 
386
 
 
387
void adm_bip_delconn(bip_t *bip, struct link_client *ic, const char *conn_name)
 
388
{
 
389
        struct bipuser *user = LINK(ic)->user;
 
390
        struct link *l;
 
391
 
 
392
        if (!(l = hash_get(&user->connections, conn_name))) {
 
393
                bip_notify(ic, "cannot find this connection");
 
394
                return;
 
395
        }
 
396
 
 
397
        bip_notify(ic, "deleting");
 
398
        link_kill(bip, l);
 
399
}
 
400
 
 
401
void adm_bip_addconn(bip_t *bip, struct link_client *ic, const char *conn_name,
 
402
                const char *network_name)
 
403
{
 
404
        struct bipuser *user = LINK(ic)->user;
 
405
        struct network *network;
 
406
 
 
407
        /* check name uniqueness */
 
408
        if (hash_get(&user->connections, conn_name)) {
 
409
                bip_notify(ic, "connection name already exists for this user.");
 
410
                return;
 
411
        }
 
412
 
 
413
        /* check we know about this network */
 
414
        network = hash_get(&bip->networks, network_name);
 
415
        if (!network) {
 
416
                bip_notify(ic, "no such network name");
 
417
                return;
 
418
        }
 
419
 
 
420
        struct link *l;
 
421
        l = irc_link_new();
 
422
        l->name = bip_strdup(conn_name);
 
423
        hash_insert(&user->connections, conn_name, l);
 
424
        list_add_last(&bip->link_list, l);
 
425
        l->user = user;
 
426
        l->network = network;
 
427
        l->log = log_new(user, conn_name);
 
428
#ifdef HAVE_LIBSSL
 
429
        l->ssl_check_mode = user->ssl_check_mode;
 
430
        l->untrusted_certs = sk_X509_new_null();
 
431
#endif
 
432
 
 
433
 
 
434
#define SCOPY(member) l->member = (LINK(ic)->member ? bip_strdup(LINK(ic)->member) : NULL)
 
435
#define ICOPY(member) l->member = LINK(ic)->member
 
436
 
 
437
        SCOPY(connect_nick);
 
438
        SCOPY(username);
 
439
        SCOPY(realname);
 
440
        /* we don't copy server password */
 
441
        SCOPY(vhost);
 
442
        ICOPY(follow_nick);
 
443
        ICOPY(ignore_first_nick);
 
444
        SCOPY(away_nick);
 
445
        SCOPY(no_client_away_msg);
 
446
        /* we don't copy on_connect_send */
 
447
#ifdef HAVE_LIBSSL
 
448
        ICOPY(ssl_check_mode);
 
449
#endif
 
450
#undef SCOPY
 
451
#undef ICOPY
 
452
        bip_notify(ic, "connection added, you should soon be able to connect");
 
453
}
 
454
 
 
455
static int add_connection(bip_t *bip, struct bipuser *user, list_t *data)
 
456
{
 
457
        struct tuple *t, *t2;
 
458
        struct link *l;
 
459
        struct chan_info *ci;
 
460
        char *name = get_tuple_pvalue(data, LEX_NAME);
 
461
 
 
462
        if (name == NULL) {
 
463
                conf_die(bip, "Connection with no name");
 
464
                return 0;
 
465
        }
 
466
        l = hash_get(&user->connections, name);
 
467
        if (!l) {
 
468
                l = irc_link_new();
 
469
                hash_insert(&user->connections, name, l);
 
470
                list_add_last(&bip->link_list, l);
 
471
                l->user = user;
 
472
                l->log = log_new(user, name);
 
473
#ifdef HAVE_LIBSSL
 
474
                l->ssl_check_mode = user->ssl_check_mode;
 
475
                l->untrusted_certs = sk_X509_new_null();
 
476
#endif
 
477
        } else {
 
478
                l->network = NULL;
 
479
                log_reset_all(l->log);
 
480
        }
 
481
 
 
482
        while ((t = list_remove_first(data))) {
 
483
                switch (t->type) {
 
484
                case LEX_NAME:
 
485
                        MOVE_STRING(l->name, t->pdata);
 
486
                        break;
 
487
                case LEX_NETWORK:
 
488
                        l->network = hash_get(&bip->networks, t->pdata);
 
489
                        if (!l->network) {
 
490
                                conf_die(bip, "Undefined network %s.\n",
 
491
                                                t->pdata);
 
492
                                return 0;
 
493
                        }
 
494
                        break;
 
495
                case LEX_NICK:
 
496
                        if (!is_valid_nick(t->pdata)) {
 
497
                                conf_die(bip, "Invalid nickname %s.", t->pdata);
 
498
                                return 0;
 
499
                        }
 
500
                        MOVE_STRING(l->connect_nick, t->pdata);
 
501
                        break;
 
502
                case LEX_USER:
 
503
                        MOVE_STRING(l->username, t->pdata);
 
504
                        break;
 
505
                case LEX_REALNAME:
 
506
                        MOVE_STRING(l->realname, t->pdata);
 
507
                        break;
 
508
                case LEX_PASSWORD:
 
509
                        MOVE_STRING(l->s_password, t->pdata);
 
510
                        break;
 
511
                case LEX_VHOST:
 
512
                        MOVE_STRING(l->vhost, t->pdata);
 
513
                        break;
 
514
                case LEX_CHANNEL:
 
515
                        name = get_tuple_pvalue(t->pdata, LEX_NAME);
 
516
                        if (name == NULL) {
 
517
                                conf_die(bip, "Channel with no name");
 
518
                                return 0;
 
519
                        }
 
520
 
 
521
                        ci = hash_get(&l->chan_infos, name);
 
522
                        if (!ci) {
 
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);
 
527
                                ci->backlog = 1;
 
528
                        }
 
529
 
 
530
                        while ((t2 = list_remove_first(t->pdata))) {
 
531
                                switch (t2->type) {
 
532
                                case LEX_NAME:
 
533
                                        MOVE_STRING(ci->name, t2->pdata);
 
534
                                        break;
 
535
                                case LEX_KEY:
 
536
                                        MOVE_STRING(ci->key, t2->pdata);
 
537
                                        break;
 
538
                                case LEX_BACKLOG:
 
539
                                        ci->backlog = t2->ndata;
 
540
                                        break;
 
541
                                }
 
542
                                if (t2->tuple_type == TUPLE_STR && t2->pdata)
 
543
                                        free(t2->pdata);
 
544
                                free(t2);
 
545
                        }
 
546
                        list_free(t->pdata);
 
547
                        break;
 
548
                case LEX_AUTOJOIN_ON_KICK:
 
549
                        l->autojoin_on_kick = t->ndata;
 
550
                        break;
 
551
                case LEX_FOLLOW_NICK:
 
552
                        l->follow_nick = t->ndata;
 
553
                        break;
 
554
                case LEX_IGN_FIRST_NICK:
 
555
                        l->ignore_first_nick = t->ndata;
 
556
                        break;
 
557
                case LEX_IGNORE_CAPAB:
 
558
                        l->ignore_server_capab = t->ndata;
 
559
                        break;
 
560
                case LEX_AWAY_NICK:
 
561
                        MOVE_STRING(l->away_nick, t->pdata);
 
562
                        break;
 
563
                case LEX_NO_CLIENT_AWAY_MSG:
 
564
                        MOVE_STRING(l->no_client_away_msg, t->pdata);
 
565
                        break;
 
566
                case LEX_ON_CONNECT_SEND:
 
567
                        list_add_last(&l->on_connect_send, t->pdata);
 
568
                        t->pdata = NULL;
 
569
                        break;
 
570
                case LEX_LOG:
 
571
                        l->log->log_to_file = t->ndata;
 
572
                        break;
 
573
#ifdef HAVE_LIBSSL
 
574
                case LEX_SSL_CHECK_MODE:
 
575
                        if (strcmp(t->pdata, "basic") == 0)
 
576
                                l->ssl_check_mode = SSL_CHECK_BASIC;
 
577
                        if (strcmp(t->pdata, "ca") == 0)
 
578
                                l->ssl_check_mode = SSL_CHECK_CA;
 
579
                        if (strcmp(t->pdata, "none") == 0)
 
580
                                l->ssl_check_mode = SSL_CHECK_NONE;
 
581
                        break;
 
582
#else
 
583
                case LEX_SSL_CHECK_MODE:
 
584
                        mylog(LOG_WARN, "Found SSL option whereas bip is "
 
585
                                        "not built with SSL support.");
 
586
                        break;
 
587
#endif
 
588
                default:
 
589
                        conf_die(bip, "Unknown keyword in connection "
 
590
                                        "statement");
 
591
                        return 0;
 
592
                }
 
593
                if (t->tuple_type == TUPLE_STR && t->pdata)
 
594
                        free(t->pdata);
 
595
                free(t);
 
596
        }
 
597
        /* checks that can only be here, or must */
 
598
        if (!l->network) {
 
599
                conf_die(bip, "Missing network in connection block");
 
600
                return 0;
 
601
        }
 
602
        if (!l->connect_nick) {
 
603
                if (!user->default_nick) {
 
604
                        conf_die(bip, "No nick set and no default nick.");
 
605
                        return 0;
 
606
                }
 
607
                l->connect_nick = bip_strdup(user->default_nick);
 
608
        }
 
609
        if (!l->username) {
 
610
                if (!user->default_username) {
 
611
                        conf_die(bip, "No username set and no default "
 
612
                                        "username.");
 
613
                        return 0;
 
614
                }
 
615
                l->username = bip_strdup(user->default_username);
 
616
        }
 
617
        if (!l->realname) {
 
618
                if (!user->default_realname) {
 
619
                        conf_die(bip, "No realname set and no default "
 
620
                                        "realname.");
 
621
                        return 0;
 
622
                }
 
623
                l->realname = bip_strdup(user->default_realname);
 
624
        }
 
625
 
 
626
        l->in_use = 1;
 
627
        return 1;
 
628
}
 
629
 
 
630
static char *get_tuple_pvalue(list_t *tuple_l, int lex)
 
631
{
 
632
        struct tuple *t;
 
633
        list_iterator_t it;
 
634
 
 
635
        for (list_it_init(tuple_l, &it); (t = list_it_item(&it));
 
636
                        list_it_next(&it)) {
 
637
                if (t->type == lex)
 
638
                        return t->pdata;
 
639
        }
 
640
        return NULL;
 
641
}
 
642
 
 
643
static int get_tuple_nvalue(list_t *tuple_l, int lex)
 
644
{
 
645
        struct tuple *t;
 
646
        list_iterator_t it;
 
647
 
 
648
        for (list_it_init(tuple_l, &it); (t = list_it_item(&it));
 
649
                        list_it_next(&it)) {
 
650
                if (t->type == lex)
 
651
                        return t->ndata;
 
652
        }
 
653
        return -1;
 
654
}
 
655
 
 
656
struct historical_directives {
 
657
        int always_backlog;
 
658
        int backlog;
 
659
        int bl_msg_only;
 
660
        int backlog_lines;
 
661
        int backlog_no_timestamp;
 
662
        int blreset_on_talk;
 
663
};
 
664
 
 
665
static int add_user(bip_t *bip, list_t *data, struct historical_directives *hds)
 
666
{
 
667
        int r;
 
668
        struct tuple *t;
 
669
        struct bipuser *u;
 
670
        char *name = get_tuple_pvalue(data, LEX_NAME);
 
671
        list_t connection_list, *cl;
 
672
 
 
673
        list_init(&connection_list, NULL);
 
674
 
 
675
        if (name == NULL) {
 
676
                conf_die(bip, "User with no name");
 
677
                return 0;
 
678
        }
 
679
        u = hash_get(&bip->users, name);
 
680
        if (!u) {
 
681
                u = bip_calloc(sizeof(struct bipuser), 1);
 
682
                hash_insert(&bip->users, name, u);
 
683
                hash_init(&u->connections, HASH_NOCASE);
 
684
                u->admin = 0;
 
685
                u->backlog = DEFAULT_BACKLOG;
 
686
                u->always_backlog = DEFAULT_ALWAYS_BACKLOG;
 
687
                u->bl_msg_only = DEFAULT_BL_MSG_ONLY;
 
688
                u->backlog_lines = DEFAULT_BACKLOG_LINES;
 
689
                u->backlog_no_timestamp = DEFAULT_BACKLOG_NO_TIMESTAMP;
 
690
                u->blreset_on_talk = DEFAULT_BLRESET_ON_TALK;
 
691
                u->blreset_connection = DEFAULT_BLRESET_CONNECTION;
 
692
                u->bip_use_notice = DEFAULT_BIP_USE_NOTICE;
 
693
        } else {
 
694
                FREE(u->name);
 
695
                FREE(u->password);
 
696
                FREE(u->default_nick);
 
697
                FREE(u->default_username);
 
698
                FREE(u->default_realname);
 
699
#ifdef HAVE_LIBSSL
 
700
                FREE(u->ssl_check_store);
 
701
                FREE(u->ssl_client_certfile);
 
702
#endif
 
703
        }
 
704
 
 
705
        u->backlog = hds->backlog;
 
706
        u->always_backlog = hds->always_backlog;
 
707
        u->bl_msg_only = hds->bl_msg_only;
 
708
        u->backlog_lines = hds->backlog_lines;
 
709
        u->backlog_no_timestamp = hds->backlog_no_timestamp;
 
710
        u->blreset_on_talk = hds->blreset_on_talk;
 
711
 
 
712
        while ((t = list_remove_first(data))) {
 
713
                switch (t->type) {
 
714
                case LEX_NAME:
 
715
                        MOVE_STRING(u->name, t->pdata);
 
716
                        break;
 
717
                case LEX_ADMIN:
 
718
                        u->admin = t->ndata;
 
719
                        break;
 
720
                case LEX_PASSWORD:
 
721
                        hash_binary(t->pdata, &u->password, &u->seed);
 
722
                        free(t->pdata);
 
723
                        t->pdata = NULL;
 
724
                        break;
 
725
                case LEX_DEFAULT_NICK:
 
726
                        MOVE_STRING(u->default_nick, t->pdata);
 
727
                        break;
 
728
                case LEX_DEFAULT_USER:
 
729
                        MOVE_STRING(u->default_username, t->pdata);
 
730
                        break;
 
731
                case LEX_DEFAULT_REALNAME:
 
732
                        MOVE_STRING(u->default_realname, t->pdata);
 
733
                        break;
 
734
                case LEX_ALWAYS_BACKLOG:
 
735
                        u->always_backlog = t->ndata;
 
736
                        break;
 
737
                case LEX_BACKLOG:
 
738
                        u->backlog = t->ndata;
 
739
                        break;
 
740
                case LEX_BL_MSG_ONLY:
 
741
                        u->bl_msg_only = t->ndata;
 
742
                        break;
 
743
                case LEX_BACKLOG_LINES:
 
744
                        u->backlog_lines = t->ndata;
 
745
                        break;
 
746
                case LEX_BACKLOG_NO_TIMESTAMP:
 
747
                        u->backlog_no_timestamp = t->ndata;
 
748
                        break;
 
749
                case LEX_BLRESET_ON_TALK:
 
750
                        u->blreset_on_talk = t->ndata;
 
751
                        break;
 
752
                case LEX_BLRESET_CONNECTION:
 
753
                        u->blreset_connection = t->ndata;
 
754
                        break;
 
755
                case LEX_BIP_USE_NOTICE:
 
756
                        u->bip_use_notice = t->ndata;
 
757
                        break;
 
758
                case LEX_CONNECTION:
 
759
                        list_add_last(&connection_list, t->pdata);
 
760
                        t->pdata = NULL;
 
761
                        break;
 
762
#ifdef HAVE_LIBSSL
 
763
                case LEX_SSL_CHECK_MODE:
 
764
                        if (!strcmp(t->pdata, "basic"))
 
765
                                u->ssl_check_mode = SSL_CHECK_BASIC;
 
766
                        if (!strcmp(t->pdata, "ca"))
 
767
                                u->ssl_check_mode = SSL_CHECK_CA;
 
768
                        if (!strcmp(t->pdata, "none"))
 
769
                                u->ssl_check_mode = SSL_CHECK_NONE;
 
770
                        free(t->pdata);
 
771
                        t->pdata = NULL;
 
772
                        break;
 
773
                case LEX_SSL_CHECK_STORE:
 
774
                        MOVE_STRING(u->ssl_check_store, t->pdata);
 
775
                        break;
 
776
                case LEX_SSL_CLIENT_CERTFILE:
 
777
                        MOVE_STRING(u->ssl_client_certfile, t->pdata);
 
778
                        break;
 
779
#else
 
780
                case LEX_SSL_CLIENT_CERTFILE:
 
781
                case LEX_SSL_CHECK_MODE:
 
782
                case LEX_SSL_CHECK_STORE:
 
783
                        mylog(LOG_WARN, "Found SSL option whereas bip is "
 
784
                                        "not built with SSL support.");
 
785
                        break;
 
786
#endif
 
787
                default:
 
788
                        conf_die(bip, "Uknown keyword in user statement");
 
789
                        return 0;
 
790
                }
 
791
                if (t->tuple_type == TUPLE_STR && t->pdata)
 
792
                        free(t->pdata);
 
793
                free(t);
 
794
        }
 
795
        if (!u->password) {
 
796
                conf_die(bip, "Missing password in user block");
 
797
                return 0;
 
798
        }
 
799
 
 
800
        while ((cl = list_remove_first(&connection_list))) {
 
801
                r = add_connection(bip, u, cl);
 
802
                free(cl);
 
803
                if (!r)
 
804
                        return 0;
 
805
        }
 
806
 
 
807
        u->in_use = 1;
 
808
        return 1;
 
809
}
 
810
 
 
811
static int validate_config(bip_t *bip)
 
812
{
 
813
        /* nick username realname or default_{nick,username,realname} in user */
 
814
        hash_iterator_t it, sit, cit;
 
815
        struct bipuser *user;
 
816
        struct link *link;
 
817
        struct chan_info *ci;
 
818
        int r = 1;
 
819
 
 
820
        for (hash_it_init(&bip->users, &it); (user = hash_it_item(&it));
 
821
                        hash_it_next(&it)) {
 
822
                for (hash_it_init(&user->connections, &sit);
 
823
                                (link = hash_it_item(&sit));
 
824
                                hash_it_next(&sit)) {
 
825
                        if (!user->default_nick || !user->default_username ||
 
826
                                        !user->default_realname) {
 
827
                                if ((!link->username &&
 
828
                                                !user->default_username) ||
 
829
                                                (!link->connect_nick &&
 
830
                                                 !user->default_nick) ||
 
831
                                                (!link->realname &&
 
832
                                                 !user->default_realname)) {
 
833
                                        conf_die(bip, "user %s, "
 
834
                                                "connection %s: you must defin"
 
835
                                                "e nick, user and realname.",
 
836
                                                user->name, link->name);
 
837
                                        link_kill(bip, link);
 
838
                                        r = 0;
 
839
                                        continue;
 
840
                                }
 
841
                        }
 
842
 
 
843
                        for (hash_it_init(&link->chan_infos, &cit);
 
844
                                        (ci = hash_it_item(&cit));
 
845
                                        hash_it_next(&cit)) {
 
846
                                if (!ci->name) {
 
847
                                        conf_die(bip, "user %s, "
 
848
                                                "connection "
 
849
                                                "%s: channel must have"
 
850
                                                "a name.", user->name,
 
851
                                                link->name);
 
852
                                        r = 0;
 
853
                                        continue;
 
854
                                }
 
855
                        }
 
856
                }
 
857
 
 
858
                if (user->backlog && !conf_log && user->backlog_lines == 0) {
 
859
                        conf_die(bip, "If conf_log = false, you must set "
 
860
                                "backlog_"
 
861
                                "lines to a non-nul value for each user with"
 
862
                                "backlog = true. Faulty user is %s",
 
863
                                user->name);
 
864
                        r = 0;
 
865
                        continue;
 
866
                }
 
867
        }
 
868
 
 
869
        hash_it_init(&bip->users, &it);
 
870
        hash_it_next(&it);
 
871
        if (hash_it_item(&it) && !strstr(conf_log_format, "%u"))
 
872
                mylog(LOG_WARN, "log_format does not contain %%u, all users'"
 
873
                        " logs will be mixed !");
 
874
        return r;
 
875
}
 
876
 
 
877
void clear_marks(bip_t *bip)
 
878
{
 
879
        list_iterator_t lit;
 
880
        hash_iterator_t hit;
 
881
 
 
882
        for (list_it_init(&bip->link_list, &lit); list_it_item(&lit);
 
883
                        list_it_next(&lit))
 
884
                ((struct link *)list_it_item(&lit))->in_use = 0;
 
885
        for (hash_it_init(&bip->users, &hit); hash_it_item(&hit);
 
886
                        hash_it_next(&hit))
 
887
                ((struct bipuser *)hash_it_item(&hit))->in_use = 0;
 
888
}
 
889
 
 
890
void user_kill(bip_t *bip, struct bipuser *user)
 
891
{
 
892
        (void)bip;
 
893
        if (!hash_is_empty(&user->connections))
 
894
                fatal("user_kill, user still has connections");
 
895
        free(user->name);
 
896
        free(user->password);
 
897
        MAYFREE(user->default_nick);
 
898
        MAYFREE(user->default_username);
 
899
        MAYFREE(user->default_realname);
 
900
 
 
901
#ifdef HAVE_LIBSSL
 
902
        MAYFREE(user->ssl_check_store);
 
903
        MAYFREE(user->ssl_client_certfile);
 
904
#endif
 
905
        free(user);
 
906
}
 
907
 
 
908
void sweep(bip_t *bip)
 
909
{
 
910
        list_iterator_t lit;
 
911
        hash_iterator_t hit;
 
912
 
 
913
        for (list_it_init(&bip->link_list, &lit); list_it_item(&lit);
 
914
                        list_it_next(&lit)) {
 
915
                struct link *l = ((struct link *)list_it_item(&lit));
 
916
                if (!l->in_use) {
 
917
                        mylog(LOG_INFO, "Administratively killing %s/%s",
 
918
                                        l->user->name, l->name);
 
919
                        list_remove_if_exists(&bip->conn_list, l);
 
920
                        link_kill(bip, l);
 
921
                        list_it_remove(&lit);
 
922
                }
 
923
        }
 
924
        for (hash_it_init(&bip->users, &hit); hash_it_item(&hit);
 
925
                        hash_it_next(&hit)) {
 
926
                struct bipuser *u = (struct bipuser *)hash_it_item(&hit);
 
927
                if (!u->in_use) {
 
928
                        hash_it_remove(&hit);
 
929
                        user_kill(bip, u);
 
930
                }
 
931
        }
 
932
}
 
933
 
 
934
int fireup(bip_t *bip, FILE *conf)
 
935
{
 
936
        int r;
 
937
        struct tuple *t;
 
938
        int err = 0;
 
939
        struct historical_directives hds;
 
940
        char *l;
 
941
 
 
942
        clear_marks(bip);
 
943
        while ((l = list_remove_first(&bip->errors)))
 
944
                free(l);
 
945
        parse_conf(conf, &err);
 
946
        if (err) {
 
947
                free_conf(root_list);
 
948
                root_list = NULL;
 
949
                return 0;
 
950
        }
 
951
 
 
952
#define SET_HV(d, n) do {\
 
953
        int __gtv = get_tuple_nvalue(root_list, LEX_##n);\
 
954
        if (__gtv != -1) \
 
955
                d = __gtv;\
 
956
        else\
 
957
                d = DEFAULT_##n;\
 
958
        } while(0);
 
959
        SET_HV(hds.always_backlog, ALWAYS_BACKLOG);
 
960
        SET_HV(hds.backlog, BACKLOG);
 
961
        SET_HV(hds.bl_msg_only, BL_MSG_ONLY);
 
962
        SET_HV(hds.backlog_lines, BACKLOG_LINES);
 
963
        SET_HV(hds.backlog_no_timestamp, BACKLOG_NO_TIMESTAMP);
 
964
        SET_HV(hds.blreset_on_talk, BLRESET_ON_TALK);
 
965
#undef SET_HV
 
966
 
 
967
        while ((t = list_remove_first(root_list))) {
 
968
                switch (t->type) {
 
969
                case LEX_LOG_SYNC_INTERVAL:
 
970
                        conf_log_sync_interval = t->ndata;
 
971
                        break;
 
972
                case LEX_LOG:
 
973
                        conf_log = t->ndata;
 
974
                        break;
 
975
                case LEX_LOG_SYSTEM:
 
976
                        conf_log_system = t->ndata;
 
977
                        break;
 
978
                case LEX_LOG_ROOT:
 
979
                        MOVE_STRING(conf_log_root, t->pdata);
 
980
                        break;
 
981
                case LEX_LOG_FORMAT:
 
982
                        MOVE_STRING(conf_log_format, t->pdata);
 
983
                        break;
 
984
                case LEX_LOG_LEVEL:
 
985
                        conf_log_level = t->ndata;
 
986
                        break;
 
987
                case LEX_IP:
 
988
                        MOVE_STRING(conf_ip, t->pdata);
 
989
                        break;
 
990
                case LEX_PORT:
 
991
                        conf_port = t->ndata;
 
992
                        break;
 
993
#ifdef HAVE_LIBSSL
 
994
                case LEX_CSS:
 
995
                        conf_css = t->ndata;
 
996
                        break;
 
997
                case LEX_CSS_PEM:
 
998
                        MOVE_STRING(conf_ssl_certfile, t->pdata);
 
999
                        break;
 
1000
#else
 
1001
                case LEX_CSS:
 
1002
                case LEX_CSS_PEM:
 
1003
                        mylog(LOG_WARN, "Found SSL option whereas bip is "
 
1004
                                        "not built with SSL support.");
 
1005
                        break;
 
1006
#endif
 
1007
                case LEX_PID_FILE:
 
1008
                        MOVE_STRING(conf_pid_file, t->pdata);
 
1009
                        break;
 
1010
                case LEX_ALWAYS_BACKLOG:
 
1011
                        hds.always_backlog = t->ndata;
 
1012
                        break;
 
1013
                case LEX_BACKLOG:
 
1014
                        hds.backlog = t->ndata;
 
1015
                        break;
 
1016
                case LEX_BL_MSG_ONLY:
 
1017
                        hds.bl_msg_only = t->ndata;
 
1018
                        break;
 
1019
                case LEX_BACKLOG_LINES:
 
1020
                        hds.backlog_lines = t->ndata;
 
1021
                        break;
 
1022
                case LEX_BACKLOG_NO_TIMESTAMP:
 
1023
                        hds.backlog_no_timestamp = t->ndata;
 
1024
                        break;
 
1025
                case LEX_BLRESET_ON_TALK:
 
1026
                        hds.blreset_on_talk = t->ndata;
 
1027
                        break;
 
1028
                case LEX_NETWORK:
 
1029
                        r = add_network(bip, t->pdata);
 
1030
                        list_free(t->pdata);
 
1031
                        if (!r)
 
1032
                                goto out_conf_error;
 
1033
                        break;
 
1034
                case LEX_USER:
 
1035
                        r = add_user(bip, t->pdata, &hds);
 
1036
                        list_free(t->pdata);
 
1037
                        if (!r)
 
1038
                                goto out_conf_error;
 
1039
                        break;
 
1040
                default:
 
1041
                        conf_die(bip, "Config error in base config (%d)",
 
1042
                                        t->type);
 
1043
                        goto out_conf_error;
 
1044
                }
 
1045
                if (t->tuple_type == TUPLE_STR && t->pdata)
 
1046
                        free(t->pdata);
 
1047
                free(t);
 
1048
        }
 
1049
        free(root_list);
 
1050
        root_list = NULL;
 
1051
 
 
1052
        if (validate_config(bip)) {
 
1053
                sweep(bip);
 
1054
                return 1;
 
1055
        } else {
 
1056
                return 0;
 
1057
        }
 
1058
out_conf_error:
 
1059
        free_conf(root_list);
 
1060
        root_list = NULL;
 
1061
        return 0;
 
1062
}
 
1063
 
 
1064
static void log_file_setup(void)
 
1065
{
 
1066
        char buf[4096];
 
1067
 
 
1068
        if (conf_log_system && conf_daemonize) {
 
1069
                if (conf_global_log_file && conf_global_log_file != stderr)
 
1070
                        fclose(conf_global_log_file);
 
1071
                snprintf(buf, 4095, "%s/bip.log", conf_log_root);
 
1072
                FILE *f = fopen(buf, "a");
 
1073
                if (!f)
 
1074
                        fatal("Can't open %s: %s", buf, strerror(errno));
 
1075
                conf_global_log_file = f;
 
1076
        } else {
 
1077
                conf_global_log_file = stderr;
 
1078
        }
 
1079
}
 
1080
 
 
1081
void check_rlimits()
 
1082
{
 
1083
        int r, cklim;
 
1084
        struct rlimit lt;
 
1085
 
 
1086
        cklim = 0;
 
1087
 
 
1088
#ifdef RLIMIT_AS
 
1089
        r = getrlimit(RLIMIT_AS, &lt);
 
1090
        if (r) {
 
1091
                mylog(LOG_ERROR, "getrlimit(): failed with %s",
 
1092
                                strerror(errno));
 
1093
        } else {
 
1094
                if (lt.rlim_max != RLIM_INFINITY) {
 
1095
                        mylog(LOG_WARN, "virtual memory rlimit active, "
 
1096
                                "bip may be KILLED by the system");
 
1097
                        cklim = 1;
 
1098
                }
 
1099
        }
 
1100
#endif
 
1101
 
 
1102
        r = getrlimit(RLIMIT_CPU, &lt);
 
1103
        if (r) {
 
1104
                mylog(LOG_ERROR, "getrlimit(): failed with %s",
 
1105
                                strerror(errno));
 
1106
        } else {
 
1107
                if (lt.rlim_max != RLIM_INFINITY) {
 
1108
                        mylog(LOG_WARN, "CPU rlimit active, bip may "
 
1109
                                "be OFTEN KILLED by the system");
 
1110
                        cklim = 1;
 
1111
                }
 
1112
        }
 
1113
 
 
1114
        r = getrlimit(RLIMIT_FSIZE, &lt);
 
1115
        if (r) {
 
1116
                mylog(LOG_ERROR, "getrlimit(): failed with %s",
 
1117
                                strerror(errno));
 
1118
        } else {
 
1119
                if (lt.rlim_max != RLIM_INFINITY) {
 
1120
                        mylog(LOG_WARN, "FSIZE rlimit active, bip will "
 
1121
                                "fail to create files of size greater than "
 
1122
                                "%d bytes.", (int)lt.rlim_max);
 
1123
                        cklim = 1;
 
1124
                }
 
1125
        }
 
1126
 
 
1127
        r = getrlimit(RLIMIT_NOFILE, &lt);
 
1128
        if (r) {
 
1129
                mylog(LOG_ERROR, "getrlimit(): failed with %s",
 
1130
                                strerror(errno));
 
1131
        } else {
 
1132
                if (lt.rlim_max != RLIM_INFINITY && lt.rlim_max < 256) {
 
1133
                        mylog(LOG_WARN, "opened files count rlimit "
 
1134
                                "active, bip will not be allowed to open more "
 
1135
                                "than %d files at a time", (int)lt.rlim_max);
 
1136
                        cklim = 1;
 
1137
                }
 
1138
        }
 
1139
 
 
1140
        r = getrlimit(RLIMIT_STACK, &lt);
 
1141
        if (r) {
 
1142
                mylog(LOG_ERROR, "getrlimit(): failed with %s",
 
1143
                                strerror(errno));
 
1144
        } else {
 
1145
                if (lt.rlim_max != RLIM_INFINITY) {
 
1146
                        mylog(LOG_WARN, "stack rlimit active, "
 
1147
                                "bip may be KILLED by the system");
 
1148
                        cklim = 1;
 
1149
                }
 
1150
        }
 
1151
 
 
1152
        if (cklim)
 
1153
                mylog(LOG_WARN, "You can check your limits with `ulimit -a'");
 
1154
}
 
1155
 
 
1156
int main(int argc, char **argv)
 
1157
{
 
1158
        FILE *conf = NULL;
 
1159
        char *confpath = NULL;
 
1160
        int ch;
 
1161
        int r, fd;
 
1162
        char buf[30];
 
1163
        bip_t bip;
 
1164
 
 
1165
        bip_init(&bip);
 
1166
        _bip = &bip;
 
1167
 
 
1168
        conf_ip = bip_strdup("0.0.0.0");
 
1169
        conf_port = 7778;
 
1170
        conf_css = 0;
 
1171
 
 
1172
        signal(SIGPIPE, SIG_IGN);
 
1173
        signal(SIGHUP, reload_config);
 
1174
        signal(SIGINT, bad_quit);
 
1175
        signal(SIGQUIT, bad_quit);
 
1176
        signal(SIGTERM, bad_quit);
 
1177
        signal(SIGXFSZ, rlimit_bigfile_reached);
 
1178
        signal(SIGXCPU, rlimit_cpu_reached);
 
1179
 
 
1180
        conf_log_root = NULL;
 
1181
        conf_log_format = bip_strdup(DEFAULT_LOG_FORMAT);
 
1182
        conf_log_level = DEFAULT_LOG_LEVEL;
 
1183
        conf_daemonize = 1;
 
1184
        conf_global_log_file = stderr;
 
1185
        conf_pid_file = NULL;
 
1186
#ifdef HAVE_LIBSSL
 
1187
        conf_ssl_certfile = NULL;
 
1188
#endif
 
1189
 
 
1190
        while ((ch = getopt(argc, argv, "hvnf:s:")) != -1) {
 
1191
                switch (ch) {
 
1192
                case 'f':
 
1193
                        confpath = bip_strdup(optarg);
 
1194
                        break;
 
1195
                case 'n':
 
1196
                        conf_daemonize = 0;
 
1197
                        break;
 
1198
                case 's':
 
1199
                        conf_biphome = bip_strdup(optarg);
 
1200
                        break;
 
1201
                case 'v':
 
1202
                        version();
 
1203
                        exit(0);
 
1204
                        break;
 
1205
                default:
 
1206
                        version();
 
1207
                        usage(argv[0]);
 
1208
                }
 
1209
        }
 
1210
 
 
1211
        umask(0027);
 
1212
 
 
1213
        check_rlimits();
 
1214
 
 
1215
        char *home = NULL; /* oidentd path searching ignores conf_biphome */
 
1216
        home = getenv("HOME");
 
1217
        if (!home) {
 
1218
                conf_die(&bip, "no $HOME !, do you live in a trailer ?");
 
1219
                return 0;
 
1220
        }
 
1221
#ifdef HAVE_OIDENTD
 
1222
        bip.oidentdpath = bip_malloc(strlen(home) + 1 +
 
1223
                        strlen(OIDENTD_FILENAME) + 1);
 
1224
        strcpy(bip.oidentdpath, home);
 
1225
        strcat(bip.oidentdpath, "/");
 
1226
        strcat(bip.oidentdpath, OIDENTD_FILENAME);
 
1227
#endif
 
1228
 
 
1229
 
 
1230
        if (!conf_biphome) {
 
1231
                conf_biphome = bip_malloc(strlen(home) + strlen("/.bip") + 1);
 
1232
                strcpy(conf_biphome, home);
 
1233
                strcat(conf_biphome, "/.bip");
 
1234
        }
 
1235
 
 
1236
        if (!confpath) {
 
1237
                confpath = bip_malloc(strlen(conf_biphome) + 1 +
 
1238
                                strlen(S_CONF) + 1);
 
1239
                strcpy(confpath, conf_biphome);
 
1240
                strcat(confpath, "/");
 
1241
                strcat(confpath, S_CONF);
 
1242
        }
 
1243
        conf = fopen(confpath, "r");
 
1244
        if (!conf)
 
1245
                fatal("config file not found");
 
1246
 
 
1247
        r = fireup(&bip, conf);
 
1248
        fclose(conf);
 
1249
        if (!r)
 
1250
                fatal("Not starting: error in config file.");
 
1251
 
 
1252
        if (!conf_log_root) {
 
1253
                char *ap = "/logs";
 
1254
                conf_log_root = bip_malloc(strlen(conf_biphome) +
 
1255
                                strlen(ap) + 1);
 
1256
                strcpy(conf_log_root, conf_biphome);
 
1257
                strcat(conf_log_root, ap);
 
1258
                mylog(LOG_INFO, "Default log root: %s", conf_log_root);
 
1259
        }
 
1260
        if (!conf_pid_file) {
 
1261
                char *pid = "/bip.pid";
 
1262
                conf_pid_file = bip_malloc(strlen(conf_biphome) +
 
1263
                                strlen(pid) + 1);
 
1264
                strcpy(conf_pid_file, conf_biphome);
 
1265
                strcat(conf_pid_file, pid);
 
1266
                mylog(LOG_INFO, "Default pid file: %s", conf_pid_file);
 
1267
        }
 
1268
 
 
1269
#ifdef HAVE_LIBSSL
 
1270
        if (conf_css) {
 
1271
                int e, fd;
 
1272
                struct stat fs;
 
1273
 
 
1274
                if (!conf_ssl_certfile) {
 
1275
                        char *ap = "/bip.pem";
 
1276
                        conf_ssl_certfile = bip_malloc(strlen(conf_biphome) +
 
1277
                                        strlen(ap) + 1);
 
1278
                        strcpy(conf_ssl_certfile, conf_biphome);
 
1279
                        strcat(conf_ssl_certfile, ap);
 
1280
                        mylog(LOG_INFO, "Using default SSL certificate file: "
 
1281
                                        "%s", conf_ssl_certfile);
 
1282
                }
 
1283
 
 
1284
                if ((fd = open(conf_ssl_certfile, O_RDONLY)) == -1)
 
1285
                        fatal("Unable to open PEM file %s for reading",
 
1286
                                conf_ssl_certfile);
 
1287
                else
 
1288
                        close(fd);
 
1289
 
 
1290
                e = stat(conf_ssl_certfile, &fs);
 
1291
                if (e)
 
1292
                        mylog(LOG_WARN, "Unable to check PEM file, stat(%s): "
 
1293
                                "%s", conf_ssl_certfile, strerror(errno));
 
1294
                else if ((fs.st_mode & S_IROTH) | (fs.st_mode & S_IWOTH))
 
1295
                        mylog(LOG_ERROR, "PEM file %s should not be world "
 
1296
                                "readable / writable. Please fix the modes.",
 
1297
                                conf_ssl_certfile);
 
1298
        }
 
1299
#endif
 
1300
 
 
1301
        check_dir(conf_log_root, 1);
 
1302
        fd = do_pid_stuff();
 
1303
        pid_t pid = 0;
 
1304
 
 
1305
        log_file_setup();
 
1306
        if (conf_daemonize)
 
1307
                pid = daemonize();
 
1308
        else
 
1309
                pid = getpid();
 
1310
        snprintf(buf, 29, "%ld\n", (long unsigned int)pid);
 
1311
        write(fd, buf, strlen(buf));
 
1312
        close(fd);
 
1313
 
 
1314
        bip.listener = listen_new(conf_ip, conf_port, conf_css);
 
1315
        if (!bip.listener)
 
1316
                fatal("Could not create listening socket");
 
1317
 
 
1318
        for (;;) {
 
1319
                irc_main(&bip);
 
1320
 
 
1321
                sighup = 0;
 
1322
 
 
1323
                conf = fopen(confpath, "r");
 
1324
                if (!conf)
 
1325
                        fatal("%s config file not found", confpath);
 
1326
                fireup(&bip, conf);
 
1327
                fclose(conf);
 
1328
 
 
1329
                /* re-open to allow logfile rotate */
 
1330
                log_file_setup();
 
1331
        }
 
1332
        return 1;
 
1333
}
 
1334
 
 
1335
#define RET_STR_LEN 256
 
1336
#define LINE_SIZE_LIM 70
 
1337
void adm_print_connection(struct link_client *ic, struct link *lnk,
 
1338
                struct bipuser *bu)
 
1339
{
 
1340
        hash_iterator_t lit;
 
1341
        char buf[RET_STR_LEN + 1];
 
1342
        int t_written = 0;
 
1343
 
 
1344
        if (!bu)
 
1345
                bu = lnk->user;
 
1346
 
 
1347
        bip_notify(ic, "* %s to %s as \"%s\" (%s!%s) :", lnk->name,
 
1348
                lnk->network->name,
 
1349
                (lnk->realname ? lnk->realname : bu->default_realname),
 
1350
                (lnk->connect_nick ? lnk->connect_nick : bu->default_nick),
 
1351
                (lnk->username ? lnk->username : bu->default_username));
 
1352
 
 
1353
        t_written = snprintf(buf, RET_STR_LEN, "  Options:");
 
1354
        if (t_written >= RET_STR_LEN)
 
1355
                goto noroom;
 
1356
        if (lnk->follow_nick) {
 
1357
                t_written += snprintf(buf + t_written,
 
1358
                        RET_STR_LEN - t_written, " follow_nick");
 
1359
                if (t_written >= RET_STR_LEN)
 
1360
                        goto noroom;
 
1361
        }
 
1362
        if (lnk->ignore_first_nick) {
 
1363
                t_written += snprintf(buf + t_written,
 
1364
                        RET_STR_LEN - t_written, " ignore_first_nick");
 
1365
                if (t_written >= RET_STR_LEN)
 
1366
                        goto noroom;
 
1367
        }
 
1368
        if (lnk->away_nick) {
 
1369
                t_written += snprintf(buf + t_written,
 
1370
                        RET_STR_LEN - t_written, " away_nick=%s",
 
1371
                        lnk->away_nick);
 
1372
                if (t_written >= RET_STR_LEN)
 
1373
                        goto noroom;
 
1374
        }
 
1375
        if (lnk->no_client_away_msg) {
 
1376
                t_written += snprintf(buf + t_written,
 
1377
                        RET_STR_LEN - t_written, " no_client_away_msg=%s",
 
1378
                        lnk->no_client_away_msg);
 
1379
                if (t_written >= RET_STR_LEN)
 
1380
                        goto noroom;
 
1381
        }
 
1382
        if (lnk->vhost) {
 
1383
                t_written += snprintf(buf + t_written,
 
1384
                        RET_STR_LEN - t_written, " vhost=%s",
 
1385
                        lnk->vhost);
 
1386
                if (t_written >= RET_STR_LEN)
 
1387
                        goto noroom;
 
1388
        }
 
1389
        if (lnk->bind_port) {
 
1390
                t_written += snprintf(buf + t_written,
 
1391
                        RET_STR_LEN - t_written, " bind_port=%u",
 
1392
                        lnk->bind_port);
 
1393
                if (t_written >= RET_STR_LEN)
 
1394
                        goto noroom;
 
1395
        }
 
1396
noroom: /* that means the line is larger that RET_STR_LEN. We're not likely to
 
1397
           even read such a long line */
 
1398
        buf[RET_STR_LEN] = 0;
 
1399
        bip_notify(ic, "%s", buf);
 
1400
 
 
1401
        // TODO: on_connect_send
 
1402
 
 
1403
        // TODO : check channels struct
 
1404
        t_written = snprintf(buf, RET_STR_LEN, "  Channels (* with key, ` no backlog)");
 
1405
        if (t_written >= RET_STR_LEN)
 
1406
                goto noroomchan;
 
1407
        for (hash_it_init(&lnk->chan_infos, &lit); hash_it_item(&lit);
 
1408
                        hash_it_next(&lit)) {
 
1409
                struct chan_info *ch = hash_it_item(&lit);
 
1410
 
 
1411
                t_written += snprintf(buf + t_written, RET_STR_LEN - t_written, " %s%s%s",
 
1412
                        ch->name, (ch->key ? "*" : ""),
 
1413
                        (ch->backlog ? "" : "`"));
 
1414
                if (t_written > LINE_SIZE_LIM) {
 
1415
                        buf[RET_STR_LEN] = 0;
 
1416
                        bip_notify(ic, "%s", buf);
 
1417
                        t_written = 0;
 
1418
                }
 
1419
        }
 
1420
noroomchan:
 
1421
        buf[RET_STR_LEN] = 0;
 
1422
        bip_notify(ic, "%s", buf);
 
1423
 
 
1424
        t_written = snprintf(buf, RET_STR_LEN, "  Status: ");
 
1425
        if (t_written >= RET_STR_LEN)
 
1426
                goto noroomstatus;
 
1427
        switch (lnk->s_state) {
 
1428
        case  IRCS_NONE:
 
1429
                t_written += snprintf(buf + t_written, RET_STR_LEN - t_written,
 
1430
                        "not started");
 
1431
                if (t_written >= RET_STR_LEN)
 
1432
                        goto noroomstatus;
 
1433
                break;
 
1434
        case  IRCS_CONNECTING:
 
1435
                t_written += snprintf(buf + t_written, RET_STR_LEN - t_written,
 
1436
                        "connecting... attempts: %d, last: %s",
 
1437
                        lnk->s_conn_attempt,
 
1438
                        hrtime(lnk->last_connection_attempt));
 
1439
                if (t_written >= RET_STR_LEN)
 
1440
                        goto noroomstatus;
 
1441
                break;
 
1442
        case  IRCS_CONNECTED:
 
1443
                t_written += snprintf(buf + t_written, RET_STR_LEN - t_written,
 
1444
                        "connected !");
 
1445
                if (t_written >= RET_STR_LEN)
 
1446
                        goto noroomstatus;
 
1447
                break;
 
1448
        case  IRCS_WAS_CONNECTED:
 
1449
                t_written += snprintf(buf + t_written, RET_STR_LEN - t_written,
 
1450
                        "disconnected, attempts: %d, last: %s",
 
1451
                        lnk->s_conn_attempt,
 
1452
                        hrtime(lnk->last_connection_attempt));
 
1453
                if (t_written >= RET_STR_LEN)
 
1454
                        goto noroomstatus;
 
1455
                break;
 
1456
        case  IRCS_RECONNECTING:
 
1457
                t_written += snprintf(buf + t_written, RET_STR_LEN - t_written,
 
1458
                        "reconnecting... attempts: %d, last: %s",
 
1459
                        lnk->s_conn_attempt,
 
1460
                        hrtime(lnk->last_connection_attempt));
 
1461
                if (t_written >= RET_STR_LEN)
 
1462
                        goto noroomstatus;
 
1463
                break;
 
1464
        case  IRCS_TIMER_WAIT:
 
1465
                t_written += snprintf(buf + t_written, RET_STR_LEN - t_written,
 
1466
                        "waiting to reconnect, attempts: %d, last: %s",
 
1467
                        lnk->s_conn_attempt,
 
1468
                        hrtime(lnk->last_connection_attempt));
 
1469
                if (t_written >= RET_STR_LEN)
 
1470
                        goto noroomstatus;
 
1471
                break;
 
1472
        default:
 
1473
                t_written += snprintf(buf + t_written, RET_STR_LEN - t_written,
 
1474
                        "unknown");
 
1475
                if (t_written >= RET_STR_LEN)
 
1476
                        goto noroomstatus;
 
1477
                break;
 
1478
                // s_conn_attempt recon_timer last_connection_attempt
 
1479
        }
 
1480
noroomstatus:
 
1481
        buf[RET_STR_LEN] = 0;
 
1482
        bip_notify(ic, "%s", buf);
 
1483
}
 
1484
 
 
1485
void adm_list_all_links(struct link_client *ic)
 
1486
{
 
1487
        list_iterator_t it;
 
1488
 
 
1489
        bip_notify(ic, "-- All links");
 
1490
        for (list_it_init(&_bip->link_list, &it); list_it_item(&it);
 
1491
                        list_it_next(&it)) {
 
1492
                struct link *l = list_it_item(&it);
 
1493
                if (l)
 
1494
                        adm_print_connection(ic, l, NULL);
 
1495
        }
 
1496
        bip_notify(ic, "-- End of All links");
 
1497
}
 
1498
 
 
1499
void adm_list_all_connections(struct link_client *ic)
 
1500
{
 
1501
        hash_iterator_t it;
 
1502
 
 
1503
        bip_notify(ic, "-- All connections");
 
1504
        for (hash_it_init(&_bip->users, &it); hash_it_item(&it);
 
1505
                        hash_it_next(&it)) {
 
1506
                struct bipuser *u = hash_it_item(&it);
 
1507
                if (u)
 
1508
                        adm_list_connections(ic, u);
 
1509
        }
 
1510
        bip_notify(ic, "-- End of All connections");
 
1511
}
 
1512
 
 
1513
#define STRORNULL(s) ((s) == NULL ? "unset" : (s))
 
1514
 
 
1515
void adm_info_user(struct link_client *ic, const char *name)
 
1516
{
 
1517
        struct bipuser *u;
 
1518
        char buf[RET_STR_LEN + 1];
 
1519
        int t_written = 0;
 
1520
 
 
1521
        bip_notify(ic, "-- User '%s' info", name);
 
1522
        u = hash_get(&_bip->users, name);
 
1523
        if (!u) {
 
1524
                bip_notify(ic, "Unknown user");
 
1525
                return;
 
1526
        }
 
1527
 
 
1528
        t_written += snprintf(buf + t_written, RET_STR_LEN - t_written,
 
1529
                              "user: %s", u->name);
 
1530
        if (t_written >= RET_STR_LEN)
 
1531
                goto noroom;
 
1532
        if (u->admin) {
 
1533
                t_written += snprintf(buf + t_written, RET_STR_LEN - t_written,
 
1534
                                ", is bip admin");
 
1535
                if (t_written >= RET_STR_LEN)
 
1536
                        goto noroom;
 
1537
        }
 
1538
 
 
1539
noroom:
 
1540
        buf[RET_STR_LEN] = 0;
 
1541
        bip_notify(ic, "%s", buf);
 
1542
 
 
1543
#ifdef HAVE_LIBSSL
 
1544
        bip_notify(ic, "SSL check mode '%s', stored into '%s'",
 
1545
                   checkmode2text(u->ssl_check_mode),
 
1546
                   STRORNULL(u->ssl_check_store));
 
1547
        if (u->ssl_client_certfile)
 
1548
                bip_notify(ic, "SSL client certificate stored into '%s'",
 
1549
                                u->ssl_client_certfile);
 
1550
#endif
 
1551
        bip_notify(ic, "Defaults nick: %s, user: %s, realname: %s",
 
1552
                   STRORNULL(u->default_nick), STRORNULL(u->default_username),
 
1553
                   STRORNULL(u->default_realname));
 
1554
        if (u->backlog) {
 
1555
                bip_notify(ic, "Backlog enabled, lines: %d, no timestamp: %s,"
 
1556
                        "  messages only: %s", u->backlog_lines,
 
1557
                        bool2text(u->backlog_no_timestamp),
 
1558
                        bool2text(u->bl_msg_only));
 
1559
                bip_notify(ic, "always backlog: %s, reset on talk: %s",
 
1560
                        bool2text(u->always_backlog),
 
1561
                        bool2text(u->blreset_on_talk));
 
1562
        } else {
 
1563
                bip_notify(ic, "Backlog disabled");
 
1564
        }
 
1565
        adm_list_connections(ic, u);
 
1566
        bip_notify(ic, "-- End of User '%s' info", name);
 
1567
}
 
1568
 
 
1569
void adm_list_users(struct link_client *ic)
 
1570
{
 
1571
        hash_iterator_t it;
 
1572
        hash_iterator_t lit;
 
1573
        char buf[RET_STR_LEN + 1];
 
1574
        connection_t *c;
 
1575
 
 
1576
        c = CONN(ic);
 
1577
 
 
1578
        bip_notify(ic, "-- User list");
 
1579
        for (hash_it_init(&_bip->users, &it); hash_it_item(&it);
 
1580
                        hash_it_next(&it)) {
 
1581
                struct bipuser *u = hash_it_item(&it);
 
1582
                int first = 1;
 
1583
                int t_written = 0;
 
1584
 
 
1585
                buf[RET_STR_LEN] = 0;
 
1586
                t_written += snprintf(buf, RET_STR_LEN, "* %s%s:", u->name,
 
1587
                                (u->admin ? "(admin)": ""));
 
1588
                if (t_written >= RET_STR_LEN)
 
1589
                        goto noroom;
 
1590
                for (hash_it_init(&u->connections, &lit); hash_it_item(&lit);
 
1591
                                hash_it_next(&lit)) {
 
1592
                        struct link *lnk = hash_it_item(&lit);
 
1593
                        if (first) {
 
1594
                                first = 0;
 
1595
                        } else {
 
1596
                                t_written += snprintf(buf + t_written,
 
1597
                                                RET_STR_LEN - t_written, ",");
 
1598
                                if (t_written >= RET_STR_LEN)
 
1599
                                        goto noroom;
 
1600
                        }
 
1601
 
 
1602
                        t_written += snprintf(buf + t_written,
 
1603
                                        RET_STR_LEN - t_written,
 
1604
                                        " %s", lnk->name);
 
1605
                        if (t_written >= RET_STR_LEN)
 
1606
                                goto noroom;
 
1607
                        if (t_written > LINE_SIZE_LIM) {
 
1608
                                buf[RET_STR_LEN] = 0;
 
1609
                                bip_notify(ic, "%s", buf);
 
1610
                                t_written = 0;
 
1611
                        }
 
1612
                }
 
1613
noroom:
 
1614
                buf[RET_STR_LEN] = 0;
 
1615
                bip_notify(ic, "%s", buf);
 
1616
        }
 
1617
        bip_notify(ic, "-- End of User list");
 
1618
}
 
1619
 
 
1620
void adm_list_networks(struct link_client *ic)
 
1621
{
 
1622
        hash_iterator_t it;
 
1623
        char buf[RET_STR_LEN + 1];
 
1624
        connection_t *c;
 
1625
 
 
1626
        c = CONN(ic);
 
1627
 
 
1628
        bip_notify(ic, "-- Network list (* means SSL):");
 
1629
        for (hash_it_init(&_bip->networks, &it); hash_it_item(&it);
 
1630
                        hash_it_next(&it)) {
 
1631
                struct network *n = hash_it_item(&it);
 
1632
                int t_written = 0;
 
1633
                int i;
 
1634
 
 
1635
                buf[RET_STR_LEN] = 0;
 
1636
#ifdef HAVE_LIBSSL
 
1637
                if (n->ssl) {
 
1638
                        t_written += snprintf(buf, RET_STR_LEN, "- %s*:",
 
1639
                                        n->name);
 
1640
                        if (t_written >= RET_STR_LEN)
 
1641
                                goto noroom;
 
1642
                } else {
 
1643
#endif
 
1644
                        t_written += snprintf(buf, RET_STR_LEN, "- %s:", n->name);
 
1645
                        if (t_written >= RET_STR_LEN)
 
1646
                                goto noroom;
 
1647
#ifdef HAVE_LIBSSL
 
1648
                }
 
1649
#endif
 
1650
                for (i = 0; i < n->serverc; i++) {
 
1651
                        struct server *serv = i+n->serverv;
 
1652
                        t_written += snprintf(buf + t_written, RET_STR_LEN
 
1653
                                - t_written, " %s:%d", serv->host,
 
1654
                                serv->port);
 
1655
                        if (t_written >= RET_STR_LEN)
 
1656
                                goto noroom;
 
1657
                        if (t_written > LINE_SIZE_LIM) {
 
1658
                                buf[RET_STR_LEN] = 0;
 
1659
                                bip_notify(ic, "%s", buf);
 
1660
                                t_written = 0;
 
1661
                        }
 
1662
                }
 
1663
noroom:
 
1664
                buf[RET_STR_LEN] = 0;
 
1665
                bip_notify(ic, "%s", buf);
 
1666
        }
 
1667
        bip_notify(ic, "-- End of Network list");
 
1668
}
 
1669
 
 
1670
void adm_list_connections(struct link_client *ic, struct bipuser *bu)
 
1671
{
 
1672
        hash_iterator_t it;
 
1673
        connection_t *c;
 
1674
 
 
1675
        c = CONN(ic);
 
1676
        if (!bu) {
 
1677
                bip_notify(ic, "-- Your connections:");
 
1678
                bu = LINK(ic)->user;
 
1679
        } else {
 
1680
                bip_notify(ic, "-- User %s's connections:", bu->name);
 
1681
        }
 
1682
 
 
1683
        for (hash_it_init(&bu->connections, &it); hash_it_item(&it);
 
1684
                        hash_it_next(&it)) {
 
1685
                struct link *lnk= hash_it_item(&it);
 
1686
                adm_print_connection(ic, lnk, bu);
 
1687
        }
 
1688
        bip_notify(ic, "-- End of Connection list");
 
1689
}
 
1690
 
 
1691
#ifdef HAVE_LIBSSL
 
1692
int link_add_untrusted(struct link_server *ls, X509 *cert)
 
1693
{
 
1694
        int i;
 
1695
 
 
1696
        /* Check whether the cert is already in the stack */
 
1697
        for (i = 0; i < sk_X509_num(LINK(ls)->untrusted_certs); i++) {
 
1698
                if (!X509_cmp(cert,
 
1699
                                sk_X509_value(LINK(ls)->untrusted_certs, i)))
 
1700
                        return 1;
 
1701
        }
 
1702
 
 
1703
        return sk_X509_push(LINK(ls)->untrusted_certs, cert);
 
1704
}
 
1705
 
 
1706
int ssl_check_trust(struct link_client *ic)
 
1707
{
 
1708
        X509 *trustcert = NULL;
 
1709
        char subject[270];
 
1710
        char issuer[270];
 
1711
        unsigned char fp[EVP_MAX_MD_SIZE];
 
1712
        char fpstr[EVP_MAX_MD_SIZE * 3 + 20];
 
1713
        unsigned int fplen;
 
1714
        int i;
 
1715
 
 
1716
        if(!LINK(ic)->untrusted_certs ||
 
1717
                        sk_X509_num(LINK(ic)->untrusted_certs) <= 0)
 
1718
                return 0;
 
1719
 
 
1720
        trustcert = sk_X509_value(LINK(ic)->untrusted_certs, 0);
 
1721
        strcpy(subject, "Subject: ");
 
1722
        strcpy(issuer, "Issuer:  ");
 
1723
        strcpy(fpstr, "MD5 fingerprint: ");
 
1724
        X509_NAME_oneline(X509_get_subject_name(trustcert), subject + 9, 256);
 
1725
        X509_NAME_oneline(X509_get_issuer_name(trustcert), issuer + 9, 256);
 
1726
 
 
1727
        X509_digest(trustcert, EVP_md5(), fp, &fplen);
 
1728
        for(i = 0; i < (int)fplen; i++)
 
1729
                sprintf(fpstr + 17 + (i * 3), "%02X%c",
 
1730
                                fp[i], (i == (int)fplen - 1) ? '\0' : ':');
 
1731
 
 
1732
        WRITE_LINE2(CONN(ic), P_SERV, "NOTICE", "TrustEm",
 
1733
                        "This server SSL certificate was not "
 
1734
                        "accepted because it is not in your store "
 
1735
                        "of trusted certificates:");
 
1736
 
 
1737
        WRITE_LINE2(CONN(ic), P_SERV, "NOTICE", "TrustEm", subject);
 
1738
        WRITE_LINE2(CONN(ic), P_SERV, "NOTICE", "TrustEm", issuer);
 
1739
        WRITE_LINE2(CONN(ic), P_SERV, "NOTICE", "TrustEm", fpstr);
 
1740
 
 
1741
        WRITE_LINE2(CONN(ic), P_SERV, "NOTICE", "TrustEm",
 
1742
                        "WARNING: if you've already trusted a "
 
1743
                        "certificate for this server before, that "
 
1744
                        "probably means it has changed.");
 
1745
 
 
1746
        WRITE_LINE2(CONN(ic), P_SERV, "NOTICE", "TrustEm",
 
1747
                        "If so, YOU MAY BE SUBJECT OF A "
 
1748
                        "MAN-IN-THE-MIDDLE ATTACK! PLEASE DON'T TRUST "
 
1749
                        "THIS CERTIFICATE IF YOU'RE NOT SURE THIS IS "
 
1750
                        "NOT THE CASE.");
 
1751
 
 
1752
        WRITE_LINE2(CONN(ic), P_SERV, "NOTICE", "TrustEm",
 
1753
                        "Type /QUOTE BIP TRUST OK to trust this "
 
1754
                        "certificate, /QUOTE BIP TRUST NO to discard it.");
 
1755
 
 
1756
        return 1;
 
1757
}
 
1758
 
 
1759
#if 0
 
1760
static int ssl_trust_next_cert(struct link_client *ic)
 
1761
{
 
1762
        (void)ic;
 
1763
}
 
1764
 
 
1765
static int ssl_discard_next_cert(struct link_client *ic)
 
1766
{
 
1767
        (void)ic;
 
1768
}
 
1769
#endif /* 0 */
 
1770
#endif
 
1771
 
 
1772
#ifdef HAVE_LIBSSL
 
1773
int adm_trust(struct link_client *ic, struct line *line)
 
1774
{
 
1775
        if (ic->allow_trust != 1) {
 
1776
                mylog(LOG_ERROR, "User attempted TRUST command without "
 
1777
                                "being allowed to!");
 
1778
                unbind_from_link(ic);
 
1779
                return OK_CLOSE;
 
1780
        }
 
1781
 
 
1782
        if(!LINK(ic)->untrusted_certs ||
 
1783
                        sk_X509_num(LINK(ic)->untrusted_certs) <= 0) {
 
1784
                /* shouldn't have been asked to /QUOTE BIP TRUST but well... */
 
1785
                WRITE_LINE2(CONN(ic), P_SERV, "NOTICE", "TrustEm",
 
1786
                                "No untrusted certificates.");
 
1787
                return ERR_PROTOCOL;
 
1788
        }
 
1789
 
 
1790
        if (irc_line_count(line) != 3)
 
1791
                return ERR_PROTOCOL;
 
1792
 
 
1793
        if (irc_line_elem_case_equals(line, 2, "OK")) {
 
1794
                /* OK, attempt to trust the cert! */
 
1795
                BIO *bio = BIO_new_file(LINK(ic)->user->ssl_check_store, "a+");
 
1796
                X509 *trustcert = sk_X509_shift(LINK(ic)->untrusted_certs);
 
1797
 
 
1798
                if(!bio || !trustcert ||
 
1799
                                PEM_write_bio_X509(bio, trustcert) <= 0)
 
1800
                        write_line_fast(CONN(ic), ":irc.bip.net NOTICE pouet "
 
1801
                                        ":==== Error while trusting test!\r\n");
 
1802
                else
 
1803
                        write_line_fast(CONN(ic), ":irc.bip.net NOTICE pouet "
 
1804
                                        ":==== Certificate now trusted.\r\n");
 
1805
 
 
1806
                BIO_free_all(bio);
 
1807
                X509_free(trustcert);
 
1808
        } else if (irc_line_elem_case_equals(line, 2, "NO")) {
 
1809
                /* NO, discard the cert! */
 
1810
                write_line_fast(CONN(ic), ":irc.bip.net NOTICE pouet "
 
1811
                                ":==== Certificate discarded.\r\n");
 
1812
 
 
1813
                X509_free(sk_X509_shift(LINK(ic)->untrusted_certs));
 
1814
        } else
 
1815
                return ERR_PROTOCOL;
 
1816
 
 
1817
        if (!ssl_check_trust(ic)) {
 
1818
                write_line_fast(CONN(ic), ":irc.bip.net NOTICE pouet "
 
1819
                                ":No more certificates waiting awaiting "
 
1820
                                "user trust, thanks!\r\n");
 
1821
                write_line_fast(CONN(ic), ":irc.bip.net NOTICE pouet "
 
1822
                                ":If the certificate is trusted, bip should "
 
1823
                                "be able to connect to the server on the "
 
1824
                                "next retry. Please wait a while and try "
 
1825
                                "connecting your client again.\r\n");
 
1826
 
 
1827
                LINK(ic)->recon_timer = 1; /* Speed up reconnection... */
 
1828
                unbind_from_link(ic);
 
1829
                return OK_CLOSE;
 
1830
        }
 
1831
        return OK_FORGET;
 
1832
}
 
1833
#endif
 
1834
 
 
1835
void _bip_notify(struct link_client *ic, char *fmt, va_list ap)
 
1836
{
 
1837
        char *nick;
 
1838
        char str[4096];
 
1839
 
 
1840
        if (LINK(ic)->l_server)
 
1841
                nick = LINK(ic)->l_server->nick;
 
1842
        else
 
1843
                nick = LINK(ic)->prev_nick;
 
1844
 
 
1845
        vsnprintf(str, 4095, fmt, ap);
 
1846
        str[4095] = 0;
 
1847
        WRITE_LINE2(CONN(ic), P_IRCMASK, (LINK(ic)->user->bip_use_notice ?
 
1848
                                "NOTICE" : "PRIVMSG"), nick, str);
 
1849
}
 
1850
 
 
1851
void bip_notify(struct link_client *ic, char *fmt, ...)
 
1852
{
 
1853
        va_list ap;
 
1854
 
 
1855
        va_start(ap, fmt);
 
1856
        _bip_notify(ic, fmt, ap);
 
1857
        va_end(ap);
 
1858
}
 
1859
 
 
1860
void adm_blreset(struct link_client *ic)
 
1861
{
 
1862
        log_reset_all(LINK(ic)->log);
 
1863
        bip_notify(ic, "backlog resetted for this network.");
 
1864
}
 
1865
 
 
1866
void adm_blreset_store(struct link_client *ic, const char *store)
 
1867
{
 
1868
        log_reset_store(LINK(ic)->log, store);
 
1869
        bip_notify(ic, "backlog resetted for %s.", store);
 
1870
}
 
1871
 
 
1872
void adm_follow_nick(struct link_client *ic, const char *val)
 
1873
{
 
1874
        struct link *link = LINK(ic);
 
1875
        if (strcasecmp(val, "TRUE") == 0) {
 
1876
                link->follow_nick = 1;
 
1877
                bip_notify(ic, "follow_nick is now true.");
 
1878
        } else {
 
1879
                link->follow_nick = 0;
 
1880
                bip_notify(ic, "follow_nick is now false.");
 
1881
        }
 
1882
}
 
1883
 
 
1884
void adm_ignore_first_nick(struct link_client *ic, const char *val)
 
1885
{
 
1886
        struct link *link = LINK(ic);
 
1887
        if (strcasecmp(val, "TRUE") == 0) {
 
1888
                link->ignore_first_nick = 1;
 
1889
                bip_notify(ic, "ignore_first_nick is now true.");
 
1890
        } else {
 
1891
                link->ignore_first_nick = 0;
 
1892
                bip_notify(ic, "ignore_first_nick is now false.");
 
1893
        }
 
1894
}
 
1895
 
 
1896
void set_on_connect_send(struct link_client *ic, char *val)
 
1897
{
 
1898
        struct link *link = LINK(ic);
 
1899
        char *s;
 
1900
 
 
1901
        if (val != NULL) {
 
1902
                list_add_last(&link->on_connect_send, bip_strdup(val));
 
1903
                bip_notify(ic, "added to on_connect_send.");
 
1904
        } else {
 
1905
                s = list_remove_last(&link->on_connect_send);
 
1906
                if (s)
 
1907
                        free(s);
 
1908
                bip_notify(ic, "last on_connect_send string deleted.");
 
1909
        }
 
1910
}
 
1911
 
 
1912
#define ON_CONNECT_MAX_STRSIZE 1024
 
1913
void adm_on_connect_send(struct link_client *ic, struct line *line,
 
1914
                unsigned int privmsg)
 
1915
{
 
1916
        char buf[ON_CONNECT_MAX_STRSIZE];
 
1917
        int t_written = 0;
 
1918
        int i;
 
1919
 
 
1920
        if (!line) {
 
1921
                set_on_connect_send(ic, NULL);
 
1922
                return;
 
1923
        }
 
1924
 
 
1925
        if (irc_line_includes(line, 2))
 
1926
                return;
 
1927
 
 
1928
        for (i = privmsg + 2; i < irc_line_count(line); i++) {
 
1929
                if (t_written) {
 
1930
                        t_written += snprintf(buf,
 
1931
                                        ON_CONNECT_MAX_STRSIZE - 1 - t_written,
 
1932
                                        " %s", irc_line_elem(line, i));
 
1933
                        if (t_written >= ON_CONNECT_MAX_STRSIZE)
 
1934
                                goto noroom;
 
1935
                } else {
 
1936
                        t_written = snprintf(buf, ON_CONNECT_MAX_STRSIZE - 1,
 
1937
                                        "%s", irc_line_elem(line, i));
 
1938
                        if (t_written >= ON_CONNECT_MAX_STRSIZE)
 
1939
                                goto noroom;
 
1940
                }
 
1941
        }
 
1942
ok:
 
1943
        buf[ON_CONNECT_MAX_STRSIZE - 1] = 0;
 
1944
        set_on_connect_send(ic, buf);
 
1945
        return;
 
1946
noroom:
 
1947
        bip_notify(ic, "on connect send string too big, truncated");
 
1948
        goto ok;
 
1949
}
 
1950
 
 
1951
void adm_away_nick(struct link_client *ic, const char *val)
 
1952
{
 
1953
        struct link *link = LINK(ic);
 
1954
        if (link->away_nick) {
 
1955
                free(link->away_nick);
 
1956
                link->away_nick = NULL;
 
1957
        }
 
1958
        if (val != NULL) {
 
1959
                link->away_nick = bip_strdup(val);
 
1960
                bip_notify(ic, "away_nick set.");
 
1961
        } else {
 
1962
                bip_notify(ic, "away_nick cleared.");
 
1963
        }
 
1964
}
 
1965
 
 
1966
void adm_bip_help(struct link_client *ic, int admin, const char *subhelp)
 
1967
{
 
1968
        if (subhelp == NULL) {
 
1969
                if (admin) {
 
1970
                        bip_notify(ic, "/BIP RELOAD # Re-read bip "
 
1971
                                        "configuration and apply changes.");
 
1972
                        bip_notify(ic, "/BIP INFO user <username> "
 
1973
                                        "# show a user's configuration");
 
1974
                        bip_notify(ic, "/BIP LIST networks|users|connections|"
 
1975
                                        "all_links|all_connections");
 
1976
                        bip_notify(ic, "/BIP ADD_CONN <connection name> "
 
1977
                                        "<network>");
 
1978
                        bip_notify(ic, "/BIP DEL_CONN <connection name>");
 
1979
                } else {
 
1980
                        bip_notify(ic, "/BIP LIST networks|connections");
 
1981
                }
 
1982
                bip_notify(ic, "/BIP JUMP # jump to next server (in same "
 
1983
                                "network)");
 
1984
                bip_notify(ic, "/BIP BLRESET [channel|query]# reset backlog "
 
1985
                                "(this connection only). Add -q flag and the "
 
1986
                                "operation is quiet. You can specify a channel "
 
1987
                                "or a nick to reset only this channel/query.");
 
1988
                bip_notify(ic, "/BIP HELP [subhelp] # show this help...");
 
1989
                bip_notify(ic, "## Temporary changes for this connection:");
 
1990
                bip_notify(ic, "/BIP FOLLOW_NICK|IGNORE_FIRST_NICK TRUE|FALSE");
 
1991
                bip_notify(ic, "/BIP ON_CONNECT_SEND <str> # Adds a string to "
 
1992
                        "send on connect");
 
1993
                bip_notify(ic, "/BIP ON_CONNECT_SEND # Clears on_connect_send");
 
1994
                bip_notify(ic, "/BIP AWAY_NICK <nick> # Set away nick");
 
1995
                bip_notify(ic, "/BIP AWAY_NICK # clear away nick");
 
1996
                bip_notify(ic, "/BIP BACKLOG [n] # backlog text of the n last "
 
1997
                                "hours");
 
1998
        } else if (admin && strcasecmp(subhelp, "RELOAD") == 0) {
 
1999
                bip_notify(ic, "/BIP RELOAD (admin only) :");
 
2000
                bip_notify(ic, "  Reloads bip configuration file and apply "
 
2001
                        "changes.");
 
2002
                bip_notify(ic, "  Please note that changes to 'user' or "
 
2003
                        "'realname' will not be applied without a JUMP.");
 
2004
        } else if (admin && strcasecmp(subhelp, "INFO") == 0) {
 
2005
                bip_notify(ic, "/BIP INFO USER <user> (admin only) :");
 
2006
                bip_notify(ic, "  Show <user>'s current configuration.");
 
2007
                bip_notify(ic, "  That means it may be different from the "
 
2008
                        "configuration stored in bip.conf");
 
2009
        } else if (admin && strcasecmp(subhelp, "ADD_CONN") == 0) {
 
2010
                bip_notify(ic, "/BIP ADD_CONN <connection name> <network> "
 
2011
                        "(admin only) :");
 
2012
                bip_notify(ic, "  Add a connection named <connection name> to "
 
2013
                        "the network <network> to your connection list");
 
2014
                bip_notify(ic, "  <network> should already exist in bip's "
 
2015
                        "configuration.");
 
2016
        } else if (admin && strcasecmp(subhelp, "DEL_CONN") == 0) {
 
2017
                bip_notify(ic, "/BIP DEL_CONN <connection name> (admin only) "
 
2018
                        ":");
 
2019
                bip_notify(ic, "  Remove the connection named <connection "
 
2020
                        "name> from your connection list.");
 
2021
                bip_notify(ic, "  Removing a connection will cause "
 
2022
                        "its disconnection.");
 
2023
        } else if (strcasecmp(subhelp, "JUMP") == 0) {
 
2024
                bip_notify(ic, "/BIP JUMP :");
 
2025
                bip_notify(ic, "  Jump to next server in current network.");
 
2026
        } else if (strcasecmp(subhelp, "BLRESET") == 0) {
 
2027
                bip_notify(ic, "/BIP BLRESET :");
 
2028
                bip_notify(ic, "  Reset backlog on this network.");
 
2029
        } else if (strcasecmp(subhelp, "FOLLOW_NICK") == 0) {
 
2030
                bip_notify(ic, "/BIP FOLLOW_NICK TRUE|FALSE :");
 
2031
                bip_notify(ic, "  Change the value of the follow_nick option "
 
2032
                        "for this connection.");
 
2033
                bip_notify(ic, "  If set to true, when you change nick, "
 
2034
                        "BIP stores the new nickname as the new default "
 
2035
                        "nickname value.");
 
2036
                bip_notify(ic, "  Thus, if you are disconnected from the "
 
2037
                        "server, BIP will restore the correct nickname.");
 
2038
        } else if (strcasecmp(subhelp, "IGNORE_FIRST_NICK") == 0) {
 
2039
                bip_notify(ic, "/BIP IGNORE_FIRST_NICK TRUE|FALSE :");
 
2040
                bip_notify(ic, "  Change the value of the ignore_first_nick "
 
2041
                        "option for this connection.");
 
2042
                bip_notify(ic, "  If set to TRUE, BIP will ignore the nickname"
 
2043
                        "sent by the client upon connect.");
 
2044
                bip_notify(ic, "  Further nickname changes will be processed "
 
2045
                        "as usual.");
 
2046
        } else if (strcasecmp(subhelp, "ON_CONNECT_SEND") == 0) {
 
2047
                bip_notify(ic, "/BIP ON_CONNECT_SEND [some text] :");
 
2048
                bip_notify(ic, "  BIP will send the text as is to the server "
 
2049
                        "upon connection.");
 
2050
                bip_notify(ic, "  You can call this command more than once.");
 
2051
                bip_notify(ic, "  If [some text] is empty, this command will "
 
2052
                        "remove any on_connect_send defined for this connection.");
 
2053
        } else if (strcasecmp(subhelp, "AWAY_NICK") == 0) {
 
2054
                bip_notify(ic, "/BIP AWAY_NICK [some_nick] :");
 
2055
                bip_notify(ic, "  If [some_nick] is set, BIP will change "
 
2056
                        "nickname to [some_nick] if there are no more client "
 
2057
                        "attached");
 
2058
                bip_notify(ic, "  If [some_nick] is empty, this command will "
 
2059
                        "unset current connection's away_nick.");
 
2060
        } else if (strcasecmp(subhelp, "LIST") == 0) {
 
2061
                bip_notify(ic, "/BIP LIST <section> :");
 
2062
                bip_notify(ic, "  List information from a these sections :");
 
2063
                bip_notify(ic, "  - networks: list all available networks");
 
2064
                bip_notify(ic, "  - connections: list all your configured "
 
2065
                        "connections and their state.");
 
2066
                if (admin) {
 
2067
                        bip_notify(ic, "  - users: list all users (admin)");
 
2068
                        bip_notify(ic, "  - all_links: list all connected "
 
2069
                                "sockets from and to BIP (admin)");
 
2070
                        bip_notify(ic, "  - all_connections: list all users' "
 
2071
                                "configured connections (admin)");
 
2072
                }
 
2073
        } else {
 
2074
                bip_notify(ic, "-- No sub-help for '%s'", subhelp);
 
2075
        }
 
2076
}
 
2077
 
 
2078
int adm_bip(bip_t *bip, struct link_client *ic, struct line *line, int privmsg)
 
2079
{
 
2080
        int admin = LINK(ic)->user->admin;
 
2081
 
 
2082
        if (privmsg) {
 
2083
                char *linestr, *elemstr;
 
2084
                char *ptr, *eptr;
 
2085
                int slen;
 
2086
 
 
2087
                if (irc_line_count(line) != 3)
 
2088
                        return OK_FORGET;
 
2089
 
 
2090
                linestr = irc_line_pop(line);
 
2091
                ptr = linestr;
 
2092
 
 
2093
                /* all elem size <= linestr size */
 
2094
                elemstr = bip_malloc(strlen(linestr) + 1);
 
2095
 
 
2096
                while((eptr = strstr(ptr, " "))) {
 
2097
                        slen = eptr - ptr;
 
2098
                        if (slen == 0) {
 
2099
                                ptr++;
 
2100
                                continue;
 
2101
                        }
 
2102
                        memcpy(elemstr, ptr, slen);
 
2103
                        elemstr[slen] = 0;
 
2104
                        irc_line_append(line, elemstr);
 
2105
                        ptr = eptr + 1;
 
2106
                }
 
2107
                eptr = ptr + strlen(ptr);
 
2108
                slen = eptr - ptr;
 
2109
                if (slen != 0) {
 
2110
                        memcpy(elemstr, ptr, slen);
 
2111
                        elemstr[slen] = 0;
 
2112
                        irc_line_append(line, elemstr);
 
2113
                }
 
2114
                free(elemstr);
 
2115
                free(linestr);
 
2116
        }
 
2117
 
 
2118
        if (!irc_line_includes(line, privmsg + 1))
 
2119
                return OK_FORGET;
 
2120
 
 
2121
        mylog(LOG_INFO, "/BIP %s from %s", irc_line_elem(line, privmsg + 1),
 
2122
                        LINK(ic)->user->name);
 
2123
        if (strcasecmp(irc_line_elem(line, privmsg + 1), "RELOAD") == 0) {
 
2124
                if (!admin) {
 
2125
                        bip_notify(ic, "-- You're not allowed to reload bip");
 
2126
                        return OK_FORGET;
 
2127
                }
 
2128
                bip_notify(ic, "-- Reloading bip...");
 
2129
                bip->reloading_client = ic;
 
2130
                sighup = 1;
 
2131
        } else if (strcasecmp(irc_line_elem(line, privmsg + 1), "LIST") == 0) {
 
2132
                if (irc_line_count(line) != privmsg + 3) {
 
2133
                        bip_notify(ic, "-- LIST command needs one argument");
 
2134
                        return OK_FORGET;
 
2135
                }
 
2136
 
 
2137
                if (admin && strcasecmp(irc_line_elem(line, privmsg + 2),
 
2138
                                        "users") == 0) {
 
2139
                        adm_list_users(ic);
 
2140
                } else if (strcasecmp(irc_line_elem(line, privmsg + 2),
 
2141
                                        "networks") == 0) {
 
2142
                        adm_list_networks(ic);
 
2143
                } else if (strcasecmp(irc_line_elem(line, privmsg + 2),
 
2144
                                        "connections") == 0) {
 
2145
                        adm_list_connections(ic, NULL);
 
2146
                } else if (admin && strcasecmp(irc_line_elem(line, privmsg + 2),
 
2147
                                        "all_connections") == 0) {
 
2148
                        adm_list_all_connections(ic);
 
2149
                } else if (admin && strcasecmp(irc_line_elem(line, privmsg + 2),
 
2150
                                        "all_links") == 0) {
 
2151
                        adm_list_all_links(ic);
 
2152
                } else {
 
2153
                        bip_notify(ic, "-- Invalid LIST request");
 
2154
                }
 
2155
        } else if (strcasecmp(irc_line_elem(line, privmsg + 1), "INFO") == 0) {
 
2156
                if (!irc_line_includes(line, privmsg + 2)) {
 
2157
                        bip_notify(ic, "-- INFO command needs at least one "
 
2158
                                        "argument");
 
2159
                        return OK_FORGET;
 
2160
                }
 
2161
 
 
2162
                if (admin && irc_line_elem_case_equals(line, privmsg + 2,
 
2163
                                        "user") == 0) {
 
2164
                        if (irc_line_count(line) == privmsg + 4) {
 
2165
                                adm_info_user(ic,
 
2166
                                        irc_line_elem(line, privmsg + 3));
 
2167
                        } else {
 
2168
                                bip_notify(ic, "-- INFO USER command needs one"
 
2169
                                        " argument");
 
2170
                        }
 
2171
#if 0
 
2172
                        TODO network info
 
2173
#endif
 
2174
                } else {
 
2175
                        bip_notify(ic, "-- Invalid INFO request");
 
2176
                }
 
2177
        } else if (irc_line_elem_case_equals(line, privmsg + 1, "JUMP")) {
 
2178
                if (LINK(ic)->l_server) {
 
2179
                        WRITE_LINE1(CONN(LINK(ic)->l_server), NULL, "QUIT",
 
2180
                                        "jumpin' jumpin'");
 
2181
                        connection_close(CONN(LINK(ic)->l_server));
 
2182
                }
 
2183
                bip_notify(ic, "-- Jumping to next server");
 
2184
        } else if (irc_line_elem_case_equals(line, privmsg + 1, "BLRESET")) {
 
2185
                if (irc_line_includes(line, privmsg + 2)) {
 
2186
                        if (irc_line_elem_equals(line, privmsg + 2, "-q")) {
 
2187
                                if (irc_line_includes(line, privmsg + 3)) {
 
2188
                                        log_reset_store(LINK(ic)->log,
 
2189
                                                irc_line_elem(line,
 
2190
                                                        privmsg + 3));
 
2191
                                } else {
 
2192
                                        log_reset_all(LINK(ic)->log);
 
2193
                                }
 
2194
                        } else {
 
2195
                                adm_blreset_store(ic, irc_line_elem(line,
 
2196
                                                        privmsg + 2));
 
2197
                        }
 
2198
                } else {
 
2199
                        adm_blreset(ic);
 
2200
                }
 
2201
        } else if (irc_line_elem_case_equals(line, privmsg + 1, "HELP")) {
 
2202
                if (irc_line_count(line) == privmsg + 2)
 
2203
                        adm_bip_help(ic, admin, NULL);
 
2204
                else if (irc_line_count(line) == privmsg + 3)
 
2205
                        adm_bip_help(ic, admin,
 
2206
                                        irc_line_elem(line, privmsg + 2));
 
2207
                else
 
2208
                        bip_notify(ic,
 
2209
                                "-- HELP command needs at most one argument");
 
2210
        } else if (irc_line_elem_case_equals(line, privmsg + 1, "FOLLOW_NICK")) {
 
2211
                if (irc_line_count(line) != privmsg + 3) {
 
2212
                        bip_notify(ic,
 
2213
                                "-- FOLLOW_NICK command needs one argument");
 
2214
                        return OK_FORGET;
 
2215
                }
 
2216
                adm_follow_nick(ic, irc_line_elem(line, privmsg + 2));
 
2217
        } else if (irc_line_elem_case_equals(line, privmsg + 1,
 
2218
                                "IGNORE_FIRST_NICK")) {
 
2219
                if (irc_line_count(line) != privmsg + 3) {
 
2220
                        bip_notify(ic, "-- IGNORE_FIRST_NICK "
 
2221
                                "command needs one argument");
 
2222
                        return OK_FORGET;
 
2223
                }
 
2224
                adm_ignore_first_nick(ic, irc_line_elem(line, privmsg + 2));
 
2225
        } else if (irc_line_elem_case_equals(line, privmsg + 1,
 
2226
                                "ON_CONNECT_SEND")) {
 
2227
                if (irc_line_count(line) == privmsg + 2) {
 
2228
                        adm_on_connect_send(ic, NULL, 0);
 
2229
                } else if (irc_line_includes(line, privmsg + 2)) {
 
2230
                        adm_on_connect_send(ic, line, privmsg);
 
2231
                } else {
 
2232
                        bip_notify(ic, "-- ON_CONNECT_SEND command needs at "
 
2233
                                "least one argument");
 
2234
                }
 
2235
        } else if (irc_line_elem_case_equals(line, privmsg + 1, "AWAY_NICK")) {
 
2236
                if (irc_line_count(line) == privmsg + 2) {
 
2237
                        adm_away_nick(ic, NULL);
 
2238
                } else if (irc_line_count(line) == privmsg + 3) {
 
2239
                        adm_away_nick(ic, irc_line_elem(line, privmsg + 2));
 
2240
                } else {
 
2241
                        bip_notify(ic, "-- AWAY_NICK command needs zero or one"
 
2242
                                " argument");
 
2243
                }
 
2244
        } else if (irc_line_elem_case_equals(line, privmsg + 1, "BACKLOG")) {
 
2245
                if (irc_line_count(line) == privmsg + 2) {
 
2246
                        irc_cli_backlog(ic, 0);
 
2247
                } else if (irc_line_count(line) == privmsg + 3) {
 
2248
                        int hours = atoi(irc_line_elem(line, privmsg + 2));
 
2249
                        irc_cli_backlog(ic, hours);
 
2250
                } else {
 
2251
                        bip_notify(ic, "-- BACKLOG takes 0 or one argument");
 
2252
                }
 
2253
        } else if (admin && irc_line_elem_case_equals(line, privmsg + 1,
 
2254
                                "ADD_CONN")) {
 
2255
                if (irc_line_count(line) != privmsg + 4) {
 
2256
                        bip_notify(ic, "/BIP ADD_CONN <connection name> "
 
2257
                                        "<network name>");
 
2258
                } else {
 
2259
                        adm_bip_addconn(bip, ic,
 
2260
                                        irc_line_elem(line, privmsg + 2),
 
2261
                                        irc_line_elem(line, privmsg + 3));
 
2262
                }
 
2263
        } else if (admin && irc_line_elem_case_equals(line, privmsg + 1,
 
2264
                                "DEL_CONN")) {
 
2265
                if (irc_line_count(line) != privmsg + 3) {
 
2266
                        bip_notify(ic, "/BIP DEL_CONN <connection name>");
 
2267
                } else {
 
2268
                        adm_bip_delconn(bip, ic,
 
2269
                                        irc_line_elem(line, privmsg + 2));
 
2270
                }
 
2271
        } else {
 
2272
                bip_notify(ic, "Unknown command.");
 
2273
        }
 
2274
        return OK_FORGET;
 
2275
}
 
2276
 
 
2277
void free_conf(list_t *l)
 
2278
{
 
2279
        struct tuple *t;
 
2280
        list_iterator_t li;
 
2281
 
 
2282
        for (list_it_init(l, &li); (t = list_it_item(&li)); list_it_next(&li)) {
 
2283
                switch (t->tuple_type) {
 
2284
                case TUPLE_STR:
 
2285
                        free(t->pdata);
 
2286
                        break;
 
2287
                case TUPLE_INT:
 
2288
                        break;
 
2289
                case TUPLE_LIST:
 
2290
                        free_conf(t->pdata);
 
2291
                        break;
 
2292
                default:
 
2293
                        fatal("internal error free_conf");
 
2294
                        break;
 
2295
                }
 
2296
                free(t);
 
2297
        }
 
2298
        free(l);
 
2299
}
 
2300