/src/dovecot/src/lib/guid.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */ |
2 | | |
3 | | #include "lib.h" |
4 | | #include "ioloop.h" |
5 | | #include "buffer.h" |
6 | | #include "str.h" |
7 | | #include "sha1.h" |
8 | | #include "hash.h" |
9 | | #include "hex-binary.h" |
10 | | #include "hostpid.h" |
11 | | #include "guid.h" |
12 | | #include "randgen.h" |
13 | | |
14 | | #include <unistd.h> |
15 | | #include <time.h> |
16 | | |
17 | | const char *guid_generate(void) |
18 | 0 | { |
19 | 0 | static struct timespec ts = { 0, 0 }; |
20 | 0 | static unsigned int pid = 0; |
21 | | |
22 | | /* we'll use the current time in nanoseconds as the initial 64bit |
23 | | counter. */ |
24 | 0 | if (ts.tv_sec == 0) { |
25 | 0 | if (clock_gettime(CLOCK_REALTIME, &ts) < 0) |
26 | 0 | i_fatal("clock_gettime() failed: %m"); |
27 | 0 | pid = getpid(); |
28 | 0 | } else if ((uint32_t)ts.tv_nsec < (uint32_t)-1) { |
29 | 0 | ts.tv_nsec++; |
30 | 0 | } else { |
31 | 0 | ts.tv_sec++; |
32 | 0 | ts.tv_nsec = 0; |
33 | 0 | } |
34 | 0 | return t_strdup_printf("%08x%08lx.%x.%s", |
35 | 0 | (unsigned int)ts.tv_nsec, |
36 | 0 | (unsigned long)ts.tv_sec, |
37 | 0 | pid, my_hostname); |
38 | 0 | } |
39 | | |
40 | | void guid_128_host_hash_get(const char *host, |
41 | | unsigned char hash_r[STATIC_ARRAY GUID_128_HOST_HASH_SIZE]) |
42 | 1 | { |
43 | 1 | unsigned char full_hash[SHA1_RESULTLEN]; |
44 | | |
45 | 1 | sha1_get_digest(host, strlen(host), full_hash); |
46 | 1 | memcpy(hash_r, full_hash + sizeof(full_hash)-GUID_128_HOST_HASH_SIZE, |
47 | 1 | GUID_128_HOST_HASH_SIZE); |
48 | 1 | } |
49 | | |
50 | | void guid_128_generate(guid_128_t guid_r) |
51 | 6.42k | { |
52 | | #if GUID_128_HOST_HASH_SIZE != 4 |
53 | | # error GUID_128_HOST_HASH_SIZE must be 4 |
54 | | #endif |
55 | 6.42k | static struct timespec ts = { 0, 0 }; |
56 | 6.42k | static uint8_t guid_static[8]; |
57 | 6.42k | uint32_t pid; |
58 | | |
59 | | /* we'll use the current time in nanoseconds as the initial 64bit |
60 | | counter. */ |
61 | 6.42k | if (ts.tv_sec == 0) { |
62 | 1 | if (clock_gettime(CLOCK_REALTIME, &ts) < 0) |
63 | 0 | i_fatal("clock_gettime() failed: %m"); |
64 | 1 | pid = getpid(); |
65 | | |
66 | 1 | guid_static[0] = (pid & 0x000000ff); |
67 | 1 | guid_static[1] = (pid & 0x0000ff00) >> 8; |
68 | 1 | guid_static[2] = (pid & 0x00ff0000) >> 16; |
69 | 1 | guid_static[3] = (pid & 0xff000000) >> 24; |
70 | 1 | guid_128_host_hash_get(my_hostdomain(), guid_static+4); |
71 | 6.42k | } else if (ioloop_timeval.tv_sec > ts.tv_sec || |
72 | 6.42k | (ioloop_timeval.tv_sec == ts.tv_sec && |
73 | 6.42k | ioloop_timeval.tv_usec * 1000 > ts.tv_nsec)) { |
74 | | /* use ioloop's time since we have it. it doesn't provide any |
75 | | more uniqueness, but it allows finding out more reliably |
76 | | when a GUID was created. */ |
77 | 6.42k | ts.tv_sec = ioloop_timeval.tv_sec; |
78 | 6.42k | ts.tv_nsec = ioloop_timeval.tv_usec*1000; |
79 | 6.42k | } else if (ts.tv_nsec < 999999999L) { |
80 | 0 | ts.tv_nsec++; |
81 | 0 | } else { |
82 | 0 | ts.tv_sec++; |
83 | 0 | ts.tv_nsec = 0; |
84 | 0 | } |
85 | | |
86 | 6.42k | guid_r[0] = (ts.tv_nsec & 0x000000ff); |
87 | 6.42k | guid_r[1] = (ts.tv_nsec & 0x0000ff00) >> 8; |
88 | 6.42k | guid_r[2] = (ts.tv_nsec & 0x00ff0000) >> 16; |
89 | 6.42k | guid_r[3] = (ts.tv_nsec & 0xff000000) >> 24; |
90 | 6.42k | guid_r[4] = (ts.tv_sec & 0x000000ff); |
91 | 6.42k | guid_r[5] = (ts.tv_sec & 0x0000ff00) >> 8; |
92 | 6.42k | guid_r[6] = (ts.tv_sec & 0x00ff0000) >> 16; |
93 | 6.42k | guid_r[7] = (ts.tv_sec & 0xff000000) >> 24; |
94 | 6.42k | memcpy(guid_r + 8, guid_static, 8); |
95 | 6.42k | } |
96 | | |
97 | | void guid_128_uuid4_generate(guid_128_t uuid) |
98 | 0 | { |
99 | 0 | random_fill(uuid, sizeof(guid_128_t)); |
100 | 0 | uuid[6] = (uuid[6] & 0x0F) | 0x40; /* Set version 4 */ |
101 | 0 | uuid[8] = (uuid[8] & 0xBF) | 0x80; /* Set variant 2 (first 2 bits to 10) */ |
102 | 0 | } |
103 | | |
104 | | bool guid_128_is_empty(const guid_128_t guid) |
105 | 0 | { |
106 | 0 | unsigned int i; |
107 | |
|
108 | 0 | for (i = 0; i < GUID_128_SIZE; i++) { |
109 | 0 | if (guid[i] != 0) |
110 | 0 | return FALSE; |
111 | 0 | } |
112 | 0 | return TRUE; |
113 | 0 | } |
114 | | |
115 | | bool guid_128_equals(const guid_128_t guid1, const guid_128_t guid2) |
116 | 0 | { |
117 | 0 | return memcmp(guid1, guid2, GUID_128_SIZE) == 0; |
118 | 0 | } |
119 | | |
120 | | int guid_128_from_string(const char *str, guid_128_t guid_r) |
121 | 0 | { |
122 | 0 | buffer_t buf; |
123 | |
|
124 | 0 | buffer_create_from_data(&buf, guid_r, GUID_128_SIZE); |
125 | 0 | return strlen(str) == GUID_128_SIZE*2 && |
126 | 0 | hex_to_binary(str, &buf) == 0 && |
127 | 0 | buf.used == GUID_128_SIZE ? 0 : -1; |
128 | 0 | } |
129 | | |
130 | | const char *guid_128_to_string(const guid_128_t guid) |
131 | 0 | { |
132 | 0 | return binary_to_hex(guid, GUID_128_SIZE); |
133 | 0 | } |
134 | | |
135 | | unsigned int guid_128_hash(const guid_128_t guid) |
136 | 0 | { |
137 | 0 | return mem_hash(guid, GUID_128_SIZE); |
138 | 0 | } |
139 | | |
140 | | int guid_128_cmp(const guid_128_t guid1, const guid_128_t guid2) |
141 | 0 | { |
142 | 0 | return memcmp(guid1, guid2, GUID_128_SIZE); |
143 | 0 | } |
144 | | |
145 | | const char *guid_128_to_uuid_string(const guid_128_t guid, enum uuid_format format) |
146 | 0 | { |
147 | 0 | switch(format) { |
148 | 0 | case FORMAT_COMPACT: |
149 | 0 | return guid_128_to_string(guid); |
150 | 0 | case FORMAT_RECORD: |
151 | 0 | return t_strdup_printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", |
152 | 0 | guid[0], guid[1], guid[2], guid[3], guid[4], |
153 | 0 | guid[5], guid[6], guid[7], guid[8], guid[9], |
154 | 0 | guid[10], guid[11], guid[12], guid[13], guid[14], |
155 | 0 | guid[15]); |
156 | 0 | case FORMAT_MICROSOFT: |
157 | 0 | return t_strdup_printf("{%s}", guid_128_to_uuid_string(guid, FORMAT_RECORD)); |
158 | 0 | } |
159 | 0 | i_unreached(); |
160 | 0 | } |
161 | | |
162 | | int guid_128_from_uuid_string(const char *str, guid_128_t guid_r) |
163 | 0 | { |
164 | 0 | size_t i,len,m=0; |
165 | 0 | int ret; |
166 | 0 | T_BEGIN { |
167 | 0 | len = strlen(str); |
168 | 0 | string_t *str2 = t_str_new(len); |
169 | 0 | for(i=0; i < len; i++) { |
170 | | /* Microsoft format */ |
171 | 0 | if (i==0 && str[i] == '{') { m=1; continue; } |
172 | 0 | else if (i == len-1 && str[i] == '}') continue; |
173 | | /* 8-4-4-4-12 */ |
174 | 0 | if (((i==8+m) || (i==13+m) || (i==18+m) || (i==23+m)) && |
175 | 0 | str[i] == '-') continue; |
176 | 0 | str_append_c(str2, str[i]); |
177 | 0 | } |
178 | 0 | ret = guid_128_from_string(str_c(str2), guid_r); |
179 | 0 | } T_END; |
180 | | |
181 | 0 | return ret; |
182 | 0 | } |