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 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 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 * 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 * 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 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 290 sip_get_rseq() 291 { 292 time_t tval; 293 294 tval = time(NULL); 295 296 return ((uint32_t)tval); 297 } 298