Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sip module - get sip password from external url #3480

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions conf/janus.plugin.sip.jcfg.sample
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,9 @@ general: {
# engine (default 32000 milliseconds)
sip_timer_t1x64 = 32000

# Set password retrieval on private url from web_session_id (Avoiding to expose reusable sip credentials)
# if web_session_id is defined, the sip password will be retrieved at $sip_passwd_url/$web_session_id
get_sip_passwd_from_url = false
#sip_passwd_url = "https://mydomain.com"

}
136 changes: 129 additions & 7 deletions src/plugins/janus_sip.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@
"username" : "<SIP URI to register; mandatory>",
"secret" : "<password to use to register; optional>",
"ha1_secret" : "<prehashed password to use to register; optional>",
"web_session_id" : "<unique ID of the web session that is registering (used for password retrieval in method get_sip_passwd_from_url); optional>",
"authuser" : "<username to use to authenticate (overrides the one in the SIP URI); optional>",
"display_name" : "<display name to use when sending SIP REGISTER; optional>",
"user_agent" : "<user agent to use when sending SIP REGISTER; optional>",
Expand Down Expand Up @@ -195,6 +196,7 @@
"secret" : "<password to use to call, only needed in case authentication is needed and no REGISTER was sent; optional>",
"ha1_secret" : "<prehashed password to use to call, only needed in case authentication is needed and no REGISTER was sent; optional>",
"authuser" : "<username to use to authenticate as to call, only needed in case authentication is needed and no REGISTER was sent; optional>",
"web_session_id" : "<unique ID of the web session that is calling (used for password retrieval in method get_sip_passwd_from_url); optional>",
"autoaccept_reinvites" : <true|false, whether we should blindly accept re-INVITEs with a 200 OK instead of relaying the SDP to the application; optional, TRUE by default>
}
\endverbatim
Expand Down Expand Up @@ -687,6 +689,7 @@

#include <arpa/inet.h>
#include <net/if.h>
#include <curl/curl.h>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

libcurl is an optional dependency in Janus. A few plugins can use it, but always in an optional way. Please see how the Streaming plugin only conditionally uses it, for instance (in that case for RTSP support). I'm not going to make it a mandatory requirement just for this. Of course, this means that all references and usages of this functionality will need to be made conditional as well (including error messages when trying to use them when curl isn't available).


#include <jansson.h>

