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