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