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