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
sip_get_random(char * buf,int buflen)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
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)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 *
sip_guid()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 *
sip_branchid(sip_msg_t sip_msg)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
sip_get_cseq()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
sip_get_rseq()292 sip_get_rseq()
293 {
294 time_t tval;
295
296 tval = time(NULL);
297
298 return ((uint32_t)tval);
299 }
300