1*2882Svi117747 /*
2*2882Svi117747  * CDDL HEADER START
3*2882Svi117747  *
4*2882Svi117747  * The contents of this file are subject to the terms of the
5*2882Svi117747  * Common Development and Distribution License (the "License").
6*2882Svi117747  * You may not use this file except in compliance with the License.
7*2882Svi117747  *
8*2882Svi117747  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*2882Svi117747  * or http://www.opensolaris.org/os/licensing.
10*2882Svi117747  * See the License for the specific language governing permissions
11*2882Svi117747  * and limitations under the License.
12*2882Svi117747  *
13*2882Svi117747  * When distributing Covered Code, include this CDDL HEADER in each
14*2882Svi117747  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*2882Svi117747  * If applicable, add the following below this CDDL HEADER, with the
16*2882Svi117747  * fields enclosed by brackets "[]" replaced with your own identifying
17*2882Svi117747  * information: Portions Copyright [yyyy] [name of copyright owner]
18*2882Svi117747  *
19*2882Svi117747  * CDDL HEADER END
20*2882Svi117747  */
21*2882Svi117747 
22*2882Svi117747 /*
23*2882Svi117747  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24*2882Svi117747  * Use is subject to license terms.
25*2882Svi117747  */
26*2882Svi117747 
27*2882Svi117747 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*2882Svi117747 
29*2882Svi117747 #include <stdio.h>
30*2882Svi117747 #include <stdlib.h>
31*2882Svi117747 #include <string.h>
32*2882Svi117747 #include <fcntl.h>
33*2882Svi117747 #include <unistd.h>
34*2882Svi117747 #include <errno.h>
35*2882Svi117747 #include <sys/types.h>
36*2882Svi117747 #include <time.h>
37*2882Svi117747 #include <sys/errno.h>
38*2882Svi117747 #ifdef	__linux__
39*2882Svi117747 #include <sasl/sasl.h>
40*2882Svi117747 #include <sasl/saslplug.h>
41*2882Svi117747 #else
42*2882Svi117747 #include <sys/md5.h>
43*2882Svi117747 #endif
44*2882Svi117747 
45*2882Svi117747 #include "sip_parse_uri.h"
46*2882Svi117747 #include "sip_msg.h"
47*2882Svi117747 #include "sip_miscdefs.h"
48*2882Svi117747 
49*2882Svi117747 void	sip_md5_hash(char *, int, char *, int, char *, int,  char *, int,
50*2882Svi117747 	    char *, int, char *, int, uchar_t *);
51*2882Svi117747 
52*2882Svi117747 #define	SIP_RANDOM_LEN	20
53*2882Svi117747 
54*2882Svi117747 /*
55*2882Svi117747  * Wrapper around /dev/urandom
56*2882Svi117747  */
57*2882Svi117747 static int
58*2882Svi117747 sip_get_random(char *buf, int buflen)
59*2882Svi117747 {
60*2882Svi117747 	static int devrandom = -1;
61*2882Svi117747 
62*2882Svi117747 	if (devrandom == -1 &&
63*2882Svi117747 	    (devrandom = open("/dev/urandom", O_RDONLY)) == -1) {
64*2882Svi117747 		return (-1);
65*2882Svi117747 	}
66*2882Svi117747 
67*2882Svi117747 	if (read(devrandom, buf, buflen) == -1)
68*2882Svi117747 		return (-1);
69*2882Svi117747 	return (0);
70*2882Svi117747 }
71*2882Svi117747 
72*2882Svi117747 /*
73*2882Svi117747  * Get MD5 hash of call_id, from_tag, to_tag using key
74*2882Svi117747  */
75*2882Svi117747 void
76*2882Svi117747 sip_md5_hash(char *str1, int lstr1, char *str2, int lstr2, char *str3,
77*2882Svi117747     int lstr3, char *str4, int lstr4, char *str5, int lstr5,
78*2882Svi117747     char *str6, int lstr6, uchar_t *digest)
79*2882Svi117747 {
80*2882Svi117747 	MD5_CTX	ctx;
81*2882Svi117747 
82*2882Svi117747 #ifdef	__linux__
83*2882Svi117747 	_sasl_MD5Init(&ctx);
84*2882Svi117747 
85*2882Svi117747 	_sasl_MD5Update(&ctx, (uchar_t *)&sip_hash_salt, sizeof (uint64_t));
86*2882Svi117747 
87*2882Svi117747 	if (str1 != NULL)
88*2882Svi117747 		_sasl_MD5Update(&ctx, (uchar_t *)str1, lstr1);
89*2882Svi117747 
90*2882Svi117747 	if (str2 != NULL)
91*2882Svi117747 		_sasl_MD5Update(&ctx, (uchar_t *)str2, lstr2);
92*2882Svi117747 
93*2882Svi117747 	if (str3 != NULL)
94*2882Svi117747 		_sasl_MD5Update(&ctx, (uchar_t *)str3, lstr3);
95*2882Svi117747 
96*2882Svi117747 	if (str4 != NULL)
97*2882Svi117747 		_sasl_MD5Update(&ctx, (uchar_t *)str4, lstr4);
98*2882Svi117747 
99*2882Svi117747 	if (str5 != NULL)
100*2882Svi117747 		_sasl_MD5Update(&ctx, (uchar_t *)str5, lstr5);
101*2882Svi117747 
102*2882Svi117747 	if (str6 != NULL)
103*2882Svi117747 		_sasl_MD5Update(&ctx, (uchar_t *)str6, lstr6);
104*2882Svi117747 
105*2882Svi117747 	_sasl_MD5Final(digest, &ctx);
106*2882Svi117747 #else	/* solaris */
107*2882Svi117747 	MD5Init(&ctx);
108*2882Svi117747 
109*2882Svi117747 	MD5Update(&ctx, (uchar_t *)&sip_hash_salt, sizeof (uint64_t));
110*2882Svi117747 
111*2882Svi117747 	if (str1 != NULL)
112*2882Svi117747 		MD5Update(&ctx, (uchar_t *)str1, lstr1);
113*2882Svi117747 
114*2882Svi117747 	if (str2 != NULL)
115*2882Svi117747 		MD5Update(&ctx, (uchar_t *)str2, lstr2);
116*2882Svi117747 
117*2882Svi117747 	if (str3 != NULL)
118*2882Svi117747 		MD5Update(&ctx, (uchar_t *)str3, lstr3);
119*2882Svi117747 
120*2882Svi117747 	if (str4 != NULL)
121*2882Svi117747 		MD5Update(&ctx, (uchar_t *)str4, lstr4);
122*2882Svi117747 
123*2882Svi117747 	if (str5 != NULL)
124*2882Svi117747 		MD5Update(&ctx, (uchar_t *)str5, lstr5);
125*2882Svi117747 
126*2882Svi117747 	if (str6 != NULL)
127*2882Svi117747 		MD5Update(&ctx, (uchar_t *)str6, lstr6);
128*2882Svi117747 
129*2882Svi117747 	MD5Final(digest, &ctx);
130*2882Svi117747 #endif
131*2882Svi117747 }
132*2882Svi117747 
133*2882Svi117747 /*
134*2882Svi117747  * generate a guid (globally unique id)
135*2882Svi117747  */
136*2882Svi117747 char *
137*2882Svi117747 sip_guid()
138*2882Svi117747 {
139*2882Svi117747 	int		i;
140*2882Svi117747 	uint8_t		*r;
141*2882Svi117747 	uint32_t 	random;
142*2882Svi117747 	uint32_t	time;
143*2882Svi117747 	char		*guid;
144*2882Svi117747 	int		guidlen;
145*2882Svi117747 #ifdef	__linux__
146*2882Svi117747 	struct timespec	tspec;
147*2882Svi117747 #endif
148*2882Svi117747 
149*2882Svi117747 	guid = (char *)malloc(SIP_RANDOM_LEN + 1);
150*2882Svi117747 	if (guid == NULL)
151*2882Svi117747 		return (NULL);
152*2882Svi117747 	/*
153*2882Svi117747 	 * Get a 32-bit random #
154*2882Svi117747 	 */
155*2882Svi117747 	if (sip_get_random((char *)&random, sizeof (random)) != 0)
156*2882Svi117747 		return (NULL);
157*2882Svi117747 #ifdef	__linux__
158*2882Svi117747 	if (clock_gettime(CLOCK_REALTIME, &tspec) != 0)
159*2882Svi117747 		return (NULL);
160*2882Svi117747 	time = (uint32_t)tspec.tv_nsec;
161*2882Svi117747 #else
162*2882Svi117747 	/*
163*2882Svi117747 	 * Get 32-bits from gethrtime()
164*2882Svi117747 	 */
165*2882Svi117747 	time = (uint32_t)gethrtime();
166*2882Svi117747 #endif
167*2882Svi117747 	(void) snprintf(guid, SIP_RANDOM_LEN + 1, "%u%u", random, time);
168*2882Svi117747 	guidlen = strlen(guid);
169*2882Svi117747 
170*2882Svi117747 	/*
171*2882Svi117747 	 * just throw in some alphabets too
172*2882Svi117747 	 */
173*2882Svi117747 	r = (uint8_t *)malloc(guidlen);
174*2882Svi117747 	if (sip_get_random((char *)r, guidlen) != 0) {
175*2882Svi117747 		free(guid);
176*2882Svi117747 		return (NULL);
177*2882Svi117747 	}
178*2882Svi117747 	for (i = 0; i < guidlen; i++) {
179*2882Svi117747 		if ((r[i] >= 65 && r[i] <= 90) ||
180*2882Svi117747 		    (r[i] >= 97 && r[i] <= 122)) {
181*2882Svi117747 			guid[i] = r[i];
182*2882Svi117747 		}
183*2882Svi117747 	}
184*2882Svi117747 	free(r);
185*2882Svi117747 	return (guid);
186*2882Svi117747 }
187*2882Svi117747 
188*2882Svi117747 /*
189*2882Svi117747  * Generate  branchid for a transaction
190*2882Svi117747  */
191*2882Svi117747 char *
192*2882Svi117747 sip_branchid(sip_msg_t sip_msg)
193*2882Svi117747 {
194*2882Svi117747 	char		*guid;
195*2882Svi117747 	char		*branchid;
196*2882Svi117747 	_sip_header_t	*via;
197*2882Svi117747 	unsigned char 	md5_hash[16];
198*2882Svi117747 	_sip_header_t	*to;
199*2882Svi117747 	_sip_header_t	*from;
200*2882Svi117747 	_sip_header_t	*callid;
201*2882Svi117747 	_sip_msg_t	*_sip_msg;
202*2882Svi117747 	int		cseq;
203*2882Svi117747 	MD5_CTX		ctx;
204*2882Svi117747 	size_t		len;
205*2882Svi117747 	int		hdrlen;
206*2882Svi117747 	int		i;
207*2882Svi117747 
208*2882Svi117747 	if (sip_msg == NULL) {
209*2882Svi117747 generate_bid:
210*2882Svi117747 		if ((branchid = (char *)malloc(SIP_BRANCHID_LEN + 1)) == NULL)
211*2882Svi117747 			return (NULL);
212*2882Svi117747 		guid = sip_guid();
213*2882Svi117747 		if (guid == NULL) {
214*2882Svi117747 			free(branchid);
215*2882Svi117747 			return (NULL);
216*2882Svi117747 		}
217*2882Svi117747 		(void) snprintf(branchid, SIP_BRANCHID_LEN + 1, "z9hG4bK%s",
218*2882Svi117747 		    guid);
219*2882Svi117747 		free(guid);
220*2882Svi117747 		return (branchid);
221*2882Svi117747 	}
222*2882Svi117747 	_sip_msg = (_sip_msg_t *)sip_msg;
223*2882Svi117747 	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
224*2882Svi117747 	via = sip_search_for_header(_sip_msg, SIP_VIA, NULL);
225*2882Svi117747 	if (via == NULL) {
226*2882Svi117747 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
227*2882Svi117747 		goto generate_bid;
228*2882Svi117747 	}
229*2882Svi117747 	to = sip_search_for_header(_sip_msg, SIP_TO, NULL);
230*2882Svi117747 	from = sip_search_for_header(_sip_msg, SIP_FROM, NULL);
231*2882Svi117747 	callid = sip_search_for_header(_sip_msg, SIP_CALL_ID, NULL);
232*2882Svi117747 	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
233*2882Svi117747 	cseq = sip_get_callseq_num(_sip_msg, NULL);
234*2882Svi117747 	if (to == NULL || from == NULL || callid == NULL || cseq == -1)
235*2882Svi117747 		return (NULL);
236*2882Svi117747 	if (_sip_msg->sip_msg_req_res == NULL ||
237*2882Svi117747 	    _sip_msg->sip_msg_req_res->U.sip_request.sip_request_uri.
238*2882Svi117747 	    sip_str_ptr == NULL) {
239*2882Svi117747 		return (NULL);
240*2882Svi117747 	}
241*2882Svi117747 	len = 2 * sizeof (md5_hash) + 1;
242*2882Svi117747 	if ((branchid = malloc(len)) == NULL)
243*2882Svi117747 		return (NULL);
244*2882Svi117747 #ifdef	__linux__
245*2882Svi117747 	_sasl_MD5Init(&ctx);
246*2882Svi117747 	hdrlen = via->sip_hdr_end - via->sip_hdr_start;
247*2882Svi117747 	_sasl_MD5Update(&ctx, (uchar_t *)via->sip_hdr_start, hdrlen);
248*2882Svi117747 	hdrlen = to->sip_hdr_end - to->sip_hdr_start;
249*2882Svi117747 	_sasl_MD5Update(&ctx, (uchar_t *)to->sip_hdr_start, hdrlen);
250*2882Svi117747 	hdrlen = from->sip_hdr_end - from->sip_hdr_start;
251*2882Svi117747 	_sasl_MD5Update(&ctx, (uchar_t *)from->sip_hdr_start, hdrlen);
252*2882Svi117747 	hdrlen = callid->sip_hdr_end - callid->sip_hdr_start;
253*2882Svi117747 	_sasl_MD5Update(&ctx, (uchar_t *)callid->sip_hdr_start, hdrlen);
254*2882Svi117747 	_sasl_MD5Update(&ctx, (uchar_t *)_sip_msg->sip_msg_req_res->
255*2882Svi117747 	    U.sip_request.sip_request_uri.sip_str_ptr,
256*2882Svi117747 	    _sip_msg->sip_msg_req_res->U.sip_request.
257*2882Svi117747 	    sip_request_uri.sip_str_len);
258*2882Svi117747 	_sasl_MD5Update(&ctx, (uchar_t *)&cseq, sizeof (int));
259*2882Svi117747 	_sasl_MD5Final(md5_hash, &ctx);
260*2882Svi117747 #else	/* solaris */
261*2882Svi117747 	MD5Init(&ctx);
262*2882Svi117747 	hdrlen = via->sip_hdr_end - via->sip_hdr_start;
263*2882Svi117747 	MD5Update(&ctx, (uchar_t *)via->sip_hdr_start, hdrlen);
264*2882Svi117747 	hdrlen = to->sip_hdr_end - to->sip_hdr_start;
265*2882Svi117747 	MD5Update(&ctx, (uchar_t *)to->sip_hdr_start, hdrlen);
266*2882Svi117747 	hdrlen = from->sip_hdr_end - from->sip_hdr_start;
267*2882Svi117747 	MD5Update(&ctx, (uchar_t *)from->sip_hdr_start, hdrlen);
268*2882Svi117747 	hdrlen = callid->sip_hdr_end - callid->sip_hdr_start;
269*2882Svi117747 	MD5Update(&ctx, (uchar_t *)callid->sip_hdr_start, hdrlen);
270*2882Svi117747 	MD5Update(&ctx, (uchar_t *)_sip_msg->sip_msg_req_res->
271*2882Svi117747 	    U.sip_request.sip_request_uri.sip_str_ptr,
272*2882Svi117747 	    _sip_msg->sip_msg_req_res->U.sip_request.
273*2882Svi117747 	    sip_request_uri.sip_str_len);
274*2882Svi117747 	MD5Update(&ctx, (uchar_t *)&cseq, sizeof (int));
275*2882Svi117747 	MD5Final(md5_hash, &ctx);
276*2882Svi117747 #endif
277*2882Svi117747 	for (i = 0; i < sizeof (md5_hash); i++) {
278*2882Svi117747 		(void) snprintf(&branchid[2 * i], len - (2 * i), "%02x",
279*2882Svi117747 		    md5_hash[i]);
280*2882Svi117747 	}
281*2882Svi117747 	return (branchid);
282*2882Svi117747 }
283*2882Svi117747 
284*2882Svi117747 uint32_t
285*2882Svi117747 sip_get_cseq()
286*2882Svi117747 {
287*2882Svi117747 	time_t	tval;
288*2882Svi117747 
289*2882Svi117747 	tval = time(NULL);
290*2882Svi117747 
291*2882Svi117747 	return ((uint32_t)tval);
292*2882Svi117747 }
293*2882Svi117747 
294*2882Svi117747 uint32_t
295*2882Svi117747 sip_get_rseq()
296*2882Svi117747 {
297*2882Svi117747 	time_t	tval;
298*2882Svi117747 
299*2882Svi117747 	tval = time(NULL);
300*2882Svi117747 
301*2882Svi117747 	return ((uint32_t)tval);
302*2882Svi117747 }
303