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