forked from bip/bip
1
0
Fork 0

Compare commits

...

6 Commits

Author SHA1 Message Date
Loïc Gomez 40ac98214a
Add missing defines for SOFT_FAIL/HARD_FAIL in util.h
This is for these previous 2 commits:
  * 428c1b6 Allow checking ssl files are readable (check_ssl_files)
  * a03b123 Also reload SSL context on bip reload, allowing for SSL cert updates
2024-03-20 23:27:33 +09:00
Loïc Gomez a03b12319a
Also reload SSL context on bip reload, allowing for SSL cert updates
- on BIP reload, check if SSL files are readable, and try to load new
  SSL context.
- on success only, update SSL context for new client connections

This allows for SSL certificate/key updates on /BIP reload or SIGHUP.

Signed-off-by: Loïc Gomez <bip@animanova.fr>
2024-03-20 22:42:01 +09:00
Loïc Gomez 428c1b6173
Allow checking ssl files are readable (check_ssl_files)
- adds a new check_path_exists() method to path_util
- move code checking if SSL-related files exist with assertions (thus
  causing a fatal error) to a new check_ssl_files() method, allowing for
  soft or hard fail modes

This will allow for non-fatal checks of SSL files existence on reload.

Signed-off-by: Loïc Gomez <bip@animanova.fr>
2024-03-20 22:33:31 +09:00
Loïc Gomez f2443aaf23
Move SSL context code to get/set_ssl_context methods
- Move code setting up SSL context from accept_new() to new
  get/set_ssl_context() methods
- set_ssl_context() will allow setting context only if not already set,
  or force re-setting context even if already present
- set_ssl_context() will return 1 if SSL context has been set
- if getting the new SSL context fails, set_ssl_context() will not break
  current SSL context

This is preparatory work for reloading SSL certificates/key on BIP
reload.

Signed-off-by: Loïc Gomez <bip@animanova.fr>
2024-03-20 22:29:05 +09:00
Loïc Gomez 400b0d66de
Fix deprecation notices for OpenSSL 3 and failure to build on GCC12
Tested with libssl 3.0.10-1ubuntu2.1 (Ubuntu 23.10) and 1.1.1f-1ubuntu2.20
(Ubuntu 20.04).

Signed-off-by: Loïc Gomez <bip@animanova.fr>
2024-03-20 22:27:20 +09:00
Loïc Gomez e643cd4944
Fix endless loop on /BIP LIST connections with long on_connect_send
- when the line to send to IRC was over a specific limit, the code was
  not moving to the next item in the on_connect_send list after sending
  the text to the client
- this change also adds a hard limit of 10 on_connect_send to display
  for each connection

Signed-off-by: Loïc Gomez <bip@animanova.fr>
2024-03-20 22:19:28 +09:00
7 changed files with 189 additions and 72 deletions

View File

@ -1396,9 +1396,10 @@ void adm_print_connection(struct link_client *ic, struct link *lnk,
bufpos = buf;
list_iterator_t itocs;
int i = 0;
for (list_it_init(&lnk->on_connect_send, &itocs);
list_it_item(&itocs);) {
bufpos = bip_strcatf_fit(&remaining, bufpos, "%s",
list_it_item(&itocs) && i < 10; i++) {
bufpos = bip_strcatf_fit(&remaining, bufpos, " on_connect_send: %s",
(char *)list_it_item(&itocs));
if (!bufpos) {
// if oversized, print and reset
@ -1406,6 +1407,7 @@ void adm_print_connection(struct link_client *ic, struct link *lnk,
bip_notify(ic, "%s", buf);
remaining = LINE_SIZE_LIM;
bufpos = buf;
list_it_next(&itocs);
continue;
} else {
// if ok, go to next item

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,24 @@ 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
@ -1171,6 +1172,7 @@ static connection_t *connection_init(int anti_flood, int ssl, time_t timeout,
static int ctx_set_dh(SSL_CTX *ctx)
{
/* Return ephemeral DH parameters. */
#if OPENSSL_VERSION_NUMBER < 0x30000000L /* 3.0.0 */
DH *dh = NULL;
FILE *f;
long ret;
@ -1203,9 +1205,104 @@ static int ctx_set_dh(SSL_CTX *ctx)
ERR_error_string(ERR_get_error(), NULL));
return 0;
}
#else
BIO *pbio = BIO_new_file(conf_client_dh_file, "r");
if (!pbio) {
mylog(LOG_ERROR, "Unable to open DH parameters, BIO_new_file(%s): %s",
conf_client_dh_file, ERR_error_string(ERR_get_error(), NULL));
return 0;
}
EVP_PKEY *param = PEM_read_bio_Parameters(pbio, NULL);
BIO_free(pbio);
if (!param) {
mylog(LOG_ERROR, "TLS DH Error: PEM_read_bio_Parameters(%s): %s",
conf_client_dh_file, ERR_error_string(ERR_get_error(), NULL));
return 0;
}
if (SSL_CTX_set0_tmp_dh_pkey(ctx, param) != 1) {
EVP_PKEY_free(param);
mylog(LOG_ERROR, "TLS DH Error: SSL_CTX_set0_tmp_dh_pkey(%s): %s",
conf_client_dh_file, ERR_error_string(ERR_get_error(), NULL));
return 0;
}
#endif
mylog(LOG_DEBUG, "TLS: succesfully set up DH params %s",
conf_client_dh_file);
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 +1338,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

@ -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

View File

@ -31,6 +31,9 @@
#define HASH_NOCASE 1
#define HASH_DEFAULT 0
#define SOFT_FAIL 0
#define HARD_FAIL 1
void mylog(int level, char *fmt, ...);
void _mylog(int level, char *fmt, va_list ap);
void fatal(char *fmt, ...);