1 /*
2 * TV headend - UUID generation routines
3 *
4 * Copyright (C) 2014 Adam Sutton
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "tvheadend.h"
21 #include "uuid.h"
22
23 #include <stdint.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27
28 #define RANDOM_PATH "/dev/urandom"
29
30 uint8_t ___uuid_empty[UUID_BIN_SIZE] = { 0 };
31
32 static int fd = -1;
33
34 /* **************************************************************************
35 * Utilities
36 * *************************************************************************/
37
38 /**
39 *
40 */
41 static inline int
hexnibble(char c)42 hexnibble(char c)
43 {
44 switch(c) {
45 case '0' ... '9': return c - '0';
46 case 'a' ... 'f': return c - 'a' + 10;
47 case 'A' ... 'F': return c - 'A' + 10;
48 default:
49 return -1;
50 }
51 }
52
53
54 /**
55 *
56 */
57 int
hex2bin(uint8_t * buf,size_t buflen,const char * str)58 hex2bin(uint8_t *buf, size_t buflen, const char *str)
59 {
60 int hi, lo;
61
62 while(*str) {
63 if(buflen == 0)
64 return -1;
65 if((hi = hexnibble(*str++)) == -1)
66 return -1;
67 if((lo = hexnibble(*str++)) == -1)
68 return -1;
69
70 *buf++ = hi << 4 | lo;
71 buflen--;
72 }
73 return 0;
74 }
75
76 /**
77 *
78 */
79 void
bin2hex(char * dst,size_t dstlen,const uint8_t * src,size_t srclen)80 bin2hex(char *dst, size_t dstlen, const uint8_t *src, size_t srclen)
81 {
82 while(dstlen > 2 && srclen > 0) {
83 *dst++ = "0123456789abcdef"[*src >> 4];
84 *dst++ = "0123456789abcdef"[*src & 0xf];
85 src++;
86 srclen--;
87 dstlen -= 2;
88 }
89 *dst = 0;
90 }
91
92 /* **************************************************************************
93 * UUID Handling
94 * *************************************************************************/
95
96 void
uuid_init(void)97 uuid_init ( void )
98 {
99 fd = tvh_open(RANDOM_PATH, O_RDONLY, 0);
100 if (fd == -1) {
101 tvherror(LS_UUID, "failed to open %s", RANDOM_PATH);
102 exit(1);
103 }
104 }
105
106 void
uuid_random(uint8_t * buf,size_t bufsize)107 uuid_random ( uint8_t *buf, size_t bufsize )
108 {
109 if (read(fd, buf, bufsize) != bufsize) {
110 tvherror(LS_UUID, "random failed: %s", strerror(errno));
111 exit(1);
112 }
113 }
114
115 /* Initialise binary */
116 int
uuid_init_bin(tvh_uuid_t * u,const char * str)117 uuid_init_bin ( tvh_uuid_t *u, const char *str )
118 {
119 memset(u, 0, sizeof(tvh_uuid_t));
120 if (str) {
121 if (strlen(str) != UUID_HEX_SIZE - 1) {
122 tvherror(LS_UUID, "wrong uuid size");
123 return -EINVAL;
124 }
125 return hex2bin(u->bin, sizeof(u->bin), str);
126 } else if (read(fd, u->bin, sizeof(u->bin)) != sizeof(u->bin)) {
127 tvherror(LS_UUID, "failed to read from %s", RANDOM_PATH);
128 return -EINVAL;
129 }
130 return 0;
131 }
132
133 /* Initialise hex string */
134 int
uuid_init_hex(tvh_uuid_t * u,const char * str)135 uuid_init_hex ( tvh_uuid_t *u, const char *str )
136 {
137 tvh_uuid_t tmp;
138 if (uuid_init_bin(&tmp, str))
139 return 1;
140 return uuid_bin2hex(&tmp, u);
141 }
142
143 /* Convert bin to hex string */
144 int
uuid_bin2hex(const tvh_uuid_t * a,tvh_uuid_t * b)145 uuid_bin2hex ( const tvh_uuid_t *a, tvh_uuid_t *b )
146 {
147 tvh_uuid_t tmp;
148 memset(&tmp, 0, sizeof(tmp));
149 bin2hex(tmp.hex, sizeof(tmp.hex), a->bin, sizeof(a->bin));
150 memcpy(b, &tmp, sizeof(tmp));
151 return 0;
152 }
153
154 /* Convert hex string to bin (in place) */
155 int
uuid_hex2bin(const tvh_uuid_t * a,tvh_uuid_t * b)156 uuid_hex2bin ( const tvh_uuid_t *a, tvh_uuid_t *b )
157 {
158 tvh_uuid_t tmp;
159 memset(&tmp, 0, sizeof(tmp));
160 if (hex2bin(tmp.bin, sizeof(tmp.bin), a->hex))
161 return 1;
162 memcpy(b, &tmp, sizeof(tmp));
163 return 0;
164 }
165
166 /* Validate hex string */
167 int
uuid_hexvalid(const char * uuid)168 uuid_hexvalid ( const char *uuid )
169 {
170 int i;
171 if (uuid == NULL)
172 return 0;
173 for (i = 0; i < UUID_HEX_SIZE - 1; i++)
174 if (hexnibble(uuid[i]) < 0)
175 return 0;
176 return 1;
177 }
178