140cb5e5dSvi117747 /*
240cb5e5dSvi117747 * CDDL HEADER START
340cb5e5dSvi117747 *
440cb5e5dSvi117747 * The contents of this file are subject to the terms of the
540cb5e5dSvi117747 * Common Development and Distribution License (the "License").
640cb5e5dSvi117747 * You may not use this file except in compliance with the License.
740cb5e5dSvi117747 *
840cb5e5dSvi117747 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
940cb5e5dSvi117747 * or http://www.opensolaris.org/os/licensing.
1040cb5e5dSvi117747 * See the License for the specific language governing permissions
1140cb5e5dSvi117747 * and limitations under the License.
1240cb5e5dSvi117747 *
1340cb5e5dSvi117747 * When distributing Covered Code, include this CDDL HEADER in each
1440cb5e5dSvi117747 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1540cb5e5dSvi117747 * If applicable, add the following below this CDDL HEADER, with the
1640cb5e5dSvi117747 * fields enclosed by brackets "[]" replaced with your own identifying
1740cb5e5dSvi117747 * information: Portions Copyright [yyyy] [name of copyright owner]
1840cb5e5dSvi117747 *
1940cb5e5dSvi117747 * CDDL HEADER END
2040cb5e5dSvi117747 */
2140cb5e5dSvi117747
2240cb5e5dSvi117747 /*
23*2c2c4183Svi117747 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
2440cb5e5dSvi117747 * Use is subject to license terms.
2540cb5e5dSvi117747 */
2640cb5e5dSvi117747
2740cb5e5dSvi117747 #pragma ident "%Z%%M% %I% %E% SMI"
2840cb5e5dSvi117747
2940cb5e5dSvi117747 #include <stdio.h>
3040cb5e5dSvi117747 #include <stdlib.h>
3140cb5e5dSvi117747 #include <string.h>
3240cb5e5dSvi117747 #include <fcntl.h>
33*2c2c4183Svi117747 #include <pthread.h>
3440cb5e5dSvi117747 #include <unistd.h>
35*2c2c4183Svi117747 #include <sip.h>
3640cb5e5dSvi117747 #ifdef __linux__
3740cb5e5dSvi117747 #include <sasl/sasl.h>
3840cb5e5dSvi117747 #include <sasl/saslplug.h>
3940cb5e5dSvi117747 #else
4040cb5e5dSvi117747 #include <sys/md5.h>
4140cb5e5dSvi117747 #endif
4240cb5e5dSvi117747
4340cb5e5dSvi117747 #include "sip_miscdefs.h"
44*2c2c4183Svi117747 #include "sip_msg.h"
4540cb5e5dSvi117747
4640cb5e5dSvi117747 void sip_md5_hash(char *, int, char *, int, char *, int, char *, int,
4740cb5e5dSvi117747 char *, int, char *, int, uchar_t *);
4840cb5e5dSvi117747
4940cb5e5dSvi117747 #define SIP_RANDOM_LEN 20
5040cb5e5dSvi117747
5140cb5e5dSvi117747 /*
5240cb5e5dSvi117747 * Wrapper around /dev/urandom
5340cb5e5dSvi117747 */
5440cb5e5dSvi117747 static int
sip_get_random(char * buf,int buflen)5540cb5e5dSvi117747 sip_get_random(char *buf, int buflen)
5640cb5e5dSvi117747 {
5740cb5e5dSvi117747 static int devrandom = -1;
5840cb5e5dSvi117747
5940cb5e5dSvi117747 if (devrandom == -1 &&
6040cb5e5dSvi117747 (devrandom = open("/dev/urandom", O_RDONLY)) == -1) {
6140cb5e5dSvi117747 return (-1);
6240cb5e5dSvi117747 }
6340cb5e5dSvi117747
6440cb5e5dSvi117747 if (read(devrandom, buf, buflen) == -1)
6540cb5e5dSvi117747 return (-1);
6640cb5e5dSvi117747 return (0);
6740cb5e5dSvi117747 }
6840cb5e5dSvi117747
6940cb5e5dSvi117747 /*
7040cb5e5dSvi117747 * Get MD5 hash of call_id, from_tag, to_tag using key
7140cb5e5dSvi117747 */
7240cb5e5dSvi117747 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)7340cb5e5dSvi117747 sip_md5_hash(char *str1, int lstr1, char *str2, int lstr2, char *str3,
7440cb5e5dSvi117747 int lstr3, char *str4, int lstr4, char *str5, int lstr5,
7540cb5e5dSvi117747 char *str6, int lstr6, uchar_t *digest)
7640cb5e5dSvi117747 {
7740cb5e5dSvi117747 MD5_CTX ctx;
7840cb5e5dSvi117747
7940cb5e5dSvi117747 #ifdef __linux__
8040cb5e5dSvi117747 _sasl_MD5Init(&ctx);
8140cb5e5dSvi117747
8240cb5e5dSvi117747 _sasl_MD5Update(&ctx, (uchar_t *)&sip_hash_salt, sizeof (uint64_t));
8340cb5e5dSvi117747
8440cb5e5dSvi117747 if (str1 != NULL)
8540cb5e5dSvi117747 _sasl_MD5Update(&ctx, (uchar_t *)str1, lstr1);
8640cb5e5dSvi117747
8740cb5e5dSvi117747 if (str2 != NULL)
8840cb5e5dSvi117747 _sasl_MD5Update(&ctx, (uchar_t *)str2, lstr2);
8940cb5e5dSvi117747
9040cb5e5dSvi117747 if (str3 != NULL)
9140cb5e5dSvi117747 _sasl_MD5Update(&ctx, (uchar_t *)str3, lstr3);
9240cb5e5dSvi117747
9340cb5e5dSvi117747 if (str4 != NULL)
9440cb5e5dSvi117747 _sasl_MD5Update(&ctx, (uchar_t *)str4, lstr4);
9540cb5e5dSvi117747
9640cb5e5dSvi117747 if (str5 != NULL)
9740cb5e5dSvi117747 _sasl_MD5Update(&ctx, (uchar_t *)str5, lstr5);
9840cb5e5dSvi117747
9940cb5e5dSvi117747 if (str6 != NULL)
10040cb5e5dSvi117747 _sasl_MD5Update(&ctx, (uchar_t *)str6, lstr6);
10140cb5e5dSvi117747
10240cb5e5dSvi117747 _sasl_MD5Final(digest, &ctx);
10340cb5e5dSvi117747 #else /* solaris */
10440cb5e5dSvi117747 MD5Init(&ctx);
10540cb5e5dSvi117747
10640cb5e5dSvi117747 MD5Update(&ctx, (uchar_t *)&sip_hash_salt, sizeof (uint64_t));
10740cb5e5dSvi117747
10840cb5e5dSvi117747 if (str1 != NULL)
10940cb5e5dSvi117747 MD5Update(&ctx, (uchar_t *)str1, lstr1);
11040cb5e5dSvi117747
11140cb5e5dSvi117747 if (str2 != NULL)
11240cb5e5dSvi117747 MD5Update(&ctx, (uchar_t *)str2, lstr2);
11340cb5e5dSvi117747
11440cb5e5dSvi117747 if (str3 != NULL)
11540cb5e5dSvi117747 MD5Update(&ctx, (uchar_t *)str3, lstr3);
11640cb5e5dSvi117747
11740cb5e5dSvi117747 if (str4 != NULL)
11840cb5e5dSvi117747 MD5Update(&ctx, (uchar_t *)str4, lstr4);
11940cb5e5dSvi117747
12040cb5e5dSvi117747 if (str5 != NULL)
12140cb5e5dSvi117747 MD5Update(&ctx, (uchar_t *)str5, lstr5);
12240cb5e5dSvi117747
12340cb5e5dSvi117747 if (str6 != NULL)
12440cb5e5dSvi117747 MD5Update(&ctx, (uchar_t *)str6, lstr6);
12540cb5e5dSvi117747
12640cb5e5dSvi117747 MD5Final(digest, &ctx);
12740cb5e5dSvi117747 #endif
12840cb5e5dSvi117747 }
12940cb5e5dSvi117747
13040cb5e5dSvi117747 /*
13140cb5e5dSvi117747 * generate a guid (globally unique id)
13240cb5e5dSvi117747 */
13340cb5e5dSvi117747 char *
sip_guid()13440cb5e5dSvi117747 sip_guid()
13540cb5e5dSvi117747 {
13640cb5e5dSvi117747 int i;
13740cb5e5dSvi117747 uint8_t *r;
13840cb5e5dSvi117747 uint32_t random;
13940cb5e5dSvi117747 uint32_t time;
14040cb5e5dSvi117747 char *guid;
14140cb5e5dSvi117747 int guidlen;
14240cb5e5dSvi117747 #ifdef __linux__
14340cb5e5dSvi117747 struct timespec tspec;
14440cb5e5dSvi117747 #endif
14540cb5e5dSvi117747
14640cb5e5dSvi117747 guid = (char *)malloc(SIP_RANDOM_LEN + 1);
14740cb5e5dSvi117747 if (guid == NULL)
14840cb5e5dSvi117747 return (NULL);
14940cb5e5dSvi117747 /*
15040cb5e5dSvi117747 * Get a 32-bit random #
15140cb5e5dSvi117747 */
15240cb5e5dSvi117747 if (sip_get_random((char *)&random, sizeof (random)) != 0)
15340cb5e5dSvi117747 return (NULL);
15440cb5e5dSvi117747 #ifdef __linux__
15540cb5e5dSvi117747 if (clock_gettime(CLOCK_REALTIME, &tspec) != 0)
15640cb5e5dSvi117747 return (NULL);
15740cb5e5dSvi117747 time = (uint32_t)tspec.tv_nsec;
15840cb5e5dSvi117747 #else
15940cb5e5dSvi117747 /*
16040cb5e5dSvi117747 * Get 32-bits from gethrtime()
16140cb5e5dSvi117747 */
16240cb5e5dSvi117747 time = (uint32_t)gethrtime();
16340cb5e5dSvi117747 #endif
16440cb5e5dSvi117747 (void) snprintf(guid, SIP_RANDOM_LEN + 1, "%u%u", random, time);
16540cb5e5dSvi117747 guidlen = strlen(guid);
16640cb5e5dSvi117747
16740cb5e5dSvi117747 /*
16840cb5e5dSvi117747 * just throw in some alphabets too
16940cb5e5dSvi117747 */
17040cb5e5dSvi117747 r = (uint8_t *)malloc(guidlen);
17140cb5e5dSvi117747 if (sip_get_random((char *)r, guidlen) != 0) {
17240cb5e5dSvi117747 free(guid);
17340cb5e5dSvi117747 return (NULL);
17440cb5e5dSvi117747 }
17540cb5e5dSvi117747 for (i = 0; i < guidlen; i++) {
17640cb5e5dSvi117747 if ((r[i] >= 65 && r[i] <= 90) ||
17740cb5e5dSvi117747 (r[i] >= 97 && r[i] <= 122)) {
17840cb5e5dSvi117747 guid[i] = r[i];
17940cb5e5dSvi117747 }
18040cb5e5dSvi117747 }
18140cb5e5dSvi117747 free(r);
18240cb5e5dSvi117747 return (guid);
18340cb5e5dSvi117747 }
18440cb5e5dSvi117747
18540cb5e5dSvi117747 /*
18640cb5e5dSvi117747 * Generate branchid for a transaction
18740cb5e5dSvi117747 */
18840cb5e5dSvi117747 char *
sip_branchid(sip_msg_t sip_msg)18940cb5e5dSvi117747 sip_branchid(sip_msg_t sip_msg)
19040cb5e5dSvi117747 {
19140cb5e5dSvi117747 char *guid;
19240cb5e5dSvi117747 char *branchid;
19340cb5e5dSvi117747 _sip_header_t *via;
19440cb5e5dSvi117747 unsigned char md5_hash[16];
19540cb5e5dSvi117747 _sip_header_t *to;
19640cb5e5dSvi117747 _sip_header_t *from;
19740cb5e5dSvi117747 _sip_header_t *callid;
19840cb5e5dSvi117747 _sip_msg_t *_sip_msg;
19940cb5e5dSvi117747 int cseq;
20040cb5e5dSvi117747 MD5_CTX ctx;
20140cb5e5dSvi117747 size_t len;
20240cb5e5dSvi117747 int hdrlen;
20340cb5e5dSvi117747 int i;
20440cb5e5dSvi117747
20540cb5e5dSvi117747 if (sip_msg == NULL) {
20640cb5e5dSvi117747 generate_bid:
20740cb5e5dSvi117747 if ((branchid = (char *)malloc(SIP_BRANCHID_LEN + 1)) == NULL)
20840cb5e5dSvi117747 return (NULL);
20940cb5e5dSvi117747 guid = sip_guid();
21040cb5e5dSvi117747 if (guid == NULL) {
21140cb5e5dSvi117747 free(branchid);
21240cb5e5dSvi117747 return (NULL);
21340cb5e5dSvi117747 }
21440cb5e5dSvi117747 (void) snprintf(branchid, SIP_BRANCHID_LEN + 1, "z9hG4bK%s",
21540cb5e5dSvi117747 guid);
21640cb5e5dSvi117747 free(guid);
21740cb5e5dSvi117747 return (branchid);
21840cb5e5dSvi117747 }
21940cb5e5dSvi117747 _sip_msg = (_sip_msg_t *)sip_msg;
22040cb5e5dSvi117747 (void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
22140cb5e5dSvi117747 via = sip_search_for_header(_sip_msg, SIP_VIA, NULL);
22240cb5e5dSvi117747 if (via == NULL) {
22340cb5e5dSvi117747 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
22440cb5e5dSvi117747 goto generate_bid;
22540cb5e5dSvi117747 }
22640cb5e5dSvi117747 to = sip_search_for_header(_sip_msg, SIP_TO, NULL);
22740cb5e5dSvi117747 from = sip_search_for_header(_sip_msg, SIP_FROM, NULL);
22840cb5e5dSvi117747 callid = sip_search_for_header(_sip_msg, SIP_CALL_ID, NULL);
22940cb5e5dSvi117747 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
23040cb5e5dSvi117747 cseq = sip_get_callseq_num(_sip_msg, NULL);
23140cb5e5dSvi117747 if (to == NULL || from == NULL || callid == NULL || cseq == -1)
23240cb5e5dSvi117747 return (NULL);
23340cb5e5dSvi117747 if (_sip_msg->sip_msg_req_res == NULL ||
23440cb5e5dSvi117747 _sip_msg->sip_msg_req_res->U.sip_request.sip_request_uri.
23540cb5e5dSvi117747 sip_str_ptr == NULL) {
23640cb5e5dSvi117747 return (NULL);
23740cb5e5dSvi117747 }
23840cb5e5dSvi117747 len = 2 * sizeof (md5_hash) + 1;
23940cb5e5dSvi117747 if ((branchid = malloc(len)) == NULL)
24040cb5e5dSvi117747 return (NULL);
24140cb5e5dSvi117747 #ifdef __linux__
24240cb5e5dSvi117747 _sasl_MD5Init(&ctx);
24340cb5e5dSvi117747 hdrlen = via->sip_hdr_end - via->sip_hdr_start;
24440cb5e5dSvi117747 _sasl_MD5Update(&ctx, (uchar_t *)via->sip_hdr_start, hdrlen);
24540cb5e5dSvi117747 hdrlen = to->sip_hdr_end - to->sip_hdr_start;
24640cb5e5dSvi117747 _sasl_MD5Update(&ctx, (uchar_t *)to->sip_hdr_start, hdrlen);
24740cb5e5dSvi117747 hdrlen = from->sip_hdr_end - from->sip_hdr_start;
24840cb5e5dSvi117747 _sasl_MD5Update(&ctx, (uchar_t *)from->sip_hdr_start, hdrlen);
24940cb5e5dSvi117747 hdrlen = callid->sip_hdr_end - callid->sip_hdr_start;
25040cb5e5dSvi117747 _sasl_MD5Update(&ctx, (uchar_t *)callid->sip_hdr_start, hdrlen);
25140cb5e5dSvi117747 _sasl_MD5Update(&ctx, (uchar_t *)_sip_msg->sip_msg_req_res->
25240cb5e5dSvi117747 U.sip_request.sip_request_uri.sip_str_ptr,
25340cb5e5dSvi117747 _sip_msg->sip_msg_req_res->U.sip_request.
25440cb5e5dSvi117747 sip_request_uri.sip_str_len);
25540cb5e5dSvi117747 _sasl_MD5Update(&ctx, (uchar_t *)&cseq, sizeof (int));
25640cb5e5dSvi117747 _sasl_MD5Final(md5_hash, &ctx);
25740cb5e5dSvi117747 #else /* solaris */
25840cb5e5dSvi117747 MD5Init(&ctx);
25940cb5e5dSvi117747 hdrlen = via->sip_hdr_end - via->sip_hdr_start;
26040cb5e5dSvi117747 MD5Update(&ctx, (uchar_t *)via->sip_hdr_start, hdrlen);
26140cb5e5dSvi117747 hdrlen = to->sip_hdr_end - to->sip_hdr_start;
26240cb5e5dSvi117747 MD5Update(&ctx, (uchar_t *)to->sip_hdr_start, hdrlen);
26340cb5e5dSvi117747 hdrlen = from->sip_hdr_end - from->sip_hdr_start;
26440cb5e5dSvi117747 MD5Update(&ctx, (uchar_t *)from->sip_hdr_start, hdrlen);
26540cb5e5dSvi117747 hdrlen = callid->sip_hdr_end - callid->sip_hdr_start;
26640cb5e5dSvi117747 MD5Update(&ctx, (uchar_t *)callid->sip_hdr_start, hdrlen);
26740cb5e5dSvi117747 MD5Update(&ctx, (uchar_t *)_sip_msg->sip_msg_req_res->
26840cb5e5dSvi117747 U.sip_request.sip_request_uri.sip_str_ptr,
26940cb5e5dSvi117747 _sip_msg->sip_msg_req_res->U.sip_request.
27040cb5e5dSvi117747 sip_request_uri.sip_str_len);
27140cb5e5dSvi117747 MD5Update(&ctx, (uchar_t *)&cseq, sizeof (int));
27240cb5e5dSvi117747 MD5Final(md5_hash, &ctx);
27340cb5e5dSvi117747 #endif
27440cb5e5dSvi117747 for (i = 0; i < sizeof (md5_hash); i++) {
27540cb5e5dSvi117747 (void) snprintf(&branchid[2 * i], len - (2 * i), "%02x",
27640cb5e5dSvi117747 md5_hash[i]);
27740cb5e5dSvi117747 }
27840cb5e5dSvi117747 return (branchid);
27940cb5e5dSvi117747 }
28040cb5e5dSvi117747
28140cb5e5dSvi117747 uint32_t
sip_get_cseq()28240cb5e5dSvi117747 sip_get_cseq()
28340cb5e5dSvi117747 {
28440cb5e5dSvi117747 time_t tval;
28540cb5e5dSvi117747
28640cb5e5dSvi117747 tval = time(NULL);
28740cb5e5dSvi117747
28840cb5e5dSvi117747 return ((uint32_t)tval);
28940cb5e5dSvi117747 }
29040cb5e5dSvi117747
29140cb5e5dSvi117747 uint32_t
sip_get_rseq()29240cb5e5dSvi117747 sip_get_rseq()
29340cb5e5dSvi117747 {
29440cb5e5dSvi117747 time_t tval;
29540cb5e5dSvi117747
29640cb5e5dSvi117747 tval = time(NULL);
29740cb5e5dSvi117747
29840cb5e5dSvi117747 return ((uint32_t)tval);
29940cb5e5dSvi117747 }
300