]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/base64.c
Add temporary fix to avoid a deadlock after a reload command on an incorrect configur...
[bacula/bacula] / bacula / src / lib / base64.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2016 Kern Sibbald
5
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    This notice must be preserved when any source code is 
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  *   Generic base 64 input and output routines
21  *
22  *    Written by Kern E. Sibbald, March MM.
23  *
24  *   Version $Id$
25  */
26
27
28 #include "bacula.h"
29
30
31 #ifdef TEST_MODE
32 #include <glob.h>
33 #endif
34
35
36 static uint8_t const base64_digits[64] =
37 {
38   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
39   'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
40   'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
41   'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
42   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
43 };
44
45 static int base64_inited = 0;
46 static uint8_t base64_map[256];
47
48
49 /* Initialize the Base 64 conversion routines */
50 void
51 base64_init(void)
52 {
53    int i;
54    memset(base64_map, 0, sizeof(base64_map));
55    for (i=0; i<64; i++)
56       base64_map[(uint8_t)base64_digits[i]] = i;
57    base64_inited = 1;
58 }
59
60 /* Convert a value to base64 characters.
61  * The result is stored in where, which
62  * must be at least 8 characters long.
63  *
64  * Returns the number of characters
65  * stored (not including the EOS).
66  */
67 int
68 to_base64(int64_t value, char *where)
69 {
70    uint64_t val;
71    int i = 0;
72    int n;
73
74    /* Handle negative values */
75    if (value < 0) {
76       where[i++] = '-';
77       value = -value;
78    }
79
80    /* Determine output size */
81    val = value;
82    do {
83       val >>= 6;
84       i++;
85    } while (val);
86    n = i;
87
88    /* Output characters */
89    val = value;
90    where[i] = 0;
91    do {
92       where[--i] = base64_digits[val & (uint64_t)0x3F];
93       val >>= 6;
94    } while (val);
95    return n;
96 }
97
98 /*
99  * Convert the Base 64 characters in where to
100  * a value. No checking is done on the validity
101  * of the characters!!
102  *
103  * Returns the value.
104  */
105 int
106 from_base64(int64_t *value, char *where)
107 {
108    uint64_t val = 0;
109    int i, neg;
110
111    if (!base64_inited)
112       base64_init();
113    /* Check if it is negative */
114    i = neg = 0;
115    if (where[i] == '-') {
116       i++;
117       neg = 1;
118    }
119    /* Construct value */
120    while (where[i] != 0 && where[i] != ' ') {
121       val <<= 6;
122       val += base64_map[(uint8_t)where[i++]];
123    }
124
125    *value = neg ? -(int64_t)val : (int64_t)val;
126    return i;
127 }
128
129
130 /*
131  * Encode binary data in bin of len bytes into
132  * buf as base64 characters.
133  *
134  * If compatible is true, the bin_to_base64 routine will be compatible
135  * with what the rest of the world uses.
136  *
137  *  Returns: the number of characters stored not
138  *           including the EOS
139  */
140 int
141 bin_to_base64(char *buf, int buflen, char *bin, int binlen, int compatible)
142 {
143    uint32_t reg, save, mask;
144    int rem, i;
145    int j = 0;
146
147    reg = 0;
148    rem = 0;
149    buflen--;                       /* allow for storing EOS */
150    for (i=0; i < binlen; ) {
151       if (rem < 6) {
152          reg <<= 8;
153          if (compatible) {
154             reg |= (uint8_t)bin[i++];
155          } else {
156             reg |= (int8_t)bin[i++];
157          }
158          rem += 8;
159       }
160       save = reg;
161       reg >>= (rem - 6);
162       if (j < buflen) {
163          buf[j++] = base64_digits[reg & 0x3F];
164       }
165       reg = save;
166       rem -= 6;
167    }
168    if (rem && j < buflen) {
169       mask = (1 << rem) - 1;
170       if (compatible) {
171          buf[j++] = base64_digits[(reg & mask) << (6 - rem)];
172       } else {
173          buf[j++] = base64_digits[reg & mask];
174       }
175    }
176    buf[j] = 0;
177    return j;
178 }
179
180 /*
181  * Decode base64 data in bin of len bytes into
182  * buf as binary characters.
183  *
184  * the base64_to_bin routine is compatible with what the rest of the world
185  * uses.
186  *
187  *  Returns: the number of characters stored not
188  *           including the EOS
189  */
190 int base64_to_bin(char *dest, int dest_size, char *src, int srclen)
191 {
192    int nprbytes;
193    uint8_t *bufout;
194    uint8_t *bufplain = (uint8_t*) dest;
195    const uint8_t *bufin;
196
197    if (!base64_inited)
198       base64_init();
199
200    if (dest_size < (((srclen + 3) / 4) * 3)) {
201       /* dest buffer too small */
202       *dest = 0;
203       return 0;
204    }
205
206    bufin = (const uint8_t *) src;
207    while ((*bufin != ' ') && (srclen != 0)) {
208       bufin++;
209       srclen--;
210    }
211
212    nprbytes = bufin - (const uint8_t *) src;
213    bufin = (const uint8_t *) src;
214    bufout = (uint8_t *) bufplain;
215
216    while (nprbytes > 4)
217    {
218       *(bufout++) = (base64_map[bufin[0]] << 2 | base64_map[bufin[1]] >> 4);
219       *(bufout++) = (base64_map[bufin[1]] << 4 | base64_map[bufin[2]] >> 2);
220       *(bufout++) = (base64_map[bufin[2]] << 6 | base64_map[bufin[3]]);
221       bufin += 4;
222       nprbytes -= 4;
223    }
224
225    /* Bacula base64 strings are not always padded with = */
226    if (nprbytes > 1) {
227       *(bufout++) = (base64_map[bufin[0]] << 2 | base64_map[bufin[1]] >> 4);
228    }
229    if (nprbytes > 2) {
230       *(bufout++) = (base64_map[bufin[1]] << 4 | base64_map[bufin[2]] >> 2);
231    }
232    if (nprbytes > 3) {
233       *(bufout++) = (base64_map[bufin[2]] << 6 | base64_map[bufin[3]]);
234    }
235    *bufout = 0;
236
237    return (bufout - (uint8_t *) dest);
238 }
239
240 #ifdef BIN_TEST
241 int main(int argc, char *argv[])
242 {
243    int len;
244    char buf[100];
245    char junk[100];
246    int i;
247
248 #ifdef xxxx
249    int xx = 0;
250    for (i=0; i < 1000; i++) {
251       bin_to_base64(buf, sizeof(buf), (char *)&xx, 4, true);
252       printf("xx=%s\n", buf);
253       xx++;
254    }
255 #endif
256    junk[0] = 0xFF;
257    for (i=1; i<100; i++) {
258       junk[i] = junk[i-1]-1;
259    }
260    len = bin_to_base64(buf, sizeof(buf), junk, 16, true);
261    printf("len=%d junk=%s\n", len, buf);
262
263    strcpy(junk, "This is a sample stringa");
264    len = bin_to_base64(buf, sizeof(buf), junk, strlen(junk), true);
265    buf[len] = 0;
266    base64_to_bin(junk, sizeof(junk), buf, len);
267    printf("buf=<%s>\n", junk);
268    return 0;
269 }
270 #endif
271
272 #ifdef TEST_MODE
273 static int errfunc(const char *epath, int eernoo)
274 {
275   printf("in errfunc\n");
276   return 1;
277 }
278
279
280 /*
281  * Test the base64 routines by encoding and decoding
282  * lstat() packets.
283  */
284 int main(int argc, char *argv[])
285 {
286    char where[500];
287    int i;
288    glob_t my_glob;
289    char *fname;
290    struct stat statp;
291    struct stat statn;
292    int debug_level = 0;
293    char *p;
294    int32_t j;
295    time_t t = 1028712799;
296
297    if (argc > 1 && strcmp(argv[1], "-v") == 0)
298       debug_level++;
299
300    base64_init();
301
302    my_glob.gl_offs = 0;
303    glob("/etc/grub.conf", GLOB_MARK, errfunc, &my_glob);
304
305    for (i=0; my_glob.gl_pathv[i]; i++) {
306       fname = my_glob.gl_pathv[i];
307       if (lstat(fname, &statp) < 0) {
308          berrno be;
309          printf("Cannot stat %s: %s\n", fname, be.bstrerror(errno));
310          continue;
311       }
312       encode_stat(where, &statp, sizeof(statp), 0, 0);
313
314       printf("Encoded stat=%s\n", where);
315
316 #ifdef xxx
317       p = where;
318       p += to_base64((int64_t)(statp.st_atime), p);
319       *p++ = ' ';
320       p += to_base64((int64_t)t, p);
321       printf("%s %s\n", fname, where);
322
323       printf("%s %lld\n", "st_dev", (int64_t)statp.st_dev);
324       printf("%s %lld\n", "st_ino", (int64_t)statp.st_ino);
325       printf("%s %lld\n", "st_mode", (int64_t)statp.st_mode);
326       printf("%s %lld\n", "st_nlink", (int64_t)statp.st_nlink);
327       printf("%s %lld\n", "st_uid", (int64_t)statp.st_uid);
328       printf("%s %lld\n", "st_gid", (int64_t)statp.st_gid);
329       printf("%s %lld\n", "st_rdev", (int64_t)statp.st_rdev);
330       printf("%s %lld\n", "st_size", (int64_t)statp.st_size);
331       printf("%s %lld\n", "st_blksize", (int64_t)statp.st_blksize);
332       printf("%s %lld\n", "st_blocks", (int64_t)statp.st_blocks);
333       printf("%s %lld\n", "st_atime", (int64_t)statp.st_atime);
334       printf("%s %lld\n", "st_mtime", (int64_t)statp.st_mtime);
335       printf("%s %lld\n", "st_ctime", (int64_t)statp.st_ctime);
336 #endif
337
338       if (debug_level)
339          printf("%s: len=%d val=%s\n", fname, strlen(where), where);
340
341       decode_stat(where, &statn, sizeof(statn), &j);
342
343       if (statp.st_dev != statn.st_dev ||
344           statp.st_ino != statn.st_ino ||
345           statp.st_mode != statn.st_mode ||
346           statp.st_nlink != statn.st_nlink ||
347           statp.st_uid != statn.st_uid ||
348           statp.st_gid != statn.st_gid ||
349           statp.st_rdev != statn.st_rdev ||
350           statp.st_size != statn.st_size ||
351           statp.st_blksize != statn.st_blksize ||
352           statp.st_blocks != statn.st_blocks ||
353           statp.st_atime != statn.st_atime ||
354           statp.st_mtime != statn.st_mtime ||
355           statp.st_ctime != statn.st_ctime) {
356
357          printf("%s: %s\n", fname, where);
358          encode_stat(where, &statn, sizeof(statn), 0, 0);
359          printf("%s: %s\n", fname, where);
360          printf("NOT EQAL\n");
361       }
362
363    }
364    globfree(&my_glob);
365
366    printf("%d files examined\n", i);
367
368    to_base64(UINT32_MAX, where);
369    printf("UINT32_MAX=%s\n", where);
370
371    return 0;
372 }
373 #endif