Add an \extref doxygen pointer for libuuid.
[asterisk/asterisk.git] / main / uuid.c
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
35 AST_MUTEX_DEFINE_STATIC(uuid_lock);
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  * \return Nothing
51  */
52 static void generate_uuid(struct ast_uuid *uuid)
53 {
54         /* libuuid provides three methods of generating uuids,
55          * uuid_generate(), uuid_generate_random(), and uuid_generate_time().
56          *
57          * uuid_generate_random() creates a UUID based on random numbers. The method
58          * attempts to use either /dev/urandom or /dev/random to generate random values.
59          * If these resources are unavailable, then random numbers will be generated
60          * using C library calls to generate pseudorandom numbers.
61          * This method of generating UUIDs corresponds to section 4.4 of RFC 4122.
62          *
63          * uuid_generate_time() creates a UUID based on the current time plus
64          * a system identifier (MAC address of the ethernet interface). This
65          * method of generating UUIDs corresponds to section 4.2 of RFC 4122.
66          *
67          * uuid_generate() will check if /dev/urandom or /dev/random is available to
68          * use. If so, it will use uuid_generate_random(). Otherwise, it will use
69          * uuid_generate_time(). The idea is that it avoids using pseudorandom
70          * numbers if necessary.
71          *
72          * For our purposes, we do not use the time-based UUID at all. There are
73          * several reasons for this:
74          *
75          * 1) The time-based algorithm makes use of a daemon process (uuidd) in order
76          * to ensure that any concurrent requests for UUIDs result in unique results.
77          * Use of this daemon is a bit dodgy for a few reasons
78          *
79          *     a) libuuid assumes a hardcoded location for the .pid file of the daemon.
80          *     However, the daemon could already be running on the system in a different
81          *     location than expected. If this is the case, then attempting to connect
82          *     to the daemon will fail, and attempting to launch another instance in
83          *     the expected location will also fail.
84          *
85          *     b) If the daemon is not running, then the first attempt to create a
86          *     time-based UUID will result in launching the daemon. Because of the hard-
87          *     coded locations that libuuid assumes for the daemon, Asterisk must be
88          *     run with permissions that will allow for the daemon to be launched in
89          *     the expected directories.
90          *
91          *     c) Once the daemon is running, concurrent requests for UUIDs are thread-safe.
92          *     However, the actual launching of the daemon is not thread-safe since libuuid
93          *     uses no synchronization primitives to ensure that only one thread (or process)
94          *     launches the daemon.
95          *
96          *     d) When libuuid launches the daemon, it sets an inactivity timer.
97          *     If no UUID generation requests are issued in that time period,
98          *     then the daemon will exit. If a new request should occur after the daemon
99          *     exits, then the daemon will be relaunched. Given point c), we cannot
100          *     necessarily guarantee the thread-safety of time-based UUID generation since
101          *     we cannot necessarily guarantee the daemon is running as we expect.
102          *     We could set up a watchdog thread to generate UUIDs at regular intervals to
103          *     prevent the daemon from exiting, but frankly, that sucks.
104          *
105          * 2) Since the MAC address of the Ethernet interface is part of the UUID when
106          * using the time-based method, there is information leaked.
107          *
108          * Given these drawbacks, we stick to only using random UUIDs. The chance of /dev/random
109          * or /dev/urandom not existing on systems in this age is next to none.
110          */
111
112         /* XXX Currently, we only protect this call if the user has no /dev/urandon on their system.
113          * If it turns out that there are issues with UUID generation despite the presence of
114          * /dev/urandom, then we may need to make the locking/unlocking unconditional.
115          */
116         if (!has_dev_urandom) {
117                 ast_mutex_lock(&uuid_lock);
118         }
119         uuid_generate_random(uuid->uu);
120         if (!has_dev_urandom) {
121                 ast_mutex_unlock(&uuid_lock);
122         }
123 }
124
125 struct ast_uuid *ast_uuid_generate(void)
126 {
127         struct ast_uuid *uuid = ast_malloc(sizeof(*uuid));
128
129         if (!uuid) {
130                 return NULL;
131         }
132         generate_uuid(uuid);
133         return uuid;
134 }
135
136 char *ast_uuid_to_str(const struct ast_uuid *uuid, char *buf, size_t size)
137 {
138         ast_assert(size >= AST_UUID_STR_LEN);
139         uuid_unparse_lower(uuid->uu, buf);
140         return buf;
141 }
142
143 char *ast_uuid_generate_str(char *buf, size_t size)
144 {
145         struct ast_uuid uuid;
146
147         generate_uuid(&uuid);
148         return ast_uuid_to_str(&uuid, buf, size);
149 }
150
151 struct ast_uuid *ast_str_to_uuid(const char *str)
152 {
153         struct ast_uuid *uuid = ast_malloc(sizeof(*uuid));
154         int res;
155
156         if (!uuid) {
157                 return NULL;
158         }
159         res = uuid_parse(str, uuid->uu);
160         if (res) {
161                 ast_log(LOG_WARNING, "Unable to convert string %s into a UUID\n", str);
162                 ast_free(uuid);
163                 return NULL;
164         }
165         return uuid;
166 }
167
168 struct ast_uuid *ast_uuid_copy(const struct ast_uuid *src)
169 {
170         struct ast_uuid *dst = ast_malloc(sizeof(*dst));
171
172         if (!dst) {
173                 return NULL;
174         }
175         uuid_copy(dst->uu, src->uu);
176         return dst;
177 }
178
179 int ast_uuid_compare(const struct ast_uuid *left, const struct ast_uuid *right)
180 {
181         return uuid_compare(left->uu, right->uu);
182 }
183
184 void ast_uuid_clear(struct ast_uuid *uuid)
185 {
186         uuid_clear(uuid->uu);
187 }
188
189 int ast_uuid_is_nil(const struct ast_uuid *uuid)
190 {
191         return uuid_is_null(uuid->uu);
192 }
193
194 void ast_uuid_init(void)
195 {
196         /* This requires some explanation.
197          *
198          * libuuid generates UUIDs based on random number generation. This involves
199          * opening a handle to /dev/urandom or /dev/random in order to get random
200          * data for the UUIDs.
201          *
202          * This is thread-safe, to a point. The problem is that the first attempt
203          * to generate a UUID will result in opening the random number handle. Once
204          * the handle is opened, all further generation is thread safe. This
205          * first generation can be potentially risky if multiple threads attempt
206          * to generate a UUID at the same time, though, since there is no thread
207          * synchronization used within libuuid. To get around this potential
208          * issue, we go ahead and generate a UUID up front so that the underlying
209          * work is done before we start requesting UUIDs for real.
210          *
211          * Think of this along the same lines as initializing a singleton.
212          */
213         uuid_t uu;
214         int dev_urandom_fd;
215
216         dev_urandom_fd = open("/dev/urandom", O_RDONLY);
217         if (dev_urandom_fd < 0) {
218                 ast_log(LOG_WARNING, "It appears your system does not have /dev/urandom on it. This\n"
219                                 "means that UUID generation will use a pseudorandom number generator. Since\n"
220                                 "the thread-safety of your system's random number generator cannot\n"
221                                 "be guaranteed, we have to synchronize UUID generation. This may result\n"
222                                 "in decreased performance. It is highly recommended that you set up your\n"
223                                 "system to have /dev/urandom\n");
224         } else {
225                 has_dev_urandom = 1;
226                 close(dev_urandom_fd);
227         }
228         uuid_generate_random(uu);
229
230         ast_debug(1, "UUID system initiated\n");
231 }