Quelle sdp_utils.c
Sprache: C
/* This Source Code Form is subject to the terms of the Mozilla Public
* License , v . 2 . 0 . If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <errno.h>
#include <limits.h>
#include <ctype.h>
#include "sdp_os_defs.h"
#include "sipcc_sdp.h"
#include "sdp_private.h"
#include "sdp_log.h"
#define MKI_BUF_LEN
4
static const char * logTag =
"sdp_utils" ;
// Actually checks for ASCII only unlike isdigit() on Windows.
// Also avoids UB issues with isdigit() sign extension when
// char is signed.
int sdp_is_ascii_digit(
const char c) {
return '0' <= c && c <=
'9' ;
}
sdp_mca_t *sdp_alloc_mca (uint32_t line) {
sdp_mca_t *mca_p;
/* Allocate resource for new media stream. */
mca_p = (sdp_mca_t *)SDP_MALLOC(
sizeof (sdp_mca_t));
if (mca_p == NULL) {
return (NULL);
}
/* Initialize mca structure */
mca_p->media = SDP_MEDIA_INVALID;
mca_p->conn.nettype = SDP_NT_INVALID;
mca_p->conn.addrtype = SDP_AT_INVALID;
mca_p->conn.conn_addr[
0 ] =
'\0' ;
mca_p->conn.is_multicast =
FALSE ;
mca_p->conn.ttl =
0 ;
mca_p->conn.num_of_addresses =
0 ;
mca_p->transport = SDP_TRANSPORT_INVALID;
mca_p->port = SDP_INVALID_VALUE;
mca_p->num_ports = SDP_INVALID_VALUE;
mca_p->vpi = SDP_INVALID_VALUE;
mca_p->vci =
0 ;
mca_p->vcci = SDP_INVALID_VALUE;
mca_p->cid = SDP_INVALID_VALUE;
mca_p->num_payloads =
0 ;
mca_p->sessinfo_found =
FALSE ;
mca_p->encrypt.encrypt_type = SDP_ENCRYPT_INVALID;
mca_p->media_attrs_p = NULL;
mca_p->next_p = NULL;
mca_p->mid =
0 ;
mca_p->bw.bw_data_count =
0 ;
mca_p->bw.bw_data_list = NULL;
mca_p->line_number = line;
mca_p->sctp_fmt = SDP_SCTP_MEDIA_FMT_UNKNOWN;
return (mca_p);
}
/*
* next_token
*
* copy token param with chars from str until null , cr , lf , or one of the delimiters is found .
* delimiters at the beginning will be skipped .
* The pointer * string_of_tokens is moved forward to the next token on sucess .
*
*/
static sdp_result_e next_token(
const char **string_of_tokens,
char *token,
unsigned toke
n_max_len, const char *delim)
{
int flag2moveon = 0 ;
const char *str;
const char *token_end;
const char *next_delim;
if (!string_of_tokens || !*string_of_tokens || !token || !delim) {
return SDP_FAILURE;
}
str = *string_of_tokens;
token_end = token + token_max_len - 1 ;
/* Locate front of token, skipping any delimiters */
for ( ; ((*str != '\0' ) && (*str != '\n' ) && (*str != '\r' )); str++) {
flag2moveon = 1 ; /* Default to move on unless we find a delimiter */
for (next_delim=delim; *next_delim; next_delim++) {
if (*str == *next_delim) {
flag2moveon = 0 ;
break ;
}
}
if ( flag2moveon ) {
break ; /* We're at the beginning of the token */
}
}
/* Make sure there's really a token present. */
if ((*str == '\0' ) || (*str == '\n' ) || (*str == '\r' )) {
return SDP_EMPTY_TOKEN;
}
/* Now locate end of token */
flag2moveon = 0 ;
while ((token < token_end) &&
(*str != '\0' ) && (*str != '\n' ) && (*str != '\r' )) {
for (next_delim=delim; *next_delim; next_delim++) {
if (*str == *next_delim) {
flag2moveon = 1 ;
break ;
}
}
if ( flag2moveon ) {
break ;
} else {
*token++ = *str++;
}
}
/* mark end of token */
*token = '\0' ;
/* set the string of tokens to the next token */
*string_of_tokens = str;
return SDP_SUCCESS;
}
/*
* verify_sdescriptions_mki
*
* Verifies the syntax of the MKI parameter .
*
* mki = mki - value " : " mki - length
* mki - value = 1 * DIGIT
* mki - length = 1 * 3 DIGIT ; range 1 . . 128
*
* Inputs :
* buf - ptr to start of MKI string assumes NULL
* terminated string
* mkiValue - buffer to store the MKI value , assumes calling
* function has provided memory for this .
* mkiLen - integer to store the MKI length
*
* Outputs :
* Returns TRUE if syntax is correct and stores the
* MKI value in mkiVal and stores the length in mkiLen .
* Returns FALSE otherwise .
*/
tinybool
verify_sdescriptions_mki (char *buf, char *mkiVal, uint16_t *mkiLen)
{
char *ptr,
mkiValBuf[SDP_SRTP_MAX_MKI_SIZE_BYTES],
mkiLenBuf[MKI_BUF_LEN];
int idx = 0 ;
unsigned long strtoul_result;
char *strtoul_end;
ptr = buf;
/* MKI must begin with a digit */
if (!ptr || (!sdp_is_ascii_digit(*ptr))) {
return FALSE ;
}
/* scan until we reach a non-digit or colon */
while (*ptr) {
if (*ptr == ':' ) {
/* terminate the MKI value */
mkiValBuf[idx] = 0 ;
ptr++;
break ;
} else if ((sdp_is_ascii_digit(*ptr) && (idx < SDP_SRTP_MAX_MKI_SIZE_BYTES-1 ))) {
mkiValBuf[idx++] = *ptr;
} else {
return FALSE ;
}
ptr++;
}
/* there has to be a mki length */
if (*ptr == 0 ) {
return FALSE ;
}
idx = 0 ;
/* verify the mki length (max 3 digits) */
while (*ptr) {
if (sdp_is_ascii_digit(*ptr) && (idx < 3 )) {
mkiLenBuf[idx++] = *ptr;
} else {
return FALSE ;
}
ptr++;
}
mkiLenBuf[idx] = 0 ;
errno = 0 ;
strtoul_result = strtoul(mkiLenBuf, &strtoul_end, 10 );
/* mki len must be between 1..128 */
if (errno || mkiLenBuf == strtoul_end || strtoul_result < 1 || strtoul_result > 128 ) {
*mkiLen = 0 ;
return FALSE ;
}
*mkiLen = (uint16_t) strtoul_result;
sstrncpy(mkiVal, mkiValBuf, MKI_BUF_LEN);
return TRUE ;
}
/*
* verify_srtp_lifetime
*
* Verifies the Lifetime parameter syntax .
*
* lifetime = [ " 2 ^ " ] 1 * ( DIGIT )
*
* Inputs :
* buf - pointer to start of lifetime string . Assumes string is
* NULL terminated .
* Outputs :
* Returns TRUE if syntax is correct . Returns FALSE otherwise .
*/
tinybool
verify_sdescriptions_lifetime (char *buf)
{
char *ptr;
tinybool tokenFound = FALSE ;
ptr = buf;
if (!ptr || *ptr == 0 ) {
return FALSE ;
}
while (*ptr) {
if (*ptr == '^' ) {
if (tokenFound) {
/* make sure we don't have multiple ^ */
return FALSE ;
} else {
tokenFound = TRUE ;
/* Lifetime is in power of 2 format, make sure first and second
* chars are 2 ^
*/
if (buf[0 ] != '2' || buf[1 ] != '^' ) {
return FALSE ;
}
}
} else if (!sdp_is_ascii_digit(*ptr)) {
return FALSE ;
}
ptr++;
}
/* Make sure if the format is 2^ that there is a number after the ^. */
if (tokenFound) {
if (strlen(buf) <= 2 ) {
return FALSE ;
}
}
return TRUE ;
}
/*
* sdp_validate_maxprate
*
* This function validates that the string passed in is of the form :
* packet - rate = 1 * DIGIT [ " . " 1 * DIGIT ]
*/
tinybool
sdp_validate_maxprate(const char *string_parm)
{
tinybool retval = FALSE ;
if (string_parm && (*string_parm)) {
while (sdp_is_ascii_digit(*string_parm)) {
string_parm++;
}
if (*string_parm == '.' ) {
string_parm++;
while (sdp_is_ascii_digit(*string_parm)) {
string_parm++;
}
}
if (*string_parm == '\0' ) {
retval = TRUE ;
} else {
retval = FALSE ;
}
}
return retval;
}
char *sdp_findchar (const char *ptr, char *char_list)
{
int i;
for (;*ptr != '\0' ; ptr++) {
for (i=0 ; char_list[i] != '\0' ; i++) {
if (*ptr == char_list[i]) {
return ((char *)ptr);
}
}
}
return ((char *)ptr);
}
/* Locate the next token in a line. The delim characters are passed in
* as a param . The token also will not go past a new line char or the
* end of the string . Skip any delimiters before the token .
*/
const char *sdp_getnextstrtok (const char *str, char *tokenstr, unsigned tokenstr_len,
const char *delim, sdp_result_e *result)
{
const char *token_list = str;
if (!str || !tokenstr || !delim || !result) {
if (result) {
*result = SDP_FAILURE;
}
return str;
}
*result = next_token(&token_list, tokenstr, tokenstr_len, delim);
return token_list;
}
/* Locate the next null ("-") or numeric token in a string. The delim
* characters are passed in as a param . The token also will not go past
* a new line char or the end of the string . Skip any delimiters before
* the token .
*/
uint32_t sdp_getnextnumtok_or_null (const char *str, const char **str_end,
const char *delim, tinybool *null_ind,
sdp_result_e *result)
{
const char *token_list = str;
char temp_token[SDP_MAX_STRING_LEN];
char *strtoul_end;
unsigned long numval;
if (null_ind) {
*null_ind = FALSE ;
}
if (!str || !str_end || !delim || !null_ind || !result) {
if (result) {
*result = SDP_FAILURE;
}
return 0 ;
}
*result = next_token(&token_list, temp_token, sizeof (temp_token), delim);
if (*result != SDP_SUCCESS) {
return 0 ;
}
/* First see if its the null char ("-") */
if (temp_token[0 ] == '-' ) {
*null_ind = TRUE ;
*result = SDP_SUCCESS;
*str_end = str;
return 0 ;
}
errno = 0 ;
numval = strtoul(temp_token, &strtoul_end, 10 );
if (errno || strtoul_end == temp_token || numval > UINT_MAX) {
*result = SDP_FAILURE;
return 0 ;
}
*result = SDP_SUCCESS;
*str_end = token_list;
return (uint32_t) numval;
}
/* Locate the next numeric token in a string. The delim characters are
* passed in as a param . The token also will not go past a new line char
* or the end of the string . Skip any delimiters before the token .
*/
uint32_t sdp_getnextnumtok (const char *str, const char **str_end,
const char *delim, sdp_result_e *result)
{
const char *token_list = str;
char temp_token[SDP_MAX_STRING_LEN];
char *strtoul_end;
unsigned long numval;
if (!str || !str_end || !delim || !result) {
if (result) {
*result = SDP_FAILURE;
}
return 0 ;
}
*result = next_token(&token_list, temp_token, sizeof (temp_token), delim);
if (*result != SDP_SUCCESS) {
return 0 ;
}
errno = 0 ;
numval = strtoul(temp_token, &strtoul_end, 10 );
if (errno || strtoul_end == temp_token || numval > UINT_MAX) {
*result = SDP_FAILURE;
return 0 ;
}
*result = SDP_SUCCESS;
*str_end = token_list;
return (uint32_t) numval;
}
/*
* SDP Crypto Utility Functions .
*
* First a few common definitions .
*/
/*
* Constants
*
* crypto_string = The string used to identify the start of sensative
* crypto data .
*
* inline_string = The string used to identify the start of key / salt
* crypto data .
*
* star_string = The string used to overwrite sensative data .
*
* ' * _ strlen ' = The length of ' * _ string ' in bytes ( not including ' \ 0 ' )
*/
static const char crypto_string[] = "X-crypto:" ;
static const int crypto_strlen = sizeof (crypto_string) - 1 ;
static const char inline_string[] = "inline:" ;
static const int inline_strlen = sizeof (inline_string) - 1 ;
/* 40 characters is the current maximum for a Base64 encoded key/salt */
static const char star_string[] = "****************************************" ;
static const int star_strlen = sizeof (star_string) - 1 ;
/*
* MIN_CRYPTO_STRING_SIZE_BYTES = This value defines the minimum
* size of a string that could contain a key / salt . This value
* is used to skip out of parsing when there is no reasonable
* assumption that sensative data will be found . The general
* format of a SRTP Key Salt in SDP looks like :
*
* X - crypto : < crypto_suite_name > inline : < master_key_salt > | |
*
* if < crypto_suite_name > and < master_key_salt > is at least
* one character and one space is used before the " inline : " ,
* then this translates to a size of ( aligned by collumn from
* the format shown above ) :
*
* 9 + 1 + 1 + 7 + 1 + 2 = 21
*
*/
#define MIN_CRYPTO_STRING_SIZE_BYTES 21
/*
* Utility macros
*
* CHAR_IS_WHITESPACE = macro to determine if the passed _ test_char
* is whitespace .
*
* SKIP_WHITESPACE = Macro to advance _ cptr to the next non - whitespace
* character . _ cptr will not be advanced past _ max_cptr .
*
* FIND_WHITESPACE = Macro to advance _ cptr until whitespace is found .
* _ cptr will not be advanced past _ max_cptr .
*/
#define CHAR_IS_WHITESPACE(_test_char) \
((((_test_char)==' ' )||((_test_char)=='\t' ))?1 :0 )
#define SKIP_WHITESPACE(_cptr, _max_cptr) \
while ((_cptr)<=(_max_cptr)) { \
if (!CHAR_IS_WHITESPACE(*(_cptr))) break ; \
(_cptr)++; \
}
#define FIND_WHITESPACE(_cptr, _max_cptr) \
while ((_cptr)<=(_max_cptr)) { \
if (CHAR_IS_WHITESPACE(*(_cptr))) break ; \
(_cptr)++; \
}
/* Function: sdp_crypto_debug
* Description : Check the passed buffer for sensitive data that should
* not be output ( such as SRTP Master Key / Salt ) and output
* the buffer as debug . Sensitive data will be replaced
* with the ' * ' character ( s ) . This function may be used
* to display very large buffers so this function ensures
* that buginf is not overloaded .
* Parameters : buffer pointer to the message buffer to filter .
* length_bytes size of message buffer in bytes .
* Returns : Nothing .
*/
void sdp_crypto_debug (char *buffer, ulong length_bytes)
{
char *current, *start;
char *last = buffer + length_bytes;
int result;
/*
* For SRTP Master Key / Salt has the form :
* X - crypto : < crypto_suite_name > inline : < master_key_salt > | |
* Where < master_key_salt > is the data to elide ( filter ) .
*/
for (start=current=buffer;
current<=last-MIN_CRYPTO_STRING_SIZE_BYTES;
current++) {
if ((*current == 'x' ) || (*current == 'X' )) {
result = cpr_strncasecmp(current, crypto_string, crypto_strlen);
if (!result) {
current += crypto_strlen;
if (current > last) break ;
/* Skip over crypto suite name */
FIND_WHITESPACE(current, last);
/* Skip over whitespace */
SKIP_WHITESPACE(current, last);
/* identify inline keyword */
result = cpr_strncasecmp(current, inline_string, inline_strlen);
if (!result) {
int star_count = 0 ;
current += inline_strlen;
if (current > last) break ;
sdp_dump_buffer(start, current - start);
/* Hide sensitive key/salt data */
while (current<=last) {
if (*current == '|' || *current == '\n' ) {
/* Done, print the stars */
while (star_count > star_strlen) {
/*
* This code is only for the case where
* too much base64 data was supplied
*/
sdp_dump_buffer((char *)star_string, star_strlen);
star_count -= star_strlen;
}
sdp_dump_buffer((char *)star_string, star_count);
break ;
} else {
star_count++;
current++;
}
}
/* Update start pointer */
start=current;
}
}
}
}
if (last > start) {
/* Display remainder of buffer */
sdp_dump_buffer(start, last - start);
}
}
/*
* sdp_debug_msg_filter
*
* DESCRIPTION
* Check the passed message buffer for sensitive data that should
* not be output ( such as SRTP Master Key / Salt ) . Sensitive data
* will be replaced with the ' * ' character ( s ) .
*
* PARAMETERS
* buffer : pointer to the message buffer to filter .
*
* length_bytes : size of message buffer in bytes .
*
* RETURN VALUE
* The buffer modified .
*/
char * sdp_debug_msg_filter (char *buffer, ulong length_bytes)
{
char *current;
char *last = buffer + length_bytes;
int result;
SDP_PRINT("\n%s:%d: Eliding sensitive data from debug output" ,
__FILE__, __LINE__);
/*
* For SRTP Master Key / Salt has the form :
* X - crypto : < crypto_suite_name > inline : < master_key_salt > | |
* Where < master_key_salt > is the data to elide ( filter ) .
*/
for (current=buffer;
current<=last-MIN_CRYPTO_STRING_SIZE_BYTES;
current++) {
if ((*current == 'x' ) || (*current == 'X' )) {
result = cpr_strncasecmp(current, crypto_string, crypto_strlen);
if (!result) {
current += crypto_strlen;
if (current > last) break ;
/* Skip over crypto suite name */
FIND_WHITESPACE(current, last);
/* Skip over whitespace */
SKIP_WHITESPACE(current, last);
/* identify inline keyword */
result = cpr_strncasecmp(current, inline_string, inline_strlen);
if (!result) {
current += inline_strlen;
if (current > last) break ;
/* Hide sensitive key/salt data */
while (current<=last) {
if (*current == '|' || *current == '\n' ) {
/* Done */
break ;
} else {
*current = '*' ;
current++;
}
}
}
}
}
}
return buffer;
}
/* Function: sdp_checkrange
* Description : This checks the range of a ulong value to make sure its
* within the range of 0 and 4 Gig . stroul cannot be used since
* for values greater greater than 4 G , stroul will either wrap
* around or return ULONG_MAX .
* Parameters : sdp_p Pointer to the sdp structure
* num The number to check the range for
* u_val This variable get populated with the ulong value
* if the number is within the range .
* Returns : tinybool - returns TRUE if the number passed is within the
* range , FALSE otherwise
*/
tinybool sdp_checkrange (sdp_t *sdp_p, char *num, ulong *u_val)
{
ulong l_val;
char *endP = NULL;
*u_val = 0 ;
if (!num || !*num) {
return FALSE ;
}
if (*num == '-' ) {
if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
SDPLogError(logTag, "%s ERROR: Parameter value is a negative number: %s" ,
sdp_p->debug_str, num);
}
return FALSE ;
}
l_val = strtoul(num, &endP, 10 );
if (*endP == '\0' ) {
if (l_val > 4294967295 UL) {
if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
SDPLogError(logTag, "%s ERROR: Parameter value: %s is greater than 4294967295" ,
sdp_p->debug_str, num);
}
return FALSE ;
}
if (l_val == 4294967295 UL) {
/*
* On certain platforms where ULONG_MAX is equivalent to
* 4294967295 , strtoul will return ULONG_MAX even if the the
* value of the string is greater than 4294967295 . To detect
* that scenario we make an explicit check here .
*/
if (strcmp("4294967295" , num)) {
if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
SDPLogError(logTag, "%s ERROR: Parameter value: %s is greater than 4294967295" ,
sdp_p->debug_str, num);
}
return FALSE ;
}
}
}
*u_val = l_val;
return TRUE ;
}
#undef CHAR_IS_WHITESPACE
#undef SKIP_WHITESPACE
#undef FIND_WHITESPACE
Messung V0.5 in Prozent C=93 H=87 G=89
¤ Dauer der Verarbeitung: 0.4 Sekunden
(vorverarbeitet am 2026-08-23)
¤
*© Formatika GbR, Deutschland
2026-08-25
Neuigkeiten
Aktuelles
Motto des Tages
Open Source Software
Jenseits des Üblichen ....
Besucherstatistik
Statistik
#Sources=476070
#Domains=661743