1 /* 2 * libjingle 3 * Copyright 2004--2005, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include "talk/base/win32.h" 29 30 #include <winsock2.h> 31 #include <ws2tcpip.h> 32 #include <algorithm> 33 34 #include "talk/base/basictypes.h" 35 #include "talk/base/byteorder.h" 36 #include "talk/base/common.h" 37 #include "talk/base/logging.h" 38 39 namespace talk_base { 40 41 // Helper function declarations for inet_ntop/inet_pton. 42 static const char* inet_ntop_v4(const void* src, char* dst, socklen_t size); 43 static const char* inet_ntop_v6(const void* src, char* dst, socklen_t size); 44 static int inet_pton_v4(const char* src, void* dst); 45 static int inet_pton_v6(const char* src, void* dst); 46 47 // Implementation of inet_ntop (create a printable representation of an 48 // ip address). XP doesn't have its own inet_ntop, and 49 // WSAAddressToString requires both IPv6 to be installed and for Winsock 50 // to be initialized. 51 const char* win32_inet_ntop(int af, const void *src, 52 char* dst, socklen_t size) { 53 if (!src || !dst) { 54 return NULL; 55 } 56 switch (af) { 57 case AF_INET: { 58 return inet_ntop_v4(src, dst, size); 59 } 60 case AF_INET6: { 61 return inet_ntop_v6(src, dst, size); 62 } 63 } 64 return NULL; 65 } 66 67 // As above, but for inet_pton. Implements inet_pton for v4 and v6. 68 // Note that our inet_ntop will output normal 'dotted' v4 addresses only. 69 int win32_inet_pton(int af, const char* src, void* dst) { 70 if (!src || !dst) { 71 return 0; 72 } 73 if (af == AF_INET) { 74 return inet_pton_v4(src, dst); 75 } else if (af == AF_INET6) { 76 return inet_pton_v6(src, dst); 77 } 78 return -1; 79 } 80 81 // Helper function for inet_ntop for IPv4 addresses. 82 // Outputs "dotted-quad" decimal notation. 83 const char* inet_ntop_v4(const void* src, char* dst, socklen_t size) { 84 if (size < INET_ADDRSTRLEN) { 85 return NULL; 86 } 87 const struct in_addr* as_in_addr = 88 reinterpret_cast<const struct in_addr*>(src); 89 talk_base::sprintfn(dst, size, "%d.%d.%d.%d", 90 as_in_addr->S_un.S_un_b.s_b1, 91 as_in_addr->S_un.S_un_b.s_b2, 92 as_in_addr->S_un.S_un_b.s_b3, 93 as_in_addr->S_un.S_un_b.s_b4); 94 return dst; 95 } 96 97 // Helper function for inet_ntop for IPv6 addresses. 98 const char* inet_ntop_v6(const void* src, char* dst, socklen_t size) { 99 if (size < INET6_ADDRSTRLEN) { 100 return NULL; 101 } 102 const uint16* as_shorts = 103 reinterpret_cast<const uint16*>(src); 104 int runpos[8]; 105 int current = 1; 106 int max = 1; 107 int maxpos = -1; 108 int run_array_size = ARRAY_SIZE(runpos); 109 // Run over the address marking runs of 0s. 110 for (int i = 0; i < run_array_size; ++i) { 111 if (as_shorts[i] == 0) { 112 runpos[i] = current; 113 if (current > max) { 114 maxpos = i; 115 max = current; 116 } 117 ++current; 118 } else { 119 runpos[i] = -1; 120 current =1; 121 } 122 } 123 124 if (max > 1) { 125 int tmpmax = maxpos; 126 // Run back through, setting -1 for all but the longest run. 127 for (int i = run_array_size - 1; i >= 0; i--) { 128 if (i > tmpmax) { 129 runpos[i] = -1; 130 } else if (runpos[i] == -1) { 131 // We're less than maxpos, we hit a -1, so the 'good' run is done. 132 // Setting tmpmax -1 means all remaining positions get set to -1. 133 tmpmax = -1; 134 } 135 } 136 } 137 138 char* cursor = dst; 139 // Print IPv4 compatible and IPv4 mapped addresses using the IPv4 helper. 140 // These addresses have an initial run of either eight zero-bytes followed 141 // by 0xFFFF, or an initial run of ten zero-bytes. 142 if (runpos[0] == 1 && (maxpos == 5 || 143 (maxpos == 4 && as_shorts[5] == 0xFFFF))) { 144 *cursor++ = ':'; 145 *cursor++ = ':'; 146 if (maxpos == 4) { 147 cursor += talk_base::sprintfn(cursor, INET6_ADDRSTRLEN - 2, "ffff:"); 148 } 149 const struct in_addr* as_v4 = 150 reinterpret_cast<const struct in_addr*>(&(as_shorts[6])); 151 inet_ntop_v4(as_v4, cursor, 152 static_cast<socklen_t>(INET6_ADDRSTRLEN - (cursor - dst))); 153 } else { 154 for (int i = 0; i < run_array_size; ++i) { 155 if (runpos[i] == -1) { 156 cursor += talk_base::sprintfn(cursor, 157 INET6_ADDRSTRLEN - (cursor - dst), 158 "%x", NetworkToHost16(as_shorts[i])); 159 if (i != 7 && runpos[i + 1] != 1) { 160 *cursor++ = ':'; 161 } 162 } else if (runpos[i] == 1) { 163 // Entered the run; print the colons and skip the run. 164 *cursor++ = ':'; 165 *cursor++ = ':'; 166 i += (max - 1); 167 } 168 } 169 } 170 return dst; 171 } 172 173 // Helper function for inet_pton for IPv4 addresses. 174 // |src| points to a character string containing an IPv4 network address in 175 // dotted-decimal format, "ddd.ddd.ddd.ddd", where ddd is a decimal number 176 // of up to three digits in the range 0 to 255. 177 // The address is converted and copied to dst, 178 // which must be sizeof(struct in_addr) (4) bytes (32 bits) long. 179 int inet_pton_v4(const char* src, void* dst) { 180 const int kIpv4AddressSize = 4; 181 int found = 0; 182 const char* src_pos = src; 183 unsigned char result[kIpv4AddressSize] = {0}; 184 185 while (*src_pos != '\0') { 186 // strtol won't treat whitespace characters in the begining as an error, 187 // so check to ensure this is started with digit before passing to strtol. 188 if (!isdigit(*src_pos)) { 189 return 0; 190 } 191 char* end_pos; 192 long value = strtol(src_pos, &end_pos, 10); 193 if (value < 0 || value > 255 || src_pos == end_pos) { 194 return 0; 195 } 196 ++found; 197 if (found > kIpv4AddressSize) { 198 return 0; 199 } 200 result[found - 1] = static_cast<unsigned char>(value); 201 src_pos = end_pos; 202 if (*src_pos == '.') { 203 // There's more. 204 ++src_pos; 205 } else if (*src_pos != '\0') { 206 // If it's neither '.' nor '\0' then return fail. 207 return 0; 208 } 209 } 210 if (found != kIpv4AddressSize) { 211 return 0; 212 } 213 memcpy(dst, result, sizeof(result)); 214 return 1; 215 } 216 217 // Helper function for inet_pton for IPv6 addresses. 218 int inet_pton_v6(const char* src, void* dst) { 219 // sscanf will pick any other invalid chars up, but it parses 0xnnnn as hex. 220 // Check for literal x in the input string. 221 const char* readcursor = src; 222 char c = *readcursor++; 223 while (c) { 224 if (c == 'x') { 225 return 0; 226 } 227 c = *readcursor++; 228 } 229 readcursor = src; 230 231 struct in6_addr an_addr; 232 memset(&an_addr, 0, sizeof(an_addr)); 233 234 uint16* addr_cursor = reinterpret_cast<uint16*>(&an_addr.s6_addr[0]); 235 uint16* addr_end = reinterpret_cast<uint16*>(&an_addr.s6_addr[16]); 236 bool seencompressed = false; 237 238 // Addresses that start with "::" (i.e., a run of initial zeros) or 239 // "::ffff:" can potentially be IPv4 mapped or compatibility addresses. 240 // These have dotted-style IPv4 addresses on the end (e.g. "::192.168.7.1"). 241 if (*readcursor == ':' && *(readcursor+1) == ':' && 242 *(readcursor + 2) != 0) { 243 // Check for periods, which we'll take as a sign of v4 addresses. 244 const char* addrstart = readcursor + 2; 245 if (talk_base::strchr(addrstart, ".")) { 246 const char* colon = talk_base::strchr(addrstart, "::"); 247 if (colon) { 248 uint16 a_short; 249 int bytesread = 0; 250 if (sscanf(addrstart, "%hx%n", &a_short, &bytesread) != 1 || 251 a_short != 0xFFFF || bytesread != 4) { 252 // Colons + periods means has to be ::ffff:a.b.c.d. But it wasn't. 253 return 0; 254 } else { 255 an_addr.s6_addr[10] = 0xFF; 256 an_addr.s6_addr[11] = 0xFF; 257 addrstart = colon + 1; 258 } 259 } 260 struct in_addr v4; 261 if (inet_pton_v4(addrstart, &v4.s_addr)) { 262 memcpy(&an_addr.s6_addr[12], &v4, sizeof(v4)); 263 memcpy(dst, &an_addr, sizeof(an_addr)); 264 return 1; 265 } else { 266 // Invalid v4 address. 267 return 0; 268 } 269 } 270 } 271 272 // For addresses without a trailing IPv4 component ('normal' IPv6 addresses). 273 while (*readcursor != 0 && addr_cursor < addr_end) { 274 if (*readcursor == ':') { 275 if (*(readcursor + 1) == ':') { 276 if (seencompressed) { 277 // Can only have one compressed run of zeroes ("::") per address. 278 return 0; 279 } 280 // Hit a compressed run. Count colons to figure out how much of the 281 // address is skipped. 282 readcursor += 2; 283 const char* coloncounter = readcursor; 284 int coloncount = 0; 285 if (*coloncounter == 0) { 286 // Special case - trailing ::. 287 addr_cursor = addr_end; 288 } else { 289 while (*coloncounter) { 290 if (*coloncounter == ':') { 291 ++coloncount; 292 } 293 ++coloncounter; 294 } 295 // (coloncount + 1) is the number of shorts left in the address. 296 addr_cursor = addr_end - (coloncount + 1); 297 seencompressed = true; 298 } 299 } else { 300 ++readcursor; 301 } 302 } else { 303 uint16 word; 304 int bytesread = 0; 305 if (sscanf(readcursor, "%hx%n", &word, &bytesread) != 1) { 306 return 0; 307 } else { 308 *addr_cursor = HostToNetwork16(word); 309 ++addr_cursor; 310 readcursor += bytesread; 311 if (*readcursor != ':' && *readcursor != '\0') { 312 return 0; 313 } 314 } 315 } 316 } 317 318 if (*readcursor != '\0' || addr_cursor < addr_end) { 319 // Catches addresses too short or too long. 320 return 0; 321 } 322 memcpy(dst, &an_addr, sizeof(an_addr)); 323 return 1; 324 } 325 326 // 327 // Unix time is in seconds relative to 1/1/1970. So we compute the windows 328 // FILETIME of that time/date, then we add/subtract in appropriate units to 329 // convert to/from unix time. 330 // The units of FILETIME are 100ns intervals, so by multiplying by or dividing 331 // by 10000000, we can convert to/from seconds. 332 // 333 // FileTime = UnixTime*10000000 + FileTime(1970) 334 // UnixTime = (FileTime-FileTime(1970))/10000000 335 // 336 337 void FileTimeToUnixTime(const FILETIME& ft, time_t* ut) { 338 ASSERT(NULL != ut); 339 340 // FILETIME has an earlier date base than time_t (1/1/1970), so subtract off 341 // the difference. 342 SYSTEMTIME base_st; 343 memset(&base_st, 0, sizeof(base_st)); 344 base_st.wDay = 1; 345 base_st.wMonth = 1; 346 base_st.wYear = 1970; 347 348 FILETIME base_ft; 349 SystemTimeToFileTime(&base_st, &base_ft); 350 351 ULARGE_INTEGER base_ul, current_ul; 352 memcpy(&base_ul, &base_ft, sizeof(FILETIME)); 353 memcpy(¤t_ul, &ft, sizeof(FILETIME)); 354 355 // Divide by big number to convert to seconds, then subtract out the 1970 356 // base date value. 357 const ULONGLONG RATIO = 10000000; 358 *ut = static_cast<time_t>((current_ul.QuadPart - base_ul.QuadPart) / RATIO); 359 } 360 361 void UnixTimeToFileTime(const time_t& ut, FILETIME* ft) { 362 ASSERT(NULL != ft); 363 364 // FILETIME has an earlier date base than time_t (1/1/1970), so add in 365 // the difference. 366 SYSTEMTIME base_st; 367 memset(&base_st, 0, sizeof(base_st)); 368 base_st.wDay = 1; 369 base_st.wMonth = 1; 370 base_st.wYear = 1970; 371 372 FILETIME base_ft; 373 SystemTimeToFileTime(&base_st, &base_ft); 374 375 ULARGE_INTEGER base_ul; 376 memcpy(&base_ul, &base_ft, sizeof(FILETIME)); 377 378 // Multiply by big number to convert to 100ns units, then add in the 1970 379 // base date value. 380 const ULONGLONG RATIO = 10000000; 381 ULARGE_INTEGER current_ul; 382 current_ul.QuadPart = base_ul.QuadPart + static_cast<int64>(ut) * RATIO; 383 memcpy(ft, ¤t_ul, sizeof(FILETIME)); 384 } 385 386 bool Utf8ToWindowsFilename(const std::string& utf8, std::wstring* filename) { 387 // TODO: Integrate into fileutils.h 388 // TODO: Handle wide and non-wide cases via TCHAR? 389 // TODO: Skip \\?\ processing if the length is not > MAX_PATH? 390 // TODO: Write unittests 391 392 // Convert to Utf16 393 int wlen = ::MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), 394 static_cast<int>(utf8.length() + 1), NULL, 395 0); 396 if (0 == wlen) { 397 return false; 398 } 399 wchar_t* wfilename = STACK_ARRAY(wchar_t, wlen); 400 if (0 == ::MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), 401 static_cast<int>(utf8.length() + 1), 402 wfilename, wlen)) { 403 return false; 404 } 405 // Replace forward slashes with backslashes 406 std::replace(wfilename, wfilename + wlen, L'/', L'\\'); 407 // Convert to complete filename 408 DWORD full_len = ::GetFullPathName(wfilename, 0, NULL, NULL); 409 if (0 == full_len) { 410 return false; 411 } 412 wchar_t* filepart = NULL; 413 wchar_t* full_filename = STACK_ARRAY(wchar_t, full_len + 6); 414 wchar_t* start = full_filename + 6; 415 if (0 == ::GetFullPathName(wfilename, full_len, start, &filepart)) { 416 return false; 417 } 418 // Add long-path prefix 419 const wchar_t kLongPathPrefix[] = L"\\\\?\\UNC"; 420 if ((start[0] != L'\\') || (start[1] != L'\\')) { 421 // Non-unc path: <pathname> 422 // Becomes: \\?\<pathname> 423 start -= 4; 424 ASSERT(start >= full_filename); 425 memcpy(start, kLongPathPrefix, 4 * sizeof(wchar_t)); 426 } else if (start[2] != L'?') { 427 // Unc path: \\<server>\<pathname> 428 // Becomes: \\?\UNC\<server>\<pathname> 429 start -= 6; 430 ASSERT(start >= full_filename); 431 memcpy(start, kLongPathPrefix, 7 * sizeof(wchar_t)); 432 } else { 433 // Already in long-path form. 434 } 435 filename->assign(start); 436 return true; 437 } 438 439 bool GetOsVersion(int* major, int* minor, int* build) { 440 OSVERSIONINFO info = {0}; 441 info.dwOSVersionInfoSize = sizeof(info); 442 if (GetVersionEx(&info)) { 443 if (major) *major = info.dwMajorVersion; 444 if (minor) *minor = info.dwMinorVersion; 445 if (build) *build = info.dwBuildNumber; 446 return true; 447 } 448 return false; 449 } 450 451 bool GetCurrentProcessIntegrityLevel(int* level) { 452 bool ret = false; 453 HANDLE process = ::GetCurrentProcess(), token; 454 if (OpenProcessToken(process, TOKEN_QUERY | TOKEN_QUERY_SOURCE, &token)) { 455 DWORD size; 456 if (!GetTokenInformation(token, TokenIntegrityLevel, NULL, 0, &size) && 457 GetLastError() == ERROR_INSUFFICIENT_BUFFER) { 458 459 char* buf = STACK_ARRAY(char, size); 460 TOKEN_MANDATORY_LABEL* til = 461 reinterpret_cast<TOKEN_MANDATORY_LABEL*>(buf); 462 if (GetTokenInformation(token, TokenIntegrityLevel, til, size, &size)) { 463 464 DWORD count = *GetSidSubAuthorityCount(til->Label.Sid); 465 *level = *GetSidSubAuthority(til->Label.Sid, count - 1); 466 ret = true; 467 } 468 } 469 CloseHandle(token); 470 } 471 return ret; 472 } 473 } // namespace talk_base 474