/ src / common / linux / guid_creator.cc
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  }