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 
46 void	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  */
54 static int
55 sip_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  */
72 void
73 sip_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  */
133 char *
134 sip_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  */
188 char *
189 sip_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) {
206 generate_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 
281 uint32_t
282 sip_get_cseq()
283 {
284 	time_t	tval;
285 
286 	tval = time(NULL);
287 
288 	return ((uint32_t)tval);
289 }
290 
291 uint32_t
292 sip_get_rseq()
293 {
294 	time_t	tval;
295 
296 	tval = time(NULL);
297 
298 	return ((uint32_t)tval);
299 }
300