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 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <fcntl.h>
31 #include <pthread.h>
32 #include <unistd.h>
33 #include <sip.h>
34 #ifdef	__linux__
35 #include <sasl/sasl.h>
36 #include <sasl/saslplug.h>
37 #else
38 #include <sys/md5.h>
39 #endif
40 
41 #include "sip_miscdefs.h"
42 #include "sip_msg.h"
43 
44 void	sip_md5_hash(char *, int, char *, int, char *, int,  char *, int,
45 	    char *, int, char *, int, uchar_t *);
46 
47 #define	SIP_RANDOM_LEN	20
48 
49 /*
50  * Wrapper around /dev/urandom
51  */
52 static int
sip_get_random(char * buf,int buflen)53 sip_get_random(char *buf, int buflen)
54 {
55 	static int devrandom = -1;
56 
57 	if (devrandom == -1 &&
58 	    (devrandom = open("/dev/urandom", O_RDONLY)) == -1) {
59 		return (-1);
60 	}
61 
62 	if (read(devrandom, buf, buflen) == -1)
63 		return (-1);
64 	return (0);
65 }
66 
67 /*
68  * Get MD5 hash of call_id, from_tag, to_tag using key
69  */
70 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)71 sip_md5_hash(char *str1, int lstr1, char *str2, int lstr2, char *str3,
72     int lstr3, char *str4, int lstr4, char *str5, int lstr5,
73     char *str6, int lstr6, uchar_t *digest)
74 {
75 	MD5_CTX	ctx;
76 
77 #ifdef	__linux__
78 	_sasl_MD5Init(&ctx);
79 
80 	_sasl_MD5Update(&ctx, (uchar_t *)&sip_hash_salt, sizeof (uint64_t));
81 
82 	if (str1 != NULL)
83 		_sasl_MD5Update(&ctx, (uchar_t *)str1, lstr1);
84 
85 	if (str2 != NULL)
86 		_sasl_MD5Update(&ctx, (uchar_t *)str2, lstr2);
87 
88 	if (str3 != NULL)
89 		_sasl_MD5Update(&ctx, (uchar_t *)str3, lstr3);
90 
91 	if (str4 != NULL)
92 		_sasl_MD5Update(&ctx, (uchar_t *)str4, lstr4);
93 
94 	if (str5 != NULL)
95 		_sasl_MD5Update(&ctx, (uchar_t *)str5, lstr5);
96 
97 	if (str6 != NULL)
98 		_sasl_MD5Update(&ctx, (uchar_t *)str6, lstr6);
99 
100 	_sasl_MD5Final(digest, &ctx);
101 #else	/* solaris */
102 	MD5Init(&ctx);
103 
104 	MD5Update(&ctx, (uchar_t *)&sip_hash_salt, sizeof (uint64_t));
105 
106 	if (str1 != NULL)
107 		MD5Update(&ctx, (uchar_t *)str1, lstr1);
108 
109 	if (str2 != NULL)
110 		MD5Update(&ctx, (uchar_t *)str2, lstr2);
111 
112 	if (str3 != NULL)
113 		MD5Update(&ctx, (uchar_t *)str3, lstr3);
114 
115 	if (str4 != NULL)
116 		MD5Update(&ctx, (uchar_t *)str4, lstr4);
117 
118 	if (str5 != NULL)
119 		MD5Update(&ctx, (uchar_t *)str5, lstr5);
120 
121 	if (str6 != NULL)
122 		MD5Update(&ctx, (uchar_t *)str6, lstr6);
123 
124 	MD5Final(digest, &ctx);
125 #endif
126 }
127 
128 /*
129  * generate a guid (globally unique id)
130  */
131 char *
sip_guid()132 sip_guid()
133 {
134 	int		i;
135 	uint8_t		*r;
136 	uint32_t 	random;
137 	uint32_t	time;
138 	char		*guid;
139 	int		guidlen;
140 #ifdef	__linux__
141 	struct timespec	tspec;
142 #endif
143 
144 	guid = (char *)malloc(SIP_RANDOM_LEN + 1);
145 	if (guid == NULL)
146 		return (NULL);
147 	/*
148 	 * Get a 32-bit random #
149 	 */
150 	if (sip_get_random((char *)&random, sizeof (random)) != 0)
151 		return (NULL);
152 #ifdef	__linux__
153 	if (clock_gettime(CLOCK_REALTIME, &tspec) != 0)
154 		return (NULL);
155 	time = (uint32_t)tspec.tv_nsec;
156 #else
157 	/*
158 	 * Get 32-bits from gethrtime()
159 	 */
160 	time = (uint32_t)gethrtime();
161 #endif
162 	(void) snprintf(guid, SIP_RANDOM_LEN + 1, "%u%u", random, time);
163 	guidlen = strlen(guid);
164 
165 	/*
166 	 * just throw in some alphabets too
167 	 */
168 	r = (uint8_t *)malloc(guidlen);
169 	if (sip_get_random((char *)r, guidlen) != 0) {
170 		free(guid);
171 		return (NULL);
172 	}
173 	for (i = 0; i < guidlen; i++) {
174 		if ((r[i] >= 65 && r[i] <= 90) ||
175 		    (r[i] >= 97 && r[i] <= 122)) {
176 			guid[i] = r[i];
177 		}
178 	}
179 	free(r);
180 	return (guid);
181 }
182 
183 /*
184  * Generate  branchid for a transaction
185  */
186 char *
sip_branchid(sip_msg_t sip_msg)187 sip_branchid(sip_msg_t sip_msg)
188 {
189 	char		*guid;
190 	char		*branchid;
191 	_sip_header_t	*via;
192 	unsigned char 	md5_hash[16];
193 	_sip_header_t	*to;
194 	_sip_header_t	*from;
195 	_sip_header_t	*callid;
196 	_sip_msg_t	*_sip_msg;
197 	int		cseq;
198 	MD5_CTX		ctx;
199 	size_t		len;
200 	int		hdrlen;
201 	int		i;
202 
203 	if (sip_msg == NULL) {
204 generate_bid:
205 		if ((branchid = (char *)malloc(SIP_BRANCHID_LEN + 1)) == NULL)
206 			return (NULL);
207 		guid = sip_guid();
208 		if (guid == NULL) {
209 			free(branchid);
210 			return (NULL);
211 		}
212 		(void) snprintf(branchid, SIP_BRANCHID_LEN + 1, "z9hG4bK%s",
213 		    guid);
214 		free(guid);
215 		return (branchid);
216 	}
217 	_sip_msg = (_sip_msg_t *)sip_msg;
218 	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
219 	via = sip_search_for_header(_sip_msg, SIP_VIA, NULL);
220 	if (via == NULL) {
221 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
222 		goto generate_bid;
223 	}
224 	to = sip_search_for_header(_sip_msg, SIP_TO, NULL);
225 	from = sip_search_for_header(_sip_msg, SIP_FROM, NULL);
226 	callid = sip_search_for_header(_sip_msg, SIP_CALL_ID, NULL);
227 	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
228 	cseq = sip_get_callseq_num(_sip_msg, NULL);
229 	if (to == NULL || from == NULL || callid == NULL || cseq == -1)
230 		return (NULL);
231 	if (_sip_msg->sip_msg_req_res == NULL ||
232 	    _sip_msg->sip_msg_req_res->U.sip_request.sip_request_uri.
233 	    sip_str_ptr == NULL) {
234 		return (NULL);
235 	}
236 	len = 2 * sizeof (md5_hash) + 1;
237 	if ((branchid = malloc(len)) == NULL)
238 		return (NULL);
239 #ifdef	__linux__
240 	_sasl_MD5Init(&ctx);
241 	hdrlen = via->sip_hdr_end - via->sip_hdr_start;
242 	_sasl_MD5Update(&ctx, (uchar_t *)via->sip_hdr_start, hdrlen);
243 	hdrlen = to->sip_hdr_end - to->sip_hdr_start;
244 	_sasl_MD5Update(&ctx, (uchar_t *)to->sip_hdr_start, hdrlen);
245 	hdrlen = from->sip_hdr_end - from->sip_hdr_start;
246 	_sasl_MD5Update(&ctx, (uchar_t *)from->sip_hdr_start, hdrlen);
247 	hdrlen = callid->sip_hdr_end - callid->sip_hdr_start;
248 	_sasl_MD5Update(&ctx, (uchar_t *)callid->sip_hdr_start, hdrlen);
249 	_sasl_MD5Update(&ctx, (uchar_t *)_sip_msg->sip_msg_req_res->
250 	    U.sip_request.sip_request_uri.sip_str_ptr,
251 	    _sip_msg->sip_msg_req_res->U.sip_request.
252 	    sip_request_uri.sip_str_len);
253 	_sasl_MD5Update(&ctx, (uchar_t *)&cseq, sizeof (int));
254 	_sasl_MD5Final(md5_hash, &ctx);
255 #else	/* solaris */
256 	MD5Init(&ctx);
257 	hdrlen = via->sip_hdr_end - via->sip_hdr_start;
258 	MD5Update(&ctx, (uchar_t *)via->sip_hdr_start, hdrlen);
259 	hdrlen = to->sip_hdr_end - to->sip_hdr_start;
260 	MD5Update(&ctx, (uchar_t *)to->sip_hdr_start, hdrlen);
261 	hdrlen = from->sip_hdr_end - from->sip_hdr_start;
262 	MD5Update(&ctx, (uchar_t *)from->sip_hdr_start, hdrlen);
263 	hdrlen = callid->sip_hdr_end - callid->sip_hdr_start;
264 	MD5Update(&ctx, (uchar_t *)callid->sip_hdr_start, hdrlen);
265 	MD5Update(&ctx, (uchar_t *)_sip_msg->sip_msg_req_res->
266 	    U.sip_request.sip_request_uri.sip_str_ptr,
267 	    _sip_msg->sip_msg_req_res->U.sip_request.
268 	    sip_request_uri.sip_str_len);
269 	MD5Update(&ctx, (uchar_t *)&cseq, sizeof (int));
270 	MD5Final(md5_hash, &ctx);
271 #endif
272 	for (i = 0; i < sizeof (md5_hash); i++) {
273 		(void) snprintf(&branchid[2 * i], len - (2 * i), "%02x",
274 		    md5_hash[i]);
275 	}
276 	return (branchid);
277 }
278 
279 uint32_t
sip_get_cseq()280 sip_get_cseq()
281 {
282 	time_t	tval;
283 
284 	tval = time(NULL);
285 
286 	return ((uint32_t)tval);
287 }
288 
289 uint32_t
sip_get_rseq()290 sip_get_rseq()
291 {
292 	time_t	tval;
293 
294 	tval = time(NULL);
295 
296 	return ((uint32_t)tval);
297 }
298