Expand Down Expand Up @@ -789,6 +792,7 @@ static struct janus_json_parameter register_parameters[] = {
{"username", JSON_STRING, JANUS_JSON_PARAM_REQUIRED},
{"secret", JSON_STRING, 0},
{"ha1_secret", JSON_STRING, 0},
{"web_session_id", JSON_STRING, 0},
{"authuser", JSON_STRING, 0},
{"display_name", JSON_STRING, 0},
{"user_agent", JSON_STRING, 0},
Expand Down Expand Up @@ -823,6 +827,7 @@ static struct janus_json_parameter call_parameters[] = {
* still need an authenticated INVITE for some reason */
{"secret", JSON_STRING, 0},
{"ha1_secret", JSON_STRING, 0},
{"web_session_id", JSON_STRING, 0},
{"authuser", JSON_STRING, 0}
};
static struct janus_json_parameter accept_parameters[] = {
Expand Down Expand Up @@ -873,6 +878,10 @@ static struct janus_json_parameter sipmessage_parameters[] = {
{"headers", JSON_OBJECT, 0},
{"call_id", JANUS_JSON_STRING, 0}
};
struct curl_response_buffer {
char *response;
size_t size;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

General note: it looks like a lot of your code uses spaces for indentation. Please use tabs everywhere (here and in all your other changes), since that's the project code style.

};

/* Useful stuff */
static volatile gint initialized = 0, stopping = 0;
Expand All @@ -884,6 +893,10 @@ static char *local_ip = NULL, *sdp_ip = NULL, *local_media_ip = NULL;
static janus_network_address janus_network_local_media_ip = { 0 };
static int keepalive_interval = 120;
static gboolean behind_nat = FALSE;

static gboolean get_sip_passwd_from_url = FALSE;
static char *sip_passwd_url = NULL;

static char *user_agent;
#define JANUS_DEFAULT_REGISTER_TTL 3600
static int register_ttl = JANUS_DEFAULT_REGISTER_TTL;
Expand Down Expand Up @@ -2048,6 +2061,14 @@ int janus_sip_init(janus_callbacks *callback, const char *config_path) {
user_agent = g_strdup("Janus WebRTC Server SIP Plugin "JANUS_SIP_VERSION_STRING);
JANUS_LOG(LOG_VERB, "SIP User-Agent set to %s\n", user_agent);

item = janus_config_get(config, config_general, janus_config_type_item, "get_sip_passwd_from_url");
if(item && item->value)
get_sip_passwd_from_url = janus_is_true(item->value);

item = janus_config_get(config, config_general, janus_config_type_item, "sip_passwd_url");
if(item && item->value)
sip_passwd_url = g_strdup(item->value);

item = janus_config_get(config, config_general, janus_config_type_item, "rtp_port_range");
if(item && item->value) {
/* Split in min and max port */
Expand Down Expand Up @@ -2203,6 +2224,14 @@ int janus_sip_init(janus_callbacks *callback, const char *config_path) {
}
JANUS_LOG(LOG_INFO, "%s initialized!\n", JANUS_SIP_NAME);
return 0;

/* Setup libcurl */
CURLcode curl_init = curl_global_init(CURL_GLOBAL_DEFAULT);
if(curl_init != CURLE_OK) {
JANUS_LOG(LOG_ERR, "libcurl setup failed: %s\n", curl_easy_strerror(curl_init));
return -1;
}

}

void janus_sip_destroy(void) {
Expand Down Expand Up @@ -2235,6 +2264,9 @@ void janus_sip_destroy(void) {
g_atomic_int_set(&initialized, 0);
g_atomic_int_set(&stopping, 0);

/* Deinitialize libcurl */
curl_global_cleanup();

/* Deinitialize sofia */
su_deinit();

Expand Down Expand Up @@ -2888,6 +2920,23 @@ static void janus_sip_hangup_media_internal(janus_plugin_session *handle) {
g_atomic_int_set(&session->hangingup, 0);
}

/* Function called by libcurl to write the data received */
static size_t curl_write_cb(void *data, size_t size, size_t nmemb, void *userp) {
size_t total_size = size * nmemb;
struct curl_response_buffer *mem = (struct curl_response_buffer *)userp;

char *ptr = realloc(mem->response, mem->size + total_size + 1);
if(ptr == NULL)
return 0;

mem->response = ptr;
memcpy(&(mem->response[mem->size]), data, total_size);
mem->size += total_size;
mem->response[mem->size] = '\0';

return total_size;
}

/* Thread to handle incoming messages */
static void *janus_sip_handler(void *data) {
JANUS_LOG(LOG_VERB, "Joining SIP handler thread\n");
Expand Down Expand Up @@ -3194,26 +3243,99 @@ static void *janus_sip_handler(void *data) {
} else {
json_t *secret = json_object_get(root, "secret");
json_t *ha1_secret = json_object_get(root, "ha1_secret");
json_t *web_session_id = json_object_get(root, "web_session_id");
json_t *authuser = json_object_get(root, "authuser");
if(!secret && !ha1_secret) {
JANUS_LOG(LOG_ERR, "Missing element (secret or ha1_secret)\n");

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this unneeded empty line.

if(!secret && !ha1_secret && (!get_sip_passwd_from_url || !web_session_id)) {
JANUS_LOG(LOG_ERR, "Missing element (secret or ha1_secret, or web_session_id (in get_sip_passwd_from_url mode) )\n");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's an extra bracket in web_session_id (in... that's not needed.

error_code = JANUS_SIP_ERROR_MISSING_ELEMENT;
g_snprintf(error_cause, 512, "Missing element (secret or ha1_secret)");
g_snprintf(error_cause, 512, "Missing element (secret or ha1_secret or web_session_id)");
goto error;
}
if(secret && ha1_secret) {
JANUS_LOG(LOG_ERR, "Conflicting elements specified (secret and ha1_secret)\n");
if( (secret && ha1_secret) || (secret && web_session_id) || (ha1_secret && web_session_id)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't add spaces in checks like if( ( (code style).

JANUS_LOG(LOG_ERR, "Conflicting elements specified at least both of (secret / ha1_secret / web_session_id)\n");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd remove the "at least both of" where you added it (it's confusing, at least to me).

error_code = JANUS_SIP_ERROR_INVALID_ELEMENT;
g_snprintf(error_cause, 512, "Conflicting elements specified (secret and ha1_secret)");
g_snprintf(error_cause, 512, "Conflicting elements specified at least both of (secret / ha1_secret / web_session_id )");
goto error;
}
if(secret) {
secret_text = json_string_value(secret);
secret_type = janus_sip_secret_type_plaintext;
} else {
} else if(ha1_secret) {
secret_text = json_string_value(ha1_secret);
secret_type = janus_sip_secret_type_hashed;
} else if(web_session_id) {
if(get_sip_passwd_from_url && sip_passwd_url) {
const char *web_session_id_str = json_string_value(web_session_id);
if(web_session_id_str == NULL) {
JANUS_LOG(LOG_ERR, "Invalid web_session_id (not a string)\n");
error_code = JANUS_SIP_ERROR_INVALID_ELEMENT;
g_snprintf(error_cause, 512, "Invalid web_session_id (not a string)");
goto error;
}

/* Build the URL */
size_t url_len = strlen(sip_passwd_url) + 1 + strlen(web_session_id_str) + 1;
char *url = malloc(url_len);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use the glib alloc helpers, not malloc directly, as we do in the rest of the code. This also means you'll need to use g_free and not free.

if(url == NULL) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This whole check is unneeded: we don't do memory checks like this because, once they occur, the server will crash anyway.

JANUS_LOG(LOG_ERR, "Out of memory while constructing URL\n");
error_code = JANUS_SIP_ERROR_UNKNOWN_ERROR;
g_snprintf(error_cause, 512, "Out of memory");
goto error;
}
snprintf(url, url_len, "%s/%s", sip_passwd_url, web_session_id_str);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, please use glib utilities like we do in other parts of the code: this should be g_snprintf.


/* Initialize libcurl */
CURL *curl_handle = curl_easy_init();
if(!curl_handle) {
JANUS_LOG(LOG_ERR, "Failed to initialize libcurl\n");
free(url);
error_code = JANUS_SIP_ERROR_UNKNOWN_ERROR;
g_snprintf(error_cause, 512, "Failed to initialize libcurl");
goto error;
}

/* Initialize the memory chunk */
struct curl_response_buffer chunk = {0};
curl_easy_setopt(curl_handle, CURLOPT_URL, url);
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, curl_write_cb);
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "Janus SIP Plugin/0.0.9");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't hardcode this, since we have defines like JANUS_SIP_VERSION_STRING and JANUS_SIP_NAME.

curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is missing properties like CURLOPT_TIMEOUT and CURLOPT_CONNECTTIMEOUT. Considering this is a blocking wait, this could end up waiting forever. You can refer to some properties we add in the Streaming plugin for RTSP (e.g., CURLOPT_NOSIGNAL or CURLOPT_NOPROGRESS).


/* Perform the request */
CURLcode res = curl_easy_perform(curl_handle);
if(res != CURLE_OK) {
JANUS_LOG(LOG_ERR, "libcurl error: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl_handle);
free(url);
if(chunk.response)
free(chunk.response);
error_code = JANUS_SIP_ERROR_IO_ERROR;
g_snprintf(error_cause, 512, "Failed to retrieve secret from private URL: %s", curl_easy_strerror(res));
goto error;
}

/* Cleanup */
curl_easy_cleanup(curl_handle);
free(url);

if(chunk.response) {
secret_text = g_strdup(chunk.response);
free(chunk.response);
secret_type = janus_sip_secret_type_plaintext;
} else {
JANUS_LOG(LOG_ERR, "Empty response from private URL\n");
error_code = JANUS_SIP_ERROR_INVALID_ELEMENT;
g_snprintf(error_cause, 512, "Empty response from private URL");
goto error;
}
} else {
secret_text = json_string_value(web_session_id);
secret_type = janus_sip_secret_type_plaintext;
}
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're adding a lot of empty lines, in the previous block too. Please don't do that.

if(authuser) {
authuser_text = json_string_value(authuser);
}
Expand Down
Loading