res_pjsip: Add existence and readablity checks for tls related files

Both transport and endpoint now check for the existence and readability
of tls certificate and key files before passing them on to pjproject.
This will cause the object to not load rather than waiting for pjproject
to discover that there's a problem when a session is attempted.

NOTE: chan_sip also uses ast_rtp_dtls_cfg_parse but it's located
in build_peer which is gigantic and I didn't want to disturb it.
Error messages will emit but it won't interrupt chan_sip loading.

ASTERISK-25618 #close

Change-Id: Ie43f2c1d653ac1fda6a6f6faecb7c2ebadaf47c9
Reported-by: George Joseph
Tested-by: George Joseph
changes/89/1789/1
George Joseph 10 years ago
parent 4cf470c70a
commit a987434564

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

@ -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")) {

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

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

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

Loading…
Cancel
Save