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 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 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 * 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 * 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 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 2922882Svi117747 sip_get_rseq() 2932882Svi117747 { 2942882Svi117747 time_t tval; 2952882Svi117747 2962882Svi117747 tval = time(NULL); 2972882Svi117747 2982882Svi117747 return ((uint32_t)tval); 2992882Svi117747 } 300