Asterisk - The Open Source Telephony Project  GIT-master-a24979a
uuid.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2012, Digium, Inc.
5  *
6  * Mark Michelson <mmmichelson@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*! \file
20  * \brief Universally unique identifier support
21  *
22  * \extref Depends on libuuid, a component of the e2fsprogs package - http://e2fsprogs.sourceforge.net/
23  */
24 
25 #include "asterisk.h"
26 #include <uuid/uuid.h>
27 #include <fcntl.h>
28 
29 #include "asterisk/uuid.h"
30 #include "asterisk/utils.h"
31 #include "asterisk/strings.h"
32 #include "asterisk/logger.h"
33 #include "asterisk/lock.h"
34 
36 
37 static int has_dev_urandom;
38 
39 struct ast_uuid {
40  uuid_t uu;
41 };
42 
43 /*!
44  * \internal
45  * \brief Generate a UUID.
46  * \since 12.0.0
47  *
48  * \param uuid Fill this with a generated UUID.
49  */
50 static void generate_uuid(struct ast_uuid *uuid)
51 {
52  /* libuuid provides three methods of generating uuids,
53  * uuid_generate(), uuid_generate_random(), and uuid_generate_time().
54  *
55  * uuid_generate_random() creates a UUID based on random numbers. The method
56  * attempts to use either /dev/urandom or /dev/random to generate random values.
57  * If these resources are unavailable, then random numbers will be generated
58  * using C library calls to generate pseudorandom numbers.
59  * This method of generating UUIDs corresponds to section 4.4 of RFC 4122.
60  *
61  * uuid_generate_time() creates a UUID based on the current time plus
62  * a system identifier (MAC address of the ethernet interface). This
63  * method of generating UUIDs corresponds to section 4.2 of RFC 4122.
64  *
65  * uuid_generate() will check if /dev/urandom or /dev/random is available to
66  * use. If so, it will use uuid_generate_random(). Otherwise, it will use
67  * uuid_generate_time(). The idea is that it avoids using pseudorandom
68  * numbers if necessary.
69  *
70  * For our purposes, we do not use the time-based UUID at all. There are
71  * several reasons for this:
72  *
73  * 1) The time-based algorithm makes use of a daemon process (uuidd) in order
74  * to ensure that any concurrent requests for UUIDs result in unique results.
75  * Use of this daemon is a bit dodgy for a few reasons
76  *
77  * a) libuuid assumes a hardcoded location for the .pid file of the daemon.
78  * However, the daemon could already be running on the system in a different
79  * location than expected. If this is the case, then attempting to connect
80  * to the daemon will fail, and attempting to launch another instance in
81  * the expected location will also fail.
82  *
83  * b) If the daemon is not running, then the first attempt to create a
84  * time-based UUID will result in launching the daemon. Because of the hard-
85  * coded locations that libuuid assumes for the daemon, Asterisk must be
86  * run with permissions that will allow for the daemon to be launched in
87  * the expected directories.
88  *
89  * c) Once the daemon is running, concurrent requests for UUIDs are thread-safe.
90  * However, the actual launching of the daemon is not thread-safe since libuuid
91  * uses no synchronization primitives to ensure that only one thread (or process)
92  * launches the daemon.
93  *
94  * d) When libuuid launches the daemon, it sets an inactivity timer.
95  * If no UUID generation requests are issued in that time period,
96  * then the daemon will exit. If a new request should occur after the daemon
97  * exits, then the daemon will be relaunched. Given point c), we cannot
98  * necessarily guarantee the thread-safety of time-based UUID generation since
99  * we cannot necessarily guarantee the daemon is running as we expect.
100  * We could set up a watchdog thread to generate UUIDs at regular intervals to
101  * prevent the daemon from exiting, but frankly, that sucks.
102  *
103  * 2) Since the MAC address of the Ethernet interface is part of the UUID when
104  * using the time-based method, there is information leaked.
105  *
106  * Given these drawbacks, we stick to only using random UUIDs. The chance of /dev/random
107  * or /dev/urandom not existing on systems in this age is next to none.
108  */
109 
110  /* XXX Currently, we only protect this call if the user has no /dev/urandom on their system.
111  * If it turns out that there are issues with UUID generation despite the presence of
112  * /dev/urandom, then we may need to make the locking/unlocking unconditional.
113  */
114  if (!has_dev_urandom) {
116  }
117  uuid_generate_random(uuid->uu);
118  if (!has_dev_urandom) {
120  }
121 }
122 
124 {
125  struct ast_uuid *uuid = ast_malloc(sizeof(*uuid));
126 
127  if (!uuid) {
128  return NULL;
129  }
130  generate_uuid(uuid);
131  return uuid;
132 }
133 
134 char *ast_uuid_to_str(struct ast_uuid *uuid, char *buf, size_t size)
135 {
136  ast_assert(size >= AST_UUID_STR_LEN);
137  uuid_unparse(uuid->uu, buf);
138  return ast_str_to_lower(buf);
139 }
140 
141 char *ast_uuid_generate_str(char *buf, size_t size)
142 {
143  struct ast_uuid uuid;
144 
145  generate_uuid(&uuid);
146  return ast_uuid_to_str(&uuid, buf, size);
147 }
148 
150 {
151  struct ast_uuid *uuid = ast_malloc(sizeof(*uuid));
152  int res;
153 
154  if (!uuid) {
155  return NULL;
156  }
157  res = uuid_parse(str, uuid->uu);
158  if (res) {
159  ast_log(LOG_WARNING, "Unable to convert string %s into a UUID\n", str);
160  ast_free(uuid);
161  return NULL;
162  }
163  return uuid;
164 }
165 
166 struct ast_uuid *ast_uuid_copy(struct ast_uuid *src)
167 {
168  struct ast_uuid *dst = ast_malloc(sizeof(*dst));
169 
170  if (!dst) {
171  return NULL;
172  }
173  uuid_copy(dst->uu, src->uu);
174  return dst;
175 }
176 
177 int ast_uuid_compare(struct ast_uuid *left, struct ast_uuid *right)
178 {
179  return uuid_compare(left->uu, right->uu);
180 }
181 
182 void ast_uuid_clear(struct ast_uuid *uuid)
183 {
184  uuid_clear(uuid->uu);
185 }
186 
187 int ast_uuid_is_nil(struct ast_uuid *uuid)
188 {
189  return uuid_is_null(uuid->uu);
190 }
191 
192 void ast_uuid_init(void)
193 {
194  /* This requires some explanation.
195  *
196  * libuuid generates UUIDs based on random number generation. This involves
197  * opening a handle to /dev/urandom or /dev/random in order to get random
198  * data for the UUIDs.
199  *
200  * This is thread-safe, to a point. The problem is that the first attempt
201  * to generate a UUID will result in opening the random number handle. Once
202  * the handle is opened, all further generation is thread safe. This
203  * first generation can be potentially risky if multiple threads attempt
204  * to generate a UUID at the same time, though, since there is no thread
205  * synchronization used within libuuid. To get around this potential
206  * issue, we go ahead and generate a UUID up front so that the underlying
207  * work is done before we start requesting UUIDs for real.
208  *
209  * Think of this along the same lines as initializing a singleton.
210  */
211  uuid_t uu;
212  int dev_urandom_fd;
213 
214  dev_urandom_fd = open("/dev/urandom", O_RDONLY);
215  if (dev_urandom_fd < 0) {
216  ast_log(LOG_WARNING, "It appears your system does not have /dev/urandom on it. This\n"
217  "means that UUID generation will use a pseudorandom number generator. Since\n"
218  "the thread-safety of your system's random number generator cannot\n"
219  "be guaranteed, we have to synchronize UUID generation. This may result\n"
220  "in decreased performance. It is highly recommended that you set up your\n"
221  "system to have /dev/urandom\n");
222  } else {
223  has_dev_urandom = 1;
224  close(dev_urandom_fd);
225  }
226  uuid_generate_random(uu);
227 
228  ast_debug(1, "UUID system initiated\n");
229 }
const char * str
Definition: app_jack.c:147
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
#define ast_log
Definition: astobj2.c:42
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
Support for logging to various files, console and syslog Configuration in file logger....
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_WARNING
Asterisk locking-related definitions:
#define ast_mutex_unlock(a)
Definition: lock.h:188
#define ast_mutex_lock(a)
Definition: lock.h:187
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:518
static int dev_urandom_fd
Definition: main/utils.c:938
#define NULL
Definition: resample.c:96
String manipulation functions.
static force_inline char * ast_str_to_lower(char *str)
Convert a string to all lower-case.
Definition: strings.h:1299
Definition: uuid.c:39
uuid_t uu
Definition: uuid.c:40
Utility functions.
#define ast_assert(a)
Definition: utils.h:734
int ast_uuid_compare(struct ast_uuid *left, struct ast_uuid *right)
Compare two UUIDs.
Definition: uuid.c:177
void ast_uuid_init(void)
Initialize the UUID system.
Definition: uuid.c:192
static ast_mutex_t uuid_lock
Definition: uuid.c:35
static void generate_uuid(struct ast_uuid *uuid)
Definition: uuid.c:50
struct ast_uuid * ast_str_to_uuid(char *str)
Convert a string to a UUID.
Definition: uuid.c:149
static int has_dev_urandom
Definition: uuid.c:37
struct ast_uuid * ast_uuid_copy(struct ast_uuid *src)
Make a copy of a UUID.
Definition: uuid.c:166
void ast_uuid_clear(struct ast_uuid *uuid)
Clear a UUID by setting it to be a nil UUID (all 0s)
Definition: uuid.c:182
struct ast_uuid * ast_uuid_generate(void)
Generate a UUID.
Definition: uuid.c:123
char * ast_uuid_to_str(struct ast_uuid *uuid, char *buf, size_t size)
Convert a UUID to a string.
Definition: uuid.c:134
char * ast_uuid_generate_str(char *buf, size_t size)
Generate a UUID string.
Definition: uuid.c:141
int ast_uuid_is_nil(struct ast_uuid *uuid)
Check if a UUID is a nil UUID (all 0s)
Definition: uuid.c:187
Universally unique identifier support.
#define AST_UUID_STR_LEN
Definition: uuid.h:27