/* linphone Copyright (C) 2012 Belledonne Communications, Grenoble, France This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "sal_impl.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif void sal_enable_log(){ sal_set_log_level(ORTP_MESSAGE); } void sal_disable_log() { sal_set_log_level(ORTP_ERROR); } void sal_set_log_level(OrtpLogLevel level) { belle_sip_log_level belle_sip_level = BELLE_SIP_LOG_MESSAGE; if ((level&ORTP_FATAL) != 0) { belle_sip_level = BELLE_SIP_LOG_FATAL; } if ((level&ORTP_ERROR) != 0) { belle_sip_level = BELLE_SIP_LOG_ERROR; } if ((level&ORTP_WARNING) != 0) { belle_sip_level = BELLE_SIP_LOG_WARNING; } if ((level&ORTP_MESSAGE) != 0) { belle_sip_level = BELLE_SIP_LOG_MESSAGE; } if (((level&ORTP_DEBUG) != 0) || ((level&ORTP_TRACE) != 0)) { belle_sip_level = BELLE_SIP_LOG_DEBUG; } belle_sip_set_log_level(belle_sip_level); } static BctbxLogFunc _belle_sip_log_handler = bctbx_logv_out; void sal_set_log_handler(BctbxLogFunc log_handler) { _belle_sip_log_handler = log_handler; belle_sip_set_log_handler(log_handler); } SalAuthInfo* sal_auth_info_create(belle_sip_auth_event_t* event) { SalAuthInfo* auth_info = sal_auth_info_new(); auth_info->realm = ms_strdup(belle_sip_auth_event_get_realm(event)); auth_info->username = ms_strdup(belle_sip_auth_event_get_username(event)); auth_info->domain = ms_strdup(belle_sip_auth_event_get_domain(event)); auth_info->mode = (SalAuthMode)belle_sip_auth_event_get_mode(event); auth_info->algorithm = ms_strdup(belle_sip_auth_event_get_algorithm(event)); return auth_info; } SalAuthMode sal_auth_info_get_mode(const SalAuthInfo* auth_info) { return auth_info->mode; } belle_sip_signing_key_t *sal_auth_info_get_signing_key(const SalAuthInfo* auth_info) { return auth_info->key; } belle_sip_certificates_chain_t *sal_auth_info_get_certificates_chain(const SalAuthInfo* auth_info) { return auth_info->certificates; } void sal_auth_info_set_mode(SalAuthInfo* auth_info, SalAuthMode mode) { auth_info->mode = mode; } void sal_certificates_chain_delete(belle_sip_certificates_chain_t *chain) { belle_sip_object_unref((belle_sip_object_t *)chain); } void sal_signing_key_delete(belle_sip_signing_key_t *key) { belle_sip_object_unref((belle_sip_object_t *)key); } int sal_auth_compute_ha1(const char* userid,const char* realm,const char* password, char ha1[33]) { return belle_sip_auth_helper_compute_ha1(userid, realm, password, ha1); } int sal_auth_compute_ha1_for_algorithm( const char *userid, const char *realm, const char *password, char *ha1, size_t size, const char *algo ) { return belle_sip_auth_helper_compute_ha1_for_algorithm(userid, realm, password, ha1, size, algo); } SalCustomHeader *sal_custom_header_ref(SalCustomHeader *ch){ if (ch == NULL) return NULL; belle_sip_object_ref(ch); return ch; } void sal_custom_header_unref(SalCustomHeader *ch){ if (ch == NULL) return; belle_sip_object_unref(ch); } SalCustomHeader *sal_custom_header_append(SalCustomHeader *ch, const char *name, const char *value){ belle_sip_message_t *msg=(belle_sip_message_t*)ch; belle_sip_header_t *h; if (msg==NULL){ msg=(belle_sip_message_t*)belle_sip_request_new(); belle_sip_object_ref(msg); } h=belle_sip_header_create(name,value); if (h==NULL){ belle_sip_error("Fail to parse custom header."); return (SalCustomHeader*)msg; } belle_sip_message_add_header(msg,h); return (SalCustomHeader*)msg; } const char *sal_custom_header_find(const SalCustomHeader *ch, const char *name){ if (ch){ belle_sip_header_t *h=belle_sip_message_get_header((belle_sip_message_t*)ch,name); if (h){ return belle_sip_header_get_unparsed_value(h); } } return NULL; } SalCustomHeader *sal_custom_header_remove(SalCustomHeader *ch, const char *name) { belle_sip_message_t *msg=(belle_sip_message_t*)ch; if (msg==NULL) return NULL; belle_sip_message_remove_header(msg, name); return (SalCustomHeader*)msg; } void sal_custom_header_free(SalCustomHeader *ch){ if (ch==NULL) return; belle_sip_object_unref((belle_sip_message_t*)ch); } SalCustomHeader *sal_custom_header_clone(const SalCustomHeader *ch){ if (ch==NULL) return NULL; return (SalCustomHeader*)belle_sip_object_ref((belle_sip_message_t*)ch); } SalCustomSdpAttribute * sal_custom_sdp_attribute_append(SalCustomSdpAttribute *csa, const char *name, const char *value) { belle_sdp_session_description_t *desc = (belle_sdp_session_description_t *)csa; belle_sdp_attribute_t *attr; if (desc == NULL) { desc = (belle_sdp_session_description_t *)belle_sdp_session_description_new(); belle_sip_object_ref(desc); } attr = BELLE_SDP_ATTRIBUTE(belle_sdp_raw_attribute_create(name, value)); if (attr == NULL) { belle_sip_error("Fail to create custom SDP attribute."); return (SalCustomSdpAttribute*)desc; } belle_sdp_session_description_add_attribute(desc, attr); return (SalCustomSdpAttribute *)desc; } const char * sal_custom_sdp_attribute_find(const SalCustomSdpAttribute *csa, const char *name) { if (csa) { return belle_sdp_session_description_get_attribute_value((belle_sdp_session_description_t *)csa, name); } return NULL; } void sal_custom_sdp_attribute_free(SalCustomSdpAttribute *csa) { if (csa == NULL) return; belle_sip_object_unref((belle_sdp_session_description_t *)csa); } SalCustomSdpAttribute * sal_custom_sdp_attribute_clone(const SalCustomSdpAttribute *csa) { if (csa == NULL) return NULL; return (SalCustomSdpAttribute *)belle_sip_object_ref((belle_sdp_session_description_t *)csa); } /** Parse a file containing either a certificate chain order in PEM format or a single DER cert * @param auth_info structure where to store the result of parsing * @param path path to certificate chain file * @param format either PEM or DER */ void sal_certificates_chain_parse_file(SalAuthInfo* auth_info, const char* path, SalCertificateRawFormat format) { auth_info->certificates = (belle_sip_certificates_chain_t*) belle_sip_certificates_chain_parse_file(path, (belle_sip_certificate_raw_format_t)format); if (auth_info->certificates) belle_sip_object_ref((belle_sip_object_t *) auth_info->certificates); } /** * Parse a file containing either a private or public rsa key * @param auth_info structure where to store the result of parsing * @param passwd password (optionnal) */ void sal_signing_key_parse_file(SalAuthInfo* auth_info, const char* path, const char *passwd) { auth_info->key = (belle_sip_signing_key_t *) belle_sip_signing_key_parse_file(path, passwd); if (auth_info->key) belle_sip_object_ref((belle_sip_object_t *) auth_info->key); } /** Parse a buffer containing either a certificate chain order in PEM format or a single DER cert * @param auth_info structure where to store the result of parsing * @param buffer the buffer to parse * @param format either PEM or DER */ void sal_certificates_chain_parse(SalAuthInfo* auth_info, const char* buffer, SalCertificateRawFormat format) { size_t len = buffer != NULL ? strlen(buffer) : 0; auth_info->certificates = (belle_sip_certificates_chain_t*) belle_sip_certificates_chain_parse(buffer, len, (belle_sip_certificate_raw_format_t)format); if (auth_info->certificates) belle_sip_object_ref((belle_sip_object_t *) auth_info->certificates); } /** * Parse a buffer containing either a private or public rsa key * @param auth_info structure where to store the result of parsing * @param passwd password (optionnal) */ void sal_signing_key_parse(SalAuthInfo* auth_info, const char* buffer, const char *passwd) { size_t len = buffer != NULL ? strlen(buffer) : 0; auth_info->key = (belle_sip_signing_key_t *) belle_sip_signing_key_parse(buffer, len, passwd); if (auth_info->key) belle_sip_object_ref((belle_sip_object_t *) auth_info->key); } /** * Parse a directory to get a certificate with the given subject common name * */ void sal_certificates_chain_parse_directory(char **certificate_pem, char **key_pem, char **fingerprint, const char* path, const char *subject, SalCertificateRawFormat format, bool_t generate_certificate, bool_t generate_dtls_fingerprint) { belle_sip_certificates_chain_t *certificate = NULL; belle_sip_signing_key_t *key = NULL; *certificate_pem = NULL; *key_pem = NULL; if (belle_sip_get_certificate_and_pkey_in_dir(path, subject, &certificate, &key, (belle_sip_certificate_raw_format_t)format) == 0) { *certificate_pem = belle_sip_certificates_chain_get_pem(certificate); *key_pem = belle_sip_signing_key_get_pem(key); ms_message("Retrieve certificate with CN=%s successful\n", subject); } else { if (generate_certificate == TRUE) { if ( belle_sip_generate_self_signed_certificate(path, subject, &certificate, &key) == 0) { *certificate_pem = belle_sip_certificates_chain_get_pem(certificate); *key_pem = belle_sip_signing_key_get_pem(key); ms_message("Generate self-signed certificate with CN=%s successful\n", subject); } } } /* generate the fingerprint as described in RFC4572 if needed */ if ((generate_dtls_fingerprint == TRUE) && (fingerprint != NULL)) { if (*fingerprint != NULL) { ms_free(*fingerprint); } *fingerprint = belle_sip_certificates_chain_get_fingerprint(certificate); } /* free key and certificate */ if ( certificate != NULL ) { belle_sip_object_unref(certificate); } if ( key != NULL ) { belle_sip_object_unref(key); } } unsigned char * sal_get_random_bytes(unsigned char *ret, size_t size){ return belle_sip_random_bytes(ret,size); } char *sal_get_random_token(int size){ return belle_sip_random_token(reinterpret_cast(ms_malloc((size_t)size)),(size_t)size); } unsigned int sal_get_random(void){ unsigned int ret=0; belle_sip_random_bytes((unsigned char*)&ret,4); return ret; } unsigned long sal_begin_background_task(const char *name, void (*max_time_reached)(void *), void *data){ return belle_sip_begin_background_task(name, max_time_reached, data); } void sal_end_background_task(unsigned long id){ belle_sip_end_background_task(id); } static belle_sip_header_t * sal_body_handler_find_header(const SalBodyHandler *body_handler, const char *header_name) { belle_sip_body_handler_t *bsbh = BELLE_SIP_BODY_HANDLER(body_handler); const belle_sip_list_t *l = belle_sip_body_handler_get_headers(bsbh); for (; l != NULL; l = l->next) { belle_sip_header_t *header = BELLE_SIP_HEADER(l->data); if (strcmp(belle_sip_header_get_name(header), header_name) == 0) { return header; } } return NULL; } SalBodyHandler * sal_body_handler_new(void) { belle_sip_memory_body_handler_t *body_handler = belle_sip_memory_body_handler_new(NULL, NULL); return (SalBodyHandler *)BELLE_SIP_BODY_HANDLER(body_handler); } SalBodyHandler * sal_body_handler_ref(SalBodyHandler *body_handler) { return (SalBodyHandler *)belle_sip_object_ref(BELLE_SIP_OBJECT(body_handler)); } void sal_body_handler_unref(SalBodyHandler *body_handler) { belle_sip_object_unref(BELLE_SIP_OBJECT(body_handler)); } const char * sal_body_handler_get_type(const SalBodyHandler *body_handler) { belle_sip_header_content_type_t *content_type = BELLE_SIP_HEADER_CONTENT_TYPE(sal_body_handler_find_header(body_handler, "Content-Type")); if (content_type != NULL) { return belle_sip_header_content_type_get_type(content_type); } return NULL; } void sal_body_handler_set_type(SalBodyHandler *body_handler, const char *type) { belle_sip_header_content_type_t *content_type = BELLE_SIP_HEADER_CONTENT_TYPE(sal_body_handler_find_header(body_handler, "Content-Type")); if (content_type == NULL) { content_type = belle_sip_header_content_type_new(); belle_sip_body_handler_add_header(BELLE_SIP_BODY_HANDLER(body_handler), BELLE_SIP_HEADER(content_type)); } belle_sip_header_content_type_set_type(content_type, type); } const char * sal_body_handler_get_subtype(const SalBodyHandler *body_handler) { belle_sip_header_content_type_t *content_type = BELLE_SIP_HEADER_CONTENT_TYPE(sal_body_handler_find_header(body_handler, "Content-Type")); if (content_type != NULL) { return belle_sip_header_content_type_get_subtype(content_type); } return NULL; } void sal_body_handler_set_subtype(SalBodyHandler *body_handler, const char *subtype) { belle_sip_header_content_type_t *content_type = BELLE_SIP_HEADER_CONTENT_TYPE(sal_body_handler_find_header(body_handler, "Content-Type")); if (content_type == NULL) { content_type = belle_sip_header_content_type_new(); belle_sip_body_handler_add_header(BELLE_SIP_BODY_HANDLER(body_handler), BELLE_SIP_HEADER(content_type)); } belle_sip_header_content_type_set_subtype(content_type, subtype); } const belle_sip_list_t * sal_body_handler_get_content_type_parameters_names(const SalBodyHandler *body_handler) { belle_sip_header_content_type_t *content_type = BELLE_SIP_HEADER_CONTENT_TYPE(sal_body_handler_find_header(body_handler, "Content-Type")); if (content_type != NULL) { return belle_sip_parameters_get_parameter_names(BELLE_SIP_PARAMETERS(content_type)); } return NULL; } const char * sal_body_handler_get_content_type_parameter(const SalBodyHandler *body_handler, const char *name) { belle_sip_header_content_type_t *content_type = BELLE_SIP_HEADER_CONTENT_TYPE(sal_body_handler_find_header(body_handler, "Content-Type")); if (content_type != NULL) { return belle_sip_parameters_get_parameter(BELLE_SIP_PARAMETERS(content_type), name); } return NULL; } void sal_body_handler_set_content_type_parameter(SalBodyHandler *body_handler, const char *paramName, const char *paramValue) { belle_sip_header_content_type_t *content_type = BELLE_SIP_HEADER_CONTENT_TYPE(sal_body_handler_find_header(body_handler, "Content-Type")); if (content_type != NULL) { belle_sip_parameters_set_parameter(BELLE_SIP_PARAMETERS(content_type), paramName, paramValue); } } const char * sal_body_handler_get_encoding(const SalBodyHandler *body_handler) { belle_sip_header_t *content_encoding = sal_body_handler_find_header(body_handler, "Content-Encoding"); if (content_encoding != NULL) { return belle_sip_header_get_unparsed_value(content_encoding); } return NULL; } void sal_body_handler_set_encoding(SalBodyHandler *body_handler, const char *encoding) { belle_sip_header_t *content_encoding = sal_body_handler_find_header(body_handler, "Content-Encoding"); if (content_encoding != NULL) { belle_sip_body_handler_remove_header_from_ptr(BELLE_SIP_BODY_HANDLER(body_handler), content_encoding); } belle_sip_body_handler_add_header(BELLE_SIP_BODY_HANDLER(body_handler), belle_sip_header_create("Content-Encoding", encoding)); } void * sal_body_handler_get_data(const SalBodyHandler *body_handler) { return belle_sip_memory_body_handler_get_buffer(BELLE_SIP_MEMORY_BODY_HANDLER(body_handler)); } void sal_body_handler_set_data(SalBodyHandler *body_handler, void *data) { belle_sip_memory_body_handler_set_buffer(BELLE_SIP_MEMORY_BODY_HANDLER(body_handler), data); } size_t sal_body_handler_get_size(const SalBodyHandler *body_handler) { return belle_sip_body_handler_get_size(BELLE_SIP_BODY_HANDLER(body_handler)); } void sal_body_handler_set_size(SalBodyHandler *body_handler, size_t size) { belle_sip_header_content_length_t *content_length = BELLE_SIP_HEADER_CONTENT_LENGTH(sal_body_handler_find_header(body_handler, "Content-Length")); if (content_length == NULL) { content_length = belle_sip_header_content_length_new(); belle_sip_body_handler_add_header(BELLE_SIP_BODY_HANDLER(body_handler), BELLE_SIP_HEADER(content_length)); } belle_sip_header_content_length_set_content_length(content_length, size); belle_sip_body_handler_set_size(BELLE_SIP_BODY_HANDLER(body_handler), size); } bool_t sal_body_handler_is_multipart(const SalBodyHandler *body_handler) { if (BELLE_SIP_IS_INSTANCE_OF(body_handler, belle_sip_multipart_body_handler_t)) return TRUE; return FALSE; } SalBodyHandler * sal_body_handler_get_part(const SalBodyHandler *body_handler, int idx) { const belle_sip_list_t *l = belle_sip_multipart_body_handler_get_parts(BELLE_SIP_MULTIPART_BODY_HANDLER(body_handler)); return (SalBodyHandler *)belle_sip_list_nth_data(l, idx); } const belle_sip_list_t * sal_body_handler_get_parts(const SalBodyHandler *body_handler) { if (!sal_body_handler_is_multipart(body_handler)) return NULL; return belle_sip_multipart_body_handler_get_parts(BELLE_SIP_MULTIPART_BODY_HANDLER(body_handler)); } SalBodyHandler * sal_body_handler_find_part_by_header(const SalBodyHandler *body_handler, const char *header_name, const char *header_value) { const belle_sip_list_t *l = belle_sip_multipart_body_handler_get_parts(BELLE_SIP_MULTIPART_BODY_HANDLER(body_handler)); for (; l != NULL; l = l->next) { belle_sip_body_handler_t *bsbh = BELLE_SIP_BODY_HANDLER(l->data); const belle_sip_list_t *headers = belle_sip_body_handler_get_headers(bsbh); for (; headers != NULL; headers = headers->next) { belle_sip_header_t *header = BELLE_SIP_HEADER(headers->data); if ((strcmp(belle_sip_header_get_name(header), header_name) == 0) && (strcmp(belle_sip_header_get_unparsed_value(header), header_value) == 0)) { return (SalBodyHandler *)bsbh; } } } return NULL; } const char * sal_body_handler_get_header(const SalBodyHandler *body_handler, const char *header_name) { belle_sip_header_t *header = sal_body_handler_find_header(body_handler, header_name); if (header != NULL) { return belle_sip_header_get_unparsed_value(header); } return NULL; } const belle_sip_list_t* sal_body_handler_get_headers(const SalBodyHandler *body_handler) { return belle_sip_body_handler_get_headers(BELLE_SIP_BODY_HANDLER(body_handler)); }