1
0
forked from bip/bip

Compare commits

..

3 Commits

Author SHA1 Message Date
Loïc Gomez
65fdde9e21 Also reload SSL context on bip reload, allowing for SSL cert updates 2024-02-07 18:08:26 +09:00
Loïc Gomez
ee9478e7ce Allow checking ssl files are readable (check_ssl_files) 2024-02-07 18:08:25 +09:00
Loïc Gomez
24365e72e8 Move SSL context code to get/set_ssl_context methods 2024-02-07 18:07:36 +09:00
14 changed files with 170 additions and 183 deletions

View File

@ -3,7 +3,7 @@ if COND_WANT_TESTS
endif
SUBDIRS = src . $(MAYBE_TESTS)
dist_man_MANS = bip.1 bip.conf.5 bipmkpw.1 bipgenconfig.1
dist_man_MANS = bip.1 bip.conf.5 bipmkpw.1
examplesdir = $(prefix)/share/doc/bip/examples/
dist_examples_DATA = samples/bip.conf samples/bip.vim

View File

@ -146,7 +146,7 @@ Defines the delay between each logfiles sync to the disk. Must be a non null
positive integer.
.TP
\fBreconn_timer\fP (default: \fB30\fP)
\fBreconn_timer\fP (default: \fB120\fP)
Defines the initial delay (in seconds) before a reconnection attempt.
The delay increases with the number of attempts:
delay = reconn_timer * number of attempts
@ -227,7 +227,7 @@ This option should of course not be enabled if \fBbacklog_lines\fP is 0 !
If you still want to do so, don't forget to \fB/BIP BLRESET\fP sometimes.
.TP
\fBbacklog_lines\fP (default: \fB0\fP)
\fBbacklog_lines\fP (default: \fB10\fP)
If set to 0, BIP will replay all the logs since last client disconnect. Else,
it'll replay exactly \fBbacklog_lines\fP lines on each channel and privates.
Be aware that BIP will replay \fBbacklog_lines\fP lines of all privates, even

View File

@ -86,7 +86,7 @@
# Sets the initial delay (in seconds) before a reconnection attempt.
# The delay increases with the number of attempts:
# delay = reconn_timer * number of attempts
#reconn_timer = 30;
#reconn_timer = 120;
# Network definition, a name and server info
#network {

View File

@ -119,7 +119,7 @@ my %optdesc = (
'optional' => 1,
'depends' => 'log', 'depval' => 'true',
'desc' => 'Do you want to activate backlog {play back logs} system ?' },
'backlog_lines' => { 'type' => 'i', 'adv' => 0, 'default' => '0',
'backlog_lines' => { 'type' => 'i', 'adv' => 0, 'default' => '10',
'optional' => 1,
'depends' => 'backlog', 'depval' => 'true',
'desc' => 'How much line do you want bip to play back upon client connect' .

View File

@ -67,7 +67,6 @@ void conf_die(bip_t *bip, char *fmt, ...);
static char *get_tuple_pvalue(list_t *tuple_l, int lex);
void bip_notify(struct link_client *ic, char *fmt, ...);
void adm_list_connections(struct link_client *ic, struct bipuser *bu);
struct link *find_link(const char *link_name, struct bipuser *bu);
void free_conf(list_t *l);
@ -374,45 +373,6 @@ static int add_network(bip_t *bip, list_t *data)
return 1;
}
void adm_bip_jump(struct link_client *ic, const char *conn_name,
int reset_timer)
{
struct link *lnk;
if (conn_name) {
lnk = find_link(conn_name, LINK(ic)->user);
if (!lnk) {
bip_notify(ic, "-- Cannot find connection named %s",
conn_name);
return;
}
goto do_the_jump;
} else {
lnk = LINK(ic);
}
do_the_jump:
if (!lnk->l_server) {
if (reset_timer) {
lnk->recon_timer = 0;
bip_notify(ic,
"-- %s is not connected, "
"timer has been reset, please wait",
conn_name);
return;
}
int timer = (lnk->recon_timer ? lnk->recon_timer : 0);
bip_notify(ic,
"-- %s is not connected, "
"please wait for reconnect (%ds)",
conn_name, timer);
return;
}
WRITE_LINE1(CONN(lnk->l_server), NULL, "QUIT", "jumpin' jumpin'");
connection_close(CONN(lnk->l_server));
bip_notify(ic, "-- Jumping to next server on %s", conn_name);
}
void adm_bip_delconn(bip_t *bip, struct link_client *ic, const char *conn_name)
{
struct bipuser *user = LINK(ic)->user;
@ -704,31 +664,6 @@ static int add_connection(bip_t *bip, struct bipuser *user, list_t *data)
return 1;
}
struct link *find_link(const char *link_name, struct bipuser *bu)
{
list_iterator_t it;
// Immediately return NULL when bip user (bu) is NULL
if (!bu) {
return NULL;
}
for (list_it_init(&_bip->link_list, &it); list_it_item(&it);
list_it_next(&it)) {
struct link *lnk = list_it_item(&it);
if (!lnk)
continue;
// Only lookup in optionally specified user links
if (bu != lnk->user)
continue;
if (strcmp(link_name, lnk->name) == 0)
return lnk;
}
return NULL;
}
static char *get_tuple_pvalue(list_t *tuple_l, int lex)
{
struct tuple *t;
@ -2057,8 +1992,8 @@ void adm_bip_help(struct link_client *ic, int admin, const char *subhelp)
bip_notify(ic, "/BIP LIST networks|connections");
}
bip_notify(ic,
"/BIP JUMP [-f] [conn_name] # jump to next "
"server (defaults to current network)");
"/BIP JUMP # jump to next server (in same "
"network)");
bip_notify(ic,
"/BIP BLRESET [channel|query]# reset backlog "
"(this connection only). Add -q flag and the "
@ -2111,14 +2046,8 @@ void adm_bip_help(struct link_client *ic, int admin, const char *subhelp)
" Removing a connection will cause "
"its disconnection.");
} else if (strcasecmp(subhelp, "JUMP") == 0) {
bip_notify(ic, "/BIP JUMP [-f] [conn_name]:");
bip_notify(ic, "/BIP JUMP :");
bip_notify(ic, " Jump to next server in current network.");
bip_notify(ic,
" If [conn_name] is set, jump to next server in "
"[conn_name] network instead.");
bip_notify(ic,
" If [-f] flag is used, also resets reconnect "
"timer.");
} else if (strcasecmp(subhelp, "BLRESET") == 0) {
bip_notify(ic, "/BIP BLRESET :");
bip_notify(ic, " Reset backlog on this network.");
@ -2298,16 +2227,12 @@ int adm_bip(bip_t *bip, struct link_client *ic, struct line *line, int privmsg)
bip_notify(ic, "-- Invalid INFO request");
}
} else if (irc_line_elem_case_equals(line, privmsg + 1, "JUMP")) {
if (irc_line_count(line) == privmsg + 2) {
adm_bip_jump(ic, NULL, 0);
} else if (irc_line_count(line) == privmsg + 3) {
adm_bip_jump(ic, irc_line_elem(line, privmsg + 2), 0);
} else if (irc_line_count(line) == privmsg + 4
&& irc_line_elem_equals(line, privmsg + 2, "-f")) {
adm_bip_jump(ic, irc_line_elem(line, privmsg + 3), 1);
} else {
bip_notify(ic, "-- Invalid usage (/BIP HELP JUMP)");
if (LINK(ic)->l_server) {
WRITE_LINE1(CONN(LINK(ic)->l_server), NULL, "QUIT",
"jumpin' jumpin'");
connection_close(CONN(LINK(ic)->l_server));
}
bip_notify(ic, "-- Jumping to next server");
} else if (irc_line_elem_case_equals(line, privmsg + 1, "BLRESET")) {
if (irc_line_includes(line, privmsg + 2)) {
if (irc_line_elem_equals(line, privmsg + 2, "-q")) {

View File

@ -68,6 +68,7 @@ void rlimit_cpu_reached(int i);
void rlimit_bigfile_reached(int i);
void conf_die(bip_t *bip, char *fmt, ...);
int fireup(bip_t *bip, FILE *conf);
int check_ssl_files(int failmode);
int do_pid_stuff(void);
static void usage(char *name)
@ -143,6 +144,44 @@ static pid_t daemonize(void)
return getpid();
}
int check_ssl_files(int failmode)
{
int e;
struct stat fs;
if (!conf_ssl_certfile) {
conf_ssl_certfile = default_path(
conf_biphome, "bip.pem", "SSL certificate");
}
if (failmode == HARD_FAIL)
assert_path_exists(conf_ssl_certfile);
else if (!check_path_exists(conf_ssl_certfile))
return 0;
e = stat(conf_ssl_certfile, &fs);
if (e)
mylog(LOG_WARN,
"Unable to check PEM file, stat(%s): %s",
conf_ssl_certfile, strerror(errno));
else if ((fs.st_mode & S_IROTH) | (fs.st_mode & S_IWOTH))
mylog(LOG_ERROR,
"PEM file %s should not be world "
"readable / writable. Please fix the modes.",
conf_ssl_certfile);
if (conf_client_dh_file) {
if (failmode == HARD_FAIL) {
assert_path_exists(conf_client_dh_file);
} else if (!check_path_exists(conf_client_dh_file)) {
return 0;
}
}
/* all is well */
return 1;
}
int main(int argc, char **argv)
{
FILE *conf = NULL;
@ -264,31 +303,8 @@ int main(int argc, char **argv)
#ifdef HAVE_LIBSSL
if (conf_css) {
int e;
struct stat fs;
if (!conf_ssl_certfile) {
conf_ssl_certfile = default_path(
conf_biphome, "bip.pem", "SSL certificate");
}
assert_path_exists(conf_ssl_certfile);
e = stat(conf_ssl_certfile, &fs);
if (e)
mylog(LOG_WARN,
"Unable to check PEM file, stat(%s): "
"%s",
conf_ssl_certfile, strerror(errno));
else if ((fs.st_mode & S_IROTH) | (fs.st_mode & S_IWOTH))
mylog(LOG_ERROR,
"PEM file %s should not be world "
"readable / writable. Please fix the modes.",
conf_ssl_certfile);
if (conf_client_dh_file) {
assert_path_exists(conf_client_dh_file);
}
}
check_ssl_files(HARD_FAIL);
}
#endif
check_dir(conf_log_root, 1);
@ -324,6 +340,22 @@ int main(int argc, char **argv)
/* re-open to allow logfile rotate */
log_file_setup();
#ifdef HAVE_LIBSSL
/* reload SSL context if server-side SSL is enabled and SSL files
* seem accessible */
if (conf_css) {
if (check_ssl_files(SOFT_FAIL)) {
if (set_ssl_context(SSLCTX_FORCE_UPDATE) == 1)
mylog(LOG_DEBUG, "SSL context has been updated");
else
mylog(LOG_DEBUG, "SSL context has not been updated");
} else {
mylog(LOG_ERROR, "Unable to update SSL context, "
"file checks failed");
}
}
#endif
}
return 1;
}

View File

@ -34,6 +34,7 @@ extern char *conf_client_ciphers;
extern char *conf_client_dh_file;
static int SSLize(connection_t *cn, int *nc);
static SSL_CTX *SSL_init_context(char *ciphers);
SSL_CTX *get_ssl_context(void);
/* SSH like trust management */
int link_add_untrusted(void *ls, X509 *cert);
#endif
@ -1206,6 +1207,77 @@ static int ctx_set_dh(SSL_CTX *ctx)
return 1;
}
int set_ssl_context(int force)
{
SSL_CTX *newctx = NULL;
if (sslctx) {
if (force == SSLCTX_FORCE_UPDATE) {
mylog(LOG_DEBUG, "SSL context already set, forcing update");
} else {
mylog(LOG_DEBUG, "SSL context is already set, not updating");
return 0;
}
} else {
mylog(LOG_DEBUG, "Initializing SSL context for accepted connections");
}
newctx = get_ssl_context();
if (!newctx) {
mylog(LOG_ERROR, "Failed to get new SSL context");
if (sslctx)
mylog(LOG_WARN, "Keeping old SSL context");
return 0;
}
sslctx = newctx;
return 1;
}
SSL_CTX *get_ssl_context(void)
{
SSL_CTX *newctx = NULL;
if (!(newctx = SSL_init_context(conf_client_ciphers))) {
mylog(LOG_ERROR, "SSL context initialization failed");
return NULL;
}
if (!conf_client_dh_file) {
// try with a default path but don't fail if it doesn't exist
conf_client_dh_file = default_path(conf_biphome, "dh.pem",
"DH parameters");
struct stat st_buf;
if (stat(conf_client_dh_file, &st_buf) != 0) {
free(conf_client_dh_file);
conf_client_dh_file = NULL;
}
}
if (conf_client_dh_file) {
if (!ctx_set_dh(newctx)) {
SSL_CTX_free(newctx);
mylog(LOG_ERROR, "SSL Unable to load DH parameters");
return NULL;
}
}
mylog(LOG_DEBUG, "Loading SSL cert from %s", conf_ssl_certfile);
if (!SSL_CTX_use_certificate_chain_file(newctx, conf_ssl_certfile)) {
mylog(LOG_WARN, "SSL: Unable to load certificate file");
SSL_CTX_free(newctx);
return NULL;
}
mylog(LOG_DEBUG, "Loading SSL key from %s", conf_ssl_certfile);
if (!SSL_CTX_use_PrivateKey_file(newctx, conf_ssl_certfile,
SSL_FILETYPE_PEM)) {
mylog(LOG_WARN, "SSL: Unable to load key file");
SSL_CTX_free(newctx);
return NULL;
}
return newctx;
}
#endif
connection_t *accept_new(connection_t *cn)
@ -1241,52 +1313,11 @@ connection_t *accept_new(connection_t *cn)
conn->client = 1;
#ifdef HAVE_LIBSSL
if (cn->ssl) {
if (!sslctx)
set_ssl_context(SSLCTX_NO_REPLACE);
if (!sslctx) {
mylog(LOG_DEBUG,
"No SSL context available for "
"accepted connections. "
"Initializing...");
if (!(sslctx = SSL_init_context(conf_client_ciphers))) {
mylog(LOG_ERROR,
"SSL context initialization "
"failed");
connection_free(conn);
return NULL;
}
if (!conf_client_dh_file) {
// try with a default path but don't fail if it
// doesn't exist
conf_client_dh_file =
default_path(conf_biphome, "dh.pem",
"DH parameters");
struct stat st_buf;
if (stat(conf_client_dh_file, &st_buf) != 0) {
free(conf_client_dh_file);
conf_client_dh_file = NULL;
}
}
if (conf_client_dh_file) {
if (!ctx_set_dh(sslctx)) {
mylog(LOG_ERROR,
"SSL Unable to load DH "
"parameters");
connection_free(conn);
return NULL;
}
}
if (!SSL_CTX_use_certificate_chain_file(
sslctx, conf_ssl_certfile))
mylog(LOG_WARN,
"SSL: Unable to load "
"certificate file");
if (!SSL_CTX_use_PrivateKey_file(sslctx,
conf_ssl_certfile,
SSL_FILETYPE_PEM))
mylog(LOG_WARN, "SSL: Unable to load key file");
connection_free(conn);
return NULL;
}
conn->ssl_h = SSL_new(sslctx);

View File

@ -60,6 +60,9 @@
#define SSL_CHECK_NONE (0)
#define SSL_CHECK_BASIC (1)
#define SSL_CHECK_CA (2)
#define SSLCTX_NO_REPLACE 0
#define SSLCTX_FORCE_UPDATE 1
#endif
struct connecting_data;
@ -113,4 +116,9 @@ uint16_t connection_localport(connection_t *cn);
uint16_t connection_remoteport(connection_t *cn);
char *connection_localip(connection_t *cn);
char *connection_remoteip(connection_t *cn);
#ifdef HAVE_LIBSSL
/* Set SSL context, force update if already set and force is 1
* Return 1 if SSL context has been set */
int set_ssl_context(int force);
#endif
#endif

View File

@ -19,7 +19,7 @@
#define DEFAULT_BACKLOG 1
#define DEFAULT_ALWAYS_BACKLOG 0
#define DEFAULT_BL_MSG_ONLY 0
#define DEFAULT_BACKLOG_LINES 0
#define DEFAULT_BACKLOG_LINES 10
#define DEFAULT_BACKLOG_TIMESTAMP BLTSTime
#define DEFAULT_BLRESET_ON_TALK 0
#define DEFAULT_BLRESET_CONNECTION 0
@ -29,6 +29,6 @@
#define DEFAULT_LOG_LEVEL LOG_INFO
#define DEFAULT_LOG_FORMAT "%u/%n/%Y-%m/%c.%d.log"
#define DEFAULT_BIP_USE_NOTICE 0
#define DEFAULT_RECONN_TIMER 30
#define DEFAULT_RECONN_TIMER 120
#endif /* DEFAULTS_H */

View File

@ -33,7 +33,6 @@
extern int sighup;
extern bip_t *_bip;
static int irc_generic_error(struct link_server *server, struct line *line);
static int irc_join(struct link_server *server, struct line *line);
static int irc_part(struct link_server *server, struct line *line);
static int irc_mode(struct link_server *server, struct line *line);
@ -626,10 +625,6 @@ int irc_dispatch_server(bip_t *bip, struct link_server *server,
ret = irc_quit(server, line);
} else if (irc_line_elem_equals(line, 0, "NICK")) {
ret = irc_nick(server, line);
} else if (irc_line_is_error(line)) {
// IRC errors catchall (for unhandled ones)
// logs error to bip.log
ret = irc_generic_error(server, line);
}
if (ret == OK_COPY) {
@ -1453,17 +1448,6 @@ static int origin_is_me(struct line *l, struct link_server *server)
return 0;
}
static int irc_generic_error(struct link_server *server, struct line *line)
{
if (irc_line_count(line) == 4)
mylog(LOG_INFO, "[%s] IRC error: %s", LINK(server)->name,
irc_line_elem(line, 3));
else
mylog(LOG_INFO, "[%s] IRC error: %s", LINK(server)->name,
irc_line_to_string(line));
return OK_COPY;
}
static int irc_join(struct link_server *server, struct line *line)
{
char *s_nick;

View File

@ -143,12 +143,6 @@ void irc_line_drop(struct line *line, int elem)
bip_cfree(array_drop(&line->words, elem));
}
int irc_line_is_error(struct line *line)
{
const char *irc_code = irc_line_elem(line, 0);
return (irc_code[0] == '4');
}
int irc_line_elem_equals(struct line *line, int elem, const char *cmp)
{
return !strcmp(irc_line_elem(line, elem), cmp);

View File

@ -98,7 +98,6 @@ int irc_line_includes(struct line *line, int elem);
const char *irc_line_elem(struct line *line, int elem);
int irc_line_count(struct line *line);
char *irc_line_pop(struct line *l);
int irc_line_is_error(struct line *line);
int irc_line_elem_equals(struct line *line, int elem, const char *cmp);
int irc_line_elem_case_equals(struct line *line, int elem, const char *cmp);
void irc_line_drop(struct line *line, int elem);

View File

@ -35,3 +35,15 @@ void assert_path_exists(char *path)
if (stat(path, &st_buf) != 0)
fatal("Path %s doesn't exist (%s)", path, strerror(errno));
}
int check_path_exists(char *path)
{
struct stat st_buf;
if (stat(path, &st_buf) != 0) {
mylog(LOG_WARN, "Path %s doesn't exist (%s)", path, strerror(errno));
return 0;
} else {
return 1;
}
}

View File

@ -18,5 +18,7 @@
char *default_path(const char *biphome, const char *filename, const char *desc);
/* exit program if path doesn't exist */
void assert_path_exists(char *path);
/* return 1 if path exists, 0 otherwise */
int check_path_exists(char *path);
#endif