sip_gids.c revision 40cb5e5daa7b80bb70fcf8dadfb20f9281566331
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <time.h>
#include <sys/errno.h>
#ifdef __linux__
#include <sasl/sasl.h>
#include <sasl/saslplug.h>
#else
#include <sys/md5.h>
#endif
#include "sip_parse_uri.h"
#include "sip_msg.h"
#include "sip_miscdefs.h"
void sip_md5_hash(char *, int, char *, int, char *, int, char *, int,
char *, int, char *, int, uchar_t *);
#define SIP_RANDOM_LEN 20
/*
* Wrapper around /dev/urandom
*/
static int
sip_get_random(char *buf, int buflen)
{
static int devrandom = -1;
if (devrandom == -1 &&
(devrandom = open("/dev/urandom", O_RDONLY)) == -1) {
return (-1);
}
if (read(devrandom, buf, buflen) == -1)
return (-1);
return (0);
}
/*
* Get MD5 hash of call_id, from_tag, to_tag using key
*/
void
sip_md5_hash(char *str1, int lstr1, char *str2, int lstr2, char *str3,
int lstr3, char *str4, int lstr4, char *str5, int lstr5,
char *str6, int lstr6, uchar_t *digest)
{
MD5_CTX ctx;
#ifdef __linux__
_sasl_MD5Init(&ctx);
_sasl_MD5Update(&ctx, (uchar_t *)&sip_hash_salt, sizeof (uint64_t));
if (str1 != NULL)
_sasl_MD5Update(&ctx, (uchar_t *)str1, lstr1);
if (str2 != NULL)
_sasl_MD5Update(&ctx, (uchar_t *)str2, lstr2);
if (str3 != NULL)
_sasl_MD5Update(&ctx, (uchar_t *)str3, lstr3);
if (str4 != NULL)
_sasl_MD5Update(&ctx, (uchar_t *)str4, lstr4);
if (str5 != NULL)
_sasl_MD5Update(&ctx, (uchar_t *)str5, lstr5);
if (str6 != NULL)
_sasl_MD5Update(&ctx, (uchar_t *)str6, lstr6);
_sasl_MD5Final(digest, &ctx);
#else /* solaris */
MD5Init(&ctx);
MD5Update(&ctx, (uchar_t *)&sip_hash_salt, sizeof (uint64_t));
if (str1 != NULL)
MD5Update(&ctx, (uchar_t *)str1, lstr1);
if (str2 != NULL)
MD5Update(&ctx, (uchar_t *)str2, lstr2);
if (str3 != NULL)
MD5Update(&ctx, (uchar_t *)str3, lstr3);
if (str4 != NULL)
MD5Update(&ctx, (uchar_t *)str4, lstr4);
if (str5 != NULL)
MD5Update(&ctx, (uchar_t *)str5, lstr5);
if (str6 != NULL)
MD5Update(&ctx, (uchar_t *)str6, lstr6);
MD5Final(digest, &ctx);
#endif
}
/*
* generate a guid (globally unique id)
*/
char *
sip_guid()
{
int i;
uint8_t *r;
uint32_t random;
uint32_t time;
char *guid;
int guidlen;
#ifdef __linux__
struct timespec tspec;
#endif
guid = (char *)malloc(SIP_RANDOM_LEN + 1);
if (guid == NULL)
return (NULL);
/*
* Get a 32-bit random #
*/
if (sip_get_random((char *)&random, sizeof (random)) != 0)
return (NULL);
#ifdef __linux__
if (clock_gettime(CLOCK_REALTIME, &tspec) != 0)
return (NULL);
time = (uint32_t)tspec.tv_nsec;
#else
/*
* Get 32-bits from gethrtime()
*/
time = (uint32_t)gethrtime();
#endif
(void) snprintf(guid, SIP_RANDOM_LEN + 1, "%u%u", random, time);
guidlen = strlen(guid);
/*
* just throw in some alphabets too
*/
r = (uint8_t *)malloc(guidlen);
if (sip_get_random((char *)r, guidlen) != 0) {
free(guid);
return (NULL);
}
for (i = 0; i < guidlen; i++) {
if ((r[i] >= 65 && r[i] <= 90) ||
(r[i] >= 97 && r[i] <= 122)) {
guid[i] = r[i];
}
}
free(r);
return (guid);
}
/*
* Generate branchid for a transaction
*/
char *
sip_branchid(sip_msg_t sip_msg)
{
char *guid;
char *branchid;
_sip_header_t *via;
unsigned char md5_hash[16];
_sip_header_t *to;
_sip_header_t *from;
_sip_header_t *callid;
_sip_msg_t *_sip_msg;
int cseq;
MD5_CTX ctx;
size_t len;
int hdrlen;
int i;
if (sip_msg == NULL) {
generate_bid:
if ((branchid = (char *)malloc(SIP_BRANCHID_LEN + 1)) == NULL)
return (NULL);
guid = sip_guid();
if (guid == NULL) {
free(branchid);
return (NULL);
}
(void) snprintf(branchid, SIP_BRANCHID_LEN + 1, "z9hG4bK%s",
guid);
free(guid);
return (branchid);
}
_sip_msg = (_sip_msg_t *)sip_msg;
(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
via = sip_search_for_header(_sip_msg, SIP_VIA, NULL);
if (via == NULL) {
(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
goto generate_bid;
}
to = sip_search_for_header(_sip_msg, SIP_TO, NULL);
from = sip_search_for_header(_sip_msg, SIP_FROM, NULL);
callid = sip_search_for_header(_sip_msg, SIP_CALL_ID, NULL);
(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
cseq = sip_get_callseq_num(_sip_msg, NULL);
if (to == NULL || from == NULL || callid == NULL || cseq == -1)
return (NULL);
if (_sip_msg->sip_msg_req_res == NULL ||
_sip_msg->sip_msg_req_res->U.sip_request.sip_request_uri.
sip_str_ptr == NULL) {
return (NULL);
}
len = 2 * sizeof (md5_hash) + 1;
if ((branchid = malloc(len)) == NULL)
return (NULL);
#ifdef __linux__
_sasl_MD5Init(&ctx);
hdrlen = via->sip_hdr_end - via->sip_hdr_start;
_sasl_MD5Update(&ctx, (uchar_t *)via->sip_hdr_start, hdrlen);
hdrlen = to->sip_hdr_end - to->sip_hdr_start;
_sasl_MD5Update(&ctx, (uchar_t *)to->sip_hdr_start, hdrlen);
hdrlen = from->sip_hdr_end - from->sip_hdr_start;
_sasl_MD5Update(&ctx, (uchar_t *)from->sip_hdr_start, hdrlen);
hdrlen = callid->sip_hdr_end - callid->sip_hdr_start;
_sasl_MD5Update(&ctx, (uchar_t *)callid->sip_hdr_start, hdrlen);
_sasl_MD5Update(&ctx, (uchar_t *)_sip_msg->sip_msg_req_res->
U.sip_request.sip_request_uri.sip_str_ptr,
_sip_msg->sip_msg_req_res->U.sip_request.
sip_request_uri.sip_str_len);
_sasl_MD5Update(&ctx, (uchar_t *)&cseq, sizeof (int));
_sasl_MD5Final(md5_hash, &ctx);
#else /* solaris */
MD5Init(&ctx);
hdrlen = via->sip_hdr_end - via->sip_hdr_start;
MD5Update(&ctx, (uchar_t *)via->sip_hdr_start, hdrlen);
hdrlen = to->sip_hdr_end - to->sip_hdr_start;
MD5Update(&ctx, (uchar_t *)to->sip_hdr_start, hdrlen);
hdrlen = from->sip_hdr_end - from->sip_hdr_start;
MD5Update(&ctx, (uchar_t *)from->sip_hdr_start, hdrlen);
hdrlen = callid->sip_hdr_end - callid->sip_hdr_start;
MD5Update(&ctx, (uchar_t *)callid->sip_hdr_start, hdrlen);
MD5Update(&ctx, (uchar_t *)_sip_msg->sip_msg_req_res->
U.sip_request.sip_request_uri.sip_str_ptr,
_sip_msg->sip_msg_req_res->U.sip_request.
sip_request_uri.sip_str_len);
MD5Update(&ctx, (uchar_t *)&cseq, sizeof (int));
MD5Final(md5_hash, &ctx);
#endif
for (i = 0; i < sizeof (md5_hash); i++) {
(void) snprintf(&branchid[2 * i], len - (2 * i), "%02x",
md5_hash[i]);
}
return (branchid);
}
uint32_t
sip_get_cseq()
{
time_t tval;
tval = time(NULL);
return ((uint32_t)tval);
}
uint32_t
sip_get_rseq()
{
time_t tval;
tval = time(NULL);
return ((uint32_t)tval);
}