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:
BytesToUInt32(const uint8_t bytes[])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
UInt32ToBytes(uint8_t bytes[],uint32_t n)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
CreateGUID(GUID * guid)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
CreateGuidFromArc4Random(GUID * guid)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
CreateGUID(GUID * guid)172 bool CreateGUID(GUID *guid) {
173 return GUIDGenerator::CreateGUID(guid);
174 }
175
176 // Parse guid to string.
GUIDToString(const GUID * guid,char * buf,int buf_len)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