guid_creator.cc
1 // Copyright 2006 Google LLC 2 // 3 // Redistribution and use in source and binary forms, with or without 4 // modification, are permitted provided that the following conditions are 5 // met: 6 // 7 // * Redistributions of source code must retain the above copyright 8 // notice, this list of conditions and the following disclaimer. 9 // * Redistributions in binary form must reproduce the above 10 // copyright notice, this list of conditions and the following disclaimer 11 // in the documentation and/or other materials provided with the 12 // distribution. 13 // * Neither the name of Google LLC nor the names of its 14 // contributors may be used to endorse or promote products derived from 15 // this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 #ifdef HAVE_CONFIG_H 30 #include <config.h> // Must come first 31 #endif 32 33 #include "common/linux/eintr_wrapper.h" 34 #include "common/linux/guid_creator.h" 35 36 #include <assert.h> 37 #include <fcntl.h> 38 #include <pthread.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <sys/stat.h> 43 #include <time.h> 44 #include <unistd.h> 45 46 #if defined(HAVE_SYS_RANDOM_H) 47 #include <sys/random.h> 48 #endif 49 50 // 51 // GUIDGenerator 52 // 53 // This class is used to generate random GUID. 54 // Currently use random number to generate a GUID since Linux has 55 // no native GUID generator. This should be OK since we don't expect 56 // crash to happen very offen. 57 // 58 class GUIDGenerator { 59 public: 60 static uint32_t BytesToUInt32(const uint8_t bytes[]) { 61 return ((uint32_t) bytes[0] 62 | ((uint32_t) bytes[1] << 8) 63 | ((uint32_t) bytes[2] << 16) 64 | ((uint32_t) bytes[3] << 24)); 65 } 66 67 static void UInt32ToBytes(uint8_t bytes[], uint32_t n) { 68 bytes[0] = n & 0xff; 69 bytes[1] = (n >> 8) & 0xff; 70 bytes[2] = (n >> 16) & 0xff; 71 bytes[3] = (n >> 24) & 0xff; 72 } 73 74 static bool CreateGUID(GUID *guid) { 75 #if defined(HAVE_ARC4RANDOM) // Android, BSD, ... 76 CreateGuidFromArc4Random(guid); 77 #else // Linux 78 bool success = false; 79 80 #if defined(HAVE_SYS_RANDOM_H) && defined(HAVE_GETRANDOM) 81 success = CreateGUIDFromGetrandom(guid); 82 #endif // HAVE_SYS_RANDOM_H && HAVE_GETRANDOM 83 if (!success) { 84 success = CreateGUIDFromDevUrandom(guid); 85 } 86 87 if (!success) { 88 CreateGUIDFromRand(guid); 89 success = true; 90 } 91 #endif 92 93 // Put in the version according to RFC 4122. 94 guid->data3 &= 0x0fff; 95 guid->data3 |= 0x4000; 96 97 // Put in the variant according to RFC 4122. 98 guid->data4[0] &= 0x3f; 99 guid->data4[0] |= 0x80; 100 101 return true; 102 } 103 104 private: 105 #ifdef HAVE_ARC4RANDOM 106 static void CreateGuidFromArc4Random(GUID *guid) { 107 char *buf = reinterpret_cast<char*>(guid); 108 109 for (size_t i = 0; i < sizeof(GUID); i += sizeof(uint32_t)) { 110 uint32_t random_data = arc4random(); 111 112 memcpy(buf + i, &random_data, sizeof(uint32_t)); 113 } 114 } 115 #else 116 static void InitOnce() { 117 pthread_once(&once_control, &InitOnceImpl); 118 } 119 120 static void InitOnceImpl() { 121 // time(NULL) is a very poor seed, so lacking anything better mix an 122 // address into it. We drop the four rightmost bits as they're likely to 123 // be 0 on almost all architectures. 124 srand(time(NULL) | ((uintptr_t)&once_control >> 4)); 125 } 126 127 static pthread_once_t once_control; 128 129 #if defined(HAVE_SYS_RANDOM_H) && defined(HAVE_GETRANDOM) 130 static bool CreateGUIDFromGetrandom(GUID *guid) { 131 char *buf = reinterpret_cast<char*>(guid); 132 int read_bytes = getrandom(buf, sizeof(GUID), GRND_NONBLOCK); 133 134 return (read_bytes == static_cast<int>(sizeof(GUID))); 135 } 136 #endif // HAVE_SYS_RANDOM_H && HAVE_GETRANDOM 137 138 // Populate the GUID using random bytes read from /dev/urandom, returns false 139 // if the GUID wasn't fully populated with random data. 140 static bool CreateGUIDFromDevUrandom(GUID *guid) { 141 char *buf = reinterpret_cast<char*>(guid); 142 int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); 143 144 if (fd == -1) { 145 return false; 146 } 147 148 ssize_t read_bytes = HANDLE_EINTR(read(fd, buf, sizeof(GUID))); 149 close(fd); 150 151 return (read_bytes == static_cast<ssize_t>(sizeof(GUID))); 152 } 153 154 // Populate the GUID using a stream of random bytes obtained from rand(). 155 static void CreateGUIDFromRand(GUID *guid) { 156 char *buf = reinterpret_cast<char*>(guid); 157 158 InitOnce(); 159 160 for (size_t i = 0; i < sizeof(GUID); i++) { 161 buf[i] = rand(); 162 } 163 } 164 #endif 165 }; 166 167 #ifndef HAVE_ARC4RANDOM 168 pthread_once_t GUIDGenerator::once_control = PTHREAD_ONCE_INIT; 169 #endif 170 171 bool CreateGUID(GUID *guid) { 172 return GUIDGenerator::CreateGUID(guid); 173 } 174 175 // Parse guid to string. 176 bool GUIDToString(const GUID *guid, char *buf, int buf_len) { 177 // Should allow more space the the max length of GUID. 178 assert(buf_len > kGUIDStringLength); 179 int num = snprintf(buf, buf_len, kGUIDFormatString, 180 guid->data1, guid->data2, guid->data3, 181 GUIDGenerator::BytesToUInt32(&(guid->data4[0])), 182 GUIDGenerator::BytesToUInt32(&(guid->data4[4]))); 183 if (num != kGUIDStringLength) 184 return false; 185 186 buf[num] = '\0'; 187 return true; 188 }