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