diff --git a/include/asterisk/utils.h b/include/asterisk/utils.h index 664e347cf2657284411be26b7a3916c6f9c216c1..832500c31e7bd423d3aa8526e3b0d87a4f49b4b2 100644 --- a/include/asterisk/utils.h +++ b/include/asterisk/utils.h @@ -1089,4 +1089,14 @@ char *ast_crypt_encrypt(const char *key); */ int ast_crypt_validate(const char *key, const char *expected); +/* + * \brief Test that a file exists and is readable by the effective user. + * \since 13.7.0 + * + * \param filename File to test. + * \return True (non-zero) if the file exists and is readable. + * \return False (zero) if the file either doesn't exists or is not readable. + */ +int ast_file_is_readable(const char *filename); + #endif /* _ASTERISK_UTILS_H */ diff --git a/main/rtp_engine.c b/main/rtp_engine.c index 32909090f6672d0a39c8aa307d0351ac504e225b..24e56b49fb188fee9b10cc8c00f657aaf607612e 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -2118,18 +2118,34 @@ int ast_rtp_dtls_cfg_parse(struct ast_rtp_dtls_cfg *dtls_cfg, const char *name, } } else if (!strcasecmp(name, "dtlscertfile")) { ast_free(dtls_cfg->certfile); + if (!ast_file_is_readable(value)) { + ast_log(LOG_ERROR, "%s file %s does not exist or is not readable\n", name, value); + return -1; + } dtls_cfg->certfile = ast_strdup(value); } else if (!strcasecmp(name, "dtlsprivatekey")) { ast_free(dtls_cfg->pvtfile); + if (!ast_file_is_readable(value)) { + ast_log(LOG_ERROR, "%s file %s does not exist or is not readable\n", name, value); + return -1; + } dtls_cfg->pvtfile = ast_strdup(value); } else if (!strcasecmp(name, "dtlscipher")) { ast_free(dtls_cfg->cipher); dtls_cfg->cipher = ast_strdup(value); } else if (!strcasecmp(name, "dtlscafile")) { ast_free(dtls_cfg->cafile); + if (!ast_file_is_readable(value)) { + ast_log(LOG_ERROR, "%s file %s does not exist or is not readable\n", name, value); + return -1; + } dtls_cfg->cafile = ast_strdup(value); } else if (!strcasecmp(name, "dtlscapath") || !strcasecmp(name, "dtlscadir")) { ast_free(dtls_cfg->capath); + if (!ast_file_is_readable(value)) { + ast_log(LOG_ERROR, "%s file %s does not exist or is not readable\n", name, value); + return -1; + } dtls_cfg->capath = ast_strdup(value); } else if (!strcasecmp(name, "dtlssetup")) { if (!strcasecmp(value, "active")) { diff --git a/main/utils.c b/main/utils.c index ba1a07ca242dac91c26834f509e933f2f46d8428..74932b8c27dca48132a90e4e0ba44b00979e485e 100644 --- a/main/utils.c +++ b/main/utils.c @@ -2927,3 +2927,20 @@ int ast_eid_cmp(const struct ast_eid *eid1, const struct ast_eid *eid2) { return memcmp(eid1, eid2, sizeof(*eid1)); } + +int ast_file_is_readable(const char *filename) +{ +#if defined(HAVE_EACCESS) || defined(HAVE_EUIDACCESS) +#if defined(HAVE_EUIDACCESS) && !defined(HAVE_EACCESS) +#define eaccess euidaccess +#endif + return eaccess(filename, R_OK) == 0; +#else + int fd = open(filename, O_RDONLY | O_NONBLOCK); + if (fd < 0) { + return 0; + } + close(fd); + return 1; +#endif +} diff --git a/res/res_pjsip/config_transport.c b/res/res_pjsip/config_transport.c index e2f0c7f4347cfac0db759005bf25017569904774..d8ece1509441e114a2fa97c8531d885bb6c4ba4c 100644 --- a/res/res_pjsip/config_transport.c +++ b/res/res_pjsip/config_transport.c @@ -27,6 +27,7 @@ #include "asterisk/astobj2.h" #include "asterisk/sorcery.h" #include "asterisk/acl.h" +#include "asterisk/utils.h" #include "include/res_pjsip_private.h" #include "asterisk/http_websocket.h" @@ -224,8 +225,22 @@ static int transport_apply(const struct ast_sorcery *sorcery, void *obj) ast_sorcery_object_get_id(obj)); return -1; } + if (!ast_strlen_zero(transport->ca_list_file)) { + if (!ast_file_is_readable(transport->ca_list_file)) { + ast_log(LOG_ERROR, "Transport: %s: ca_list_file %s is either missing or not readable\n", + ast_sorcery_object_get_id(obj), transport->ca_list_file); + return -1; + } + } transport->tls.ca_list_file = pj_str((char*)transport->ca_list_file); #ifdef HAVE_PJ_SSL_CERT_LOAD_FROM_FILES2 + if (!ast_strlen_zero(transport->ca_list_path)) { + if (!ast_file_is_readable(transport->ca_list_path)) { + ast_log(LOG_ERROR, "Transport: %s: ca_list_path %s is either missing or not readable\n", + ast_sorcery_object_get_id(obj), transport->ca_list_path); + return -1; + } + } transport->tls.ca_list_path = pj_str((char*)transport->ca_list_path); #else if (!ast_strlen_zero(transport->ca_list_path)) { @@ -233,7 +248,21 @@ static int transport_apply(const struct ast_sorcery *sorcery, void *obj) "support the 'ca_list_path' option. Please upgrade to version 2.4 or later.\n"); } #endif + if (!ast_strlen_zero(transport->cert_file)) { + if (!ast_file_is_readable(transport->cert_file)) { + ast_log(LOG_ERROR, "Transport: %s: cert_file %s is either missing or not readable\n", + ast_sorcery_object_get_id(obj), transport->cert_file); + return -1; + } + } transport->tls.cert_file = pj_str((char*)transport->cert_file); + if (!ast_strlen_zero(transport->privkey_file)) { + if (!ast_file_is_readable(transport->privkey_file)) { + ast_log(LOG_ERROR, "Transport: %s: privkey_file %s is either missing or not readable\n", + ast_sorcery_object_get_id(obj), transport->privkey_file); + return -1; + } + } transport->tls.privkey_file = pj_str((char*)transport->privkey_file); transport->tls.password = pj_str((char*)transport->password); set_qos(transport, &transport->tls.qos_params); diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 3bb086945172c52af7b3b4278d07593b6166f16a..72f896ad0c4d1bd2beae19ee3aaf20ec9a788417 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -680,7 +680,7 @@ static int media_encryption_handler(const struct aco_option *opt, struct ast_var endpoint->media.rtp.encryption = AST_SIP_MEDIA_ENCRYPT_SDES; } else if (!strcasecmp("dtls", var->value)) { endpoint->media.rtp.encryption = AST_SIP_MEDIA_ENCRYPT_DTLS; - ast_rtp_dtls_cfg_parse(&endpoint->media.rtp.dtls_cfg, "dtlsenable", "yes"); + return ast_rtp_dtls_cfg_parse(&endpoint->media.rtp.dtls_cfg, "dtlsenable", "yes"); } else { return -1; }