12882Svi117747 /*
22882Svi117747 * CDDL HEADER START
32882Svi117747 *
42882Svi117747 * The contents of this file are subject to the terms of the
52882Svi117747 * Common Development and Distribution License (the "License").
62882Svi117747 * You may not use this file except in compliance with the License.
72882Svi117747 *
82882Svi117747 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92882Svi117747 * or http://www.opensolaris.org/os/licensing.
102882Svi117747 * See the License for the specific language governing permissions
112882Svi117747 * and limitations under the License.
122882Svi117747 *
132882Svi117747 * When distributing Covered Code, include this CDDL HEADER in each
142882Svi117747 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152882Svi117747 * If applicable, add the following below this CDDL HEADER, with the
162882Svi117747 * fields enclosed by brackets "[]" replaced with your own identifying
172882Svi117747 * information: Portions Copyright [yyyy] [name of copyright owner]
182882Svi117747 *
192882Svi117747 * CDDL HEADER END
202882Svi117747 */
212882Svi117747
222882Svi117747 /*
23*3439Svi117747 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
242882Svi117747 * Use is subject to license terms.
252882Svi117747 */
262882Svi117747
272882Svi117747 #pragma ident "%Z%%M% %I% %E% SMI"
282882Svi117747
292882Svi117747 #include <stdio.h>
302882Svi117747 #include <stdlib.h>
312882Svi117747 #include <string.h>
322882Svi117747 #include <fcntl.h>
33*3439Svi117747 #include <pthread.h>
342882Svi117747 #include <unistd.h>
35*3439Svi117747 #include <sip.h>
362882Svi117747 #ifdef __linux__
372882Svi117747 #include <sasl/sasl.h>
382882Svi117747 #include <sasl/saslplug.h>
392882Svi117747 #else
402882Svi117747 #include <sys/md5.h>
412882Svi117747 #endif
422882Svi117747
43*3439Svi117747 #include "sip_miscdefs.h"
442882Svi117747 #include "sip_msg.h"
452882Svi117747
462882Svi117747 void sip_md5_hash(char *, int, char *, int, char *, int, char *, int,
472882Svi117747 char *, int, char *, int, uchar_t *);
482882Svi117747
492882Svi117747 #define SIP_RANDOM_LEN 20
502882Svi117747
512882Svi117747 /*
522882Svi117747 * Wrapper around /dev/urandom
532882Svi117747 */
542882Svi117747 static int
sip_get_random(char * buf,int buflen)552882Svi117747 sip_get_random(char *buf, int buflen)
562882Svi117747 {
572882Svi117747 static int devrandom = -1;
582882Svi117747
592882Svi117747 if (devrandom == -1 &&
602882Svi117747 (devrandom = open("/dev/urandom", O_RDONLY)) == -1) {
612882Svi117747 return (-1);
622882Svi117747 }
632882Svi117747
642882Svi117747 if (read(devrandom, buf, buflen) == -1)
652882Svi117747 return (-1);
662882Svi117747 return (0);
672882Svi117747 }
682882Svi117747
692882Svi117747 /*
702882Svi117747 * Get MD5 hash of call_id, from_tag, to_tag using key
712882Svi117747 */
722882Svi117747 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)732882Svi117747 sip_md5_hash(char *str1, int lstr1, char *str2, int lstr2, char *str3,
742882Svi117747 int lstr3, char *str4, int lstr4, char *str5, int lstr5,
752882Svi117747 char *str6, int lstr6, uchar_t *digest)
762882Svi117747 {
772882Svi117747 MD5_CTX ctx;
782882Svi117747
792882Svi117747 #ifdef __linux__
802882Svi117747 _sasl_MD5Init(&ctx);
812882Svi117747
822882Svi117747 _sasl_MD5Update(&ctx, (uchar_t *)&sip_hash_salt, sizeof (uint64_t));
832882Svi117747
842882Svi117747 if (str1 != NULL)
852882Svi117747 _sasl_MD5Update(&ctx, (uchar_t *)str1, lstr1);
862882Svi117747
872882Svi117747 if (str2 != NULL)
882882Svi117747 _sasl_MD5Update(&ctx, (uchar_t *)str2, lstr2);
892882Svi117747
902882Svi117747 if (str3 != NULL)
912882Svi117747 _sasl_MD5Update(&ctx, (uchar_t *)str3, lstr3);
922882Svi117747
932882Svi117747 if (str4 != NULL)
942882Svi117747 _sasl_MD5Update(&ctx, (uchar_t *)str4, lstr4);
952882Svi117747
962882Svi117747 if (str5 != NULL)
972882Svi117747 _sasl_MD5Update(&ctx, (uchar_t *)str5, lstr5);
982882Svi117747
992882Svi117747 if (str6 != NULL)
1002882Svi117747 _sasl_MD5Update(&ctx, (uchar_t *)str6, lstr6);
1012882Svi117747
1022882Svi117747 _sasl_MD5Final(digest, &ctx);
1032882Svi117747 #else /* solaris */
1042882Svi117747 MD5Init(&ctx);
1052882Svi117747
1062882Svi117747 MD5Update(&ctx, (uchar_t *)&sip_hash_salt, sizeof (uint64_t));
1072882Svi117747
1082882Svi117747 if (str1 != NULL)
1092882Svi117747 MD5Update(&ctx, (uchar_t *)str1, lstr1);
1102882Svi117747
1112882Svi117747 if (str2 != NULL)
1122882Svi117747 MD5Update(&ctx, (uchar_t *)str2, lstr2);
1132882Svi117747
1142882Svi117747 if (str3 != NULL)
1152882Svi117747 MD5Update(&ctx, (uchar_t *)str3, lstr3);
1162882Svi117747
1172882Svi117747 if (str4 != NULL)
1182882Svi117747 MD5Update(&ctx, (uchar_t *)str4, lstr4);
1192882Svi117747
1202882Svi117747 if (str5 != NULL)
1212882Svi117747 MD5Update(&ctx, (uchar_t *)str5, lstr5);
1222882Svi117747
1232882Svi117747 if (str6 != NULL)
1242882Svi117747 MD5Update(&ctx, (uchar_t *)str6, lstr6);
1252882Svi117747
1262882Svi117747 MD5Final(digest, &ctx);
1272882Svi117747 #endif
1282882Svi117747 }
1292882Svi117747
1302882Svi117747 /*
1312882Svi117747 * generate a guid (globally unique id)
1322882Svi117747 */
1332882Svi117747 char *
sip_guid()1342882Svi117747 sip_guid()
1352882Svi117747 {
1362882Svi117747 int i;
1372882Svi117747 uint8_t *r;
1382882Svi117747 uint32_t random;
1392882Svi117747 uint32_t time;
1402882Svi117747 char *guid;
1412882Svi117747 int guidlen;
1422882Svi117747 #ifdef __linux__
1432882Svi117747 struct timespec tspec;
1442882Svi117747 #endif
1452882Svi117747
1462882Svi117747 guid = (char *)malloc(SIP_RANDOM_LEN + 1);
1472882Svi117747 if (guid == NULL)
1482882Svi117747 return (NULL);
1492882Svi117747 /*
1502882Svi117747 * Get a 32-bit random #
1512882Svi117747 */
1522882Svi117747 if (sip_get_random((char *)&random, sizeof (random)) != 0)
1532882Svi117747 return (NULL);
1542882Svi117747 #ifdef __linux__
1552882Svi117747 if (clock_gettime(CLOCK_REALTIME, &tspec) != 0)
1562882Svi117747 return (NULL);
1572882Svi117747 time = (uint32_t)tspec.tv_nsec;
1582882Svi117747 #else
1592882Svi117747 /*
1602882Svi117747 * Get 32-bits from gethrtime()
1612882Svi117747 */
1622882Svi117747 time = (uint32_t)gethrtime();
1632882Svi117747 #endif
1642882Svi117747 (void) snprintf(guid, SIP_RANDOM_LEN + 1, "%u%u", random, time);
1652882Svi117747 guidlen = strlen(guid);
1662882Svi117747
1672882Svi117747 /*
1682882Svi117747 * just throw in some alphabets too
1692882Svi117747 */
1702882Svi117747 r = (uint8_t *)malloc(guidlen);
1712882Svi117747 if (sip_get_random((char *)r, guidlen) != 0) {
1722882Svi117747 free(guid);
1732882Svi117747 return (NULL);
1742882Svi117747 }
1752882Svi117747 for (i = 0; i < guidlen; i++) {
1762882Svi117747 if ((r[i] >= 65 && r[i] <= 90) ||
1772882Svi117747 (r[i] >= 97 && r[i] <= 122)) {
1782882Svi117747 guid[i] = r[i];
1792882Svi117747 }
1802882Svi117747 }
1812882Svi117747 free(r);
1822882Svi117747 return (guid);
1832882Svi117747 }
1842882Svi117747
1852882Svi117747 /*
1862882Svi117747 * Generate branchid for a transaction
1872882Svi117747 */
1882882Svi117747 char *
sip_branchid(sip_msg_t sip_msg)1892882Svi117747 sip_branchid(sip_msg_t sip_msg)
1902882Svi117747 {
1912882Svi117747 char *guid;
1922882Svi117747 char *branchid;
1932882Svi117747 _sip_header_t *via;
1942882Svi117747 unsigned char md5_hash[16];
1952882Svi117747 _sip_header_t *to;
1962882Svi117747 _sip_header_t *from;
1972882Svi117747 _sip_header_t *callid;
1982882Svi117747 _sip_msg_t *_sip_msg;
1992882Svi117747 int cseq;
2002882Svi117747 MD5_CTX ctx;
2012882Svi117747 size_t len;
2022882Svi117747 int hdrlen;
2032882Svi117747 int i;
2042882Svi117747
2052882Svi117747 if (sip_msg == NULL) {
2062882Svi117747 generate_bid:
2072882Svi117747 if ((branchid = (char *)malloc(SIP_BRANCHID_LEN + 1)) == NULL)
2082882Svi117747 return (NULL);
2092882Svi117747 guid = sip_guid();
2102882Svi117747 if (guid == NULL) {
2112882Svi117747 free(branchid);
2122882Svi117747 return (NULL);
2132882Svi117747 }
2142882Svi117747 (void) snprintf(branchid, SIP_BRANCHID_LEN + 1, "z9hG4bK%s",
2152882Svi117747 guid);
2162882Svi117747 free(guid);
2172882Svi117747 return (branchid);
2182882Svi117747 }
2192882Svi117747 _sip_msg = (_sip_msg_t *)sip_msg;
2202882Svi117747 (void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
2212882Svi117747 via = sip_search_for_header(_sip_msg, SIP_VIA, NULL);
2222882Svi117747 if (via == NULL) {
2232882Svi117747 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
2242882Svi117747 goto generate_bid;
2252882Svi117747 }
2262882Svi117747 to = sip_search_for_header(_sip_msg, SIP_TO, NULL);
2272882Svi117747 from = sip_search_for_header(_sip_msg, SIP_FROM, NULL);
2282882Svi117747 callid = sip_search_for_header(_sip_msg, SIP_CALL_ID, NULL);
2292882Svi117747 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
2302882Svi117747 cseq = sip_get_callseq_num(_sip_msg, NULL);
2312882Svi117747 if (to == NULL || from == NULL || callid == NULL || cseq == -1)
2322882Svi117747 return (NULL);
2332882Svi117747 if (_sip_msg->sip_msg_req_res == NULL ||
2342882Svi117747 _sip_msg->sip_msg_req_res->U.sip_request.sip_request_uri.
2352882Svi117747 sip_str_ptr == NULL) {
2362882Svi117747 return (NULL);
2372882Svi117747 }
2382882Svi117747 len = 2 * sizeof (md5_hash) + 1;
2392882Svi117747 if ((branchid = malloc(len)) == NULL)
2402882Svi117747 return (NULL);
2412882Svi117747 #ifdef __linux__
2422882Svi117747 _sasl_MD5Init(&ctx);
2432882Svi117747 hdrlen = via->sip_hdr_end - via->sip_hdr_start;
2442882Svi117747 _sasl_MD5Update(&ctx, (uchar_t *)via->sip_hdr_start, hdrlen);
2452882Svi117747 hdrlen = to->sip_hdr_end - to->sip_hdr_start;
2462882Svi117747 _sasl_MD5Update(&ctx, (uchar_t *)to->sip_hdr_start, hdrlen);
2472882Svi117747 hdrlen = from->sip_hdr_end - from->sip_hdr_start;
2482882Svi117747 _sasl_MD5Update(&ctx, (uchar_t *)from->sip_hdr_start, hdrlen);
2492882Svi117747 hdrlen = callid->sip_hdr_end - callid->sip_hdr_start;
2502882Svi117747 _sasl_MD5Update(&ctx, (uchar_t *)callid->sip_hdr_start, hdrlen);
2512882Svi117747 _sasl_MD5Update(&ctx, (uchar_t *)_sip_msg->sip_msg_req_res->
2522882Svi117747 U.sip_request.sip_request_uri.sip_str_ptr,
2532882Svi117747 _sip_msg->sip_msg_req_res->U.sip_request.
2542882Svi117747 sip_request_uri.sip_str_len);
2552882Svi117747 _sasl_MD5Update(&ctx, (uchar_t *)&cseq, sizeof (int));
2562882Svi117747 _sasl_MD5Final(md5_hash, &ctx);
2572882Svi117747 #else /* solaris */
2582882Svi117747 MD5Init(&ctx);
2592882Svi117747 hdrlen = via->sip_hdr_end - via->sip_hdr_start;
2602882Svi117747 MD5Update(&ctx, (uchar_t *)via->sip_hdr_start, hdrlen);
2612882Svi117747 hdrlen = to->sip_hdr_end - to->sip_hdr_start;
2622882Svi117747 MD5Update(&ctx, (uchar_t *)to->sip_hdr_start, hdrlen);
2632882Svi117747 hdrlen = from->sip_hdr_end - from->sip_hdr_start;
2642882Svi117747 MD5Update(&ctx, (uchar_t *)from->sip_hdr_start, hdrlen);
2652882Svi117747 hdrlen = callid->sip_hdr_end - callid->sip_hdr_start;
2662882Svi117747 MD5Update(&ctx, (uchar_t *)callid->sip_hdr_start, hdrlen);
2672882Svi117747 MD5Update(&ctx, (uchar_t *)_sip_msg->sip_msg_req_res->
2682882Svi117747 U.sip_request.sip_request_uri.sip_str_ptr,
2692882Svi117747 _sip_msg->sip_msg_req_res->U.sip_request.
2702882Svi117747 sip_request_uri.sip_str_len);
2712882Svi117747 MD5Update(&ctx, (uchar_t *)&cseq, sizeof (int));
2722882Svi117747 MD5Final(md5_hash, &ctx);
2732882Svi117747 #endif
2742882Svi117747 for (i = 0; i < sizeof (md5_hash); i++) {
2752882Svi117747 (void) snprintf(&branchid[2 * i], len - (2 * i), "%02x",
2762882Svi117747 md5_hash[i]);
2772882Svi117747 }
2782882Svi117747 return (branchid);
2792882Svi117747 }
2802882Svi117747
2812882Svi117747 uint32_t
sip_get_cseq()2822882Svi117747 sip_get_cseq()
2832882Svi117747 {
2842882Svi117747 time_t tval;
2852882Svi117747
2862882Svi117747 tval = time(NULL);
2872882Svi117747
2882882Svi117747 return ((uint32_t)tval);
2892882Svi117747 }
2902882Svi117747
2912882Svi117747 uint32_t
sip_get_rseq()2922882Svi117747 sip_get_rseq()
2932882Svi117747 {
2942882Svi117747 time_t tval;
2952882Svi117747
2962882Svi117747 tval = time(NULL);
2972882Svi117747
2982882Svi117747 return ((uint32_t)tval);
2992882Svi117747 }
300