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