Guest User

Bacula Dirty Dumper

a guest
Oct 15th, 2014
511
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2.     Bacula dirty extractor
  3.  
  4.     This is a quick hack to extract everything we could from the Bacula backup files.
  5.     It doesn't care about sessions, volumes, configs, databases and other mess, which
  6.     in many cases would lead to terrible consequences. It assumes that the files were
  7.     stored sequentially and took care about filenames, links, directory and raw data.
  8.     The other types of records are not supported.
  9. */
  10. #define _GNU_SOURCE
  11. #include <stdint.h>
  12. #include <stdio.h>
  13. #include <sys/mman.h>
  14. #include <sys/stat.h>
  15. #include <ctype.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <fcntl.h>
  19.  
  20. int verbose = 0;
  21.  
  22. struct block {
  23.     uint32_t    CheckSum;       /* Block check sum */
  24.     uint32_t    BlockSize;      /* Block byte size including the header */
  25.     uint32_t    BlockNumber;        /* Block number */
  26.     char        ID[4];          /* Identification and block level "BB02" */
  27.     uint32_t    VolSessionId;       /* Session Id for Job */
  28.     uint32_t    VolSessionTime;     /* Session Time for Job */
  29. };
  30.  
  31. struct record {
  32.     int32_t     FileIndex;      /* File index supplied by File daemon */
  33.     int32_t     Stream;         /* Stream number supplied by File daemon */
  34.     uint32_t    DataSize;       /* size of following data record in bytes */
  35. };
  36.  
  37. static char **read_array_from_string(char *string, int *count)
  38. {
  39.     char *p, *q, *t = string;
  40.     char **r = NULL;
  41.     int c = 0;
  42.     *count = 0;
  43.     if (string == NULL)
  44.         return NULL;
  45.     while (*t) {
  46.         p = t;
  47.         while (*p && isspace(*p))
  48.             p++;
  49.         if (! *p)
  50.             break;
  51.         q = p;
  52.         while (*q && *q != ' ')
  53.             q++;
  54.         int l = q - p;
  55.         if (l) {
  56.             char *x = realloc(NULL, l + 1);
  57.             if (x == NULL)
  58.                 break;
  59.             r = realloc(r, sizeof(char*)*(c + 2));
  60.             if (r == NULL)
  61.                 break;
  62.             memcpy(x, p, l);
  63.             /* trim trailing spaces */
  64.             x[l] = 0;
  65.             while (l && isspace(x[--l]))
  66.                 x[l] = 0;
  67.             r[c] = x;
  68.             r[c + 1] = NULL;
  69.             c++;
  70.         }
  71.         t = q;
  72.     }
  73.     *count = c;
  74.     return r;
  75. }
  76.  
  77. static void _mkdir(const char *dir) {
  78.     char tmp[1024];
  79.     char *p = NULL;
  80.     size_t len;
  81.     struct stat sb;
  82.  
  83.     if (stat(dir, &sb) == 0)
  84.         return;
  85.     snprintf(tmp, sizeof(tmp),"%s",dir);
  86.     len = strlen(tmp);
  87.     if (tmp[len - 1] == '/')
  88.         tmp[len - 1] = 0;
  89.     for (p = tmp + 1; *p; p++)
  90.         if (*p == '/') {
  91.             *p = 0;
  92.             mkdir(tmp, S_IRWXU);
  93.             *p = '/';
  94.         }
  95.     mkdir(tmp, S_IRWXU);
  96. }
  97.  
  98. int last_handle = -1;
  99.  
  100. int parse_attr(uint8_t *str)
  101. {
  102.     char *s = str;
  103.     int c;
  104.     /* <File-Index> <Type> <Filename> */
  105.     char **part1 = read_array_from_string(s, &c);
  106.     if (c != 3) {
  107.         fprintf(stderr, "Malformed file record %s (%d)\n", s, c);
  108.         return 0;
  109.     }
  110.     s += strlen(s) + 1;
  111.     /* <File-Attributes> (16 x base64 of stat buf) */
  112.     char **part2 = read_array_from_string(s, &c);
  113.     if (c != 16) {
  114.         fprintf(stderr, "Malformed attributes %s (%d)\n", s, c);
  115.         return 0;
  116.     }
  117.     s += strlen(s) + 1;
  118.     char *link = s;
  119.     struct stat buf;
  120.     bzero(&buf, sizeof(buf));
  121.     int type = atoi(part1[1]);
  122.     char *filename = part1[2];
  123.     char *path = strdup(filename);
  124.     char *pathname = dirname(path);
  125.     char *trim_root(char *path) {
  126.         if (path && *path == '/')
  127.             return path + 1;
  128.         return path;
  129.     }
  130.     pathname = trim_root(pathname);
  131.     filename = trim_root(filename);
  132.     link = trim_root(link);
  133.     _mkdir(pathname);
  134.     free(path);
  135.     printf("%d %s %s\n", type, filename, link);
  136.     if (link && *link) {
  137.         if (symlink(link, filename) != 0)
  138.             perror("symlink");
  139.     } else
  140.     if (type == 5) {
  141.         /* do nothing, we already created directory */
  142.     } else
  143.     if (type == 3) {
  144.         /* regualr file */
  145.         if (last_handle >= 0) {
  146.             close(last_handle);
  147.             last_handle = -1;
  148.         }
  149.         last_handle = open(filename, O_WRONLY | O_CREAT, 0644);
  150.         if (last_handle < 0)
  151.             perror("open");
  152.     }
  153.     void free_array(char **list) {
  154.         int i = 0;
  155.         if (list == NULL)
  156.             return;
  157.         while (list[i]) {
  158.             free(list[i]);
  159.             i++;
  160.         }
  161.         free(list);
  162.     }
  163.     free_array(part1);
  164.     free_array(part2);
  165. }
  166.  
  167. static uint32_t crc32(uint32_t crc, const void *data, int len)
  168. {
  169.     int i;
  170.     uint8_t *tmp = (uint8_t*)data;
  171.     crc = ~crc;
  172.     while (len--) {
  173.         crc ^= *tmp++;
  174.         for (i = 0; i < 8; i++)
  175.             if (crc & 1)
  176.                 crc >>= 1, crc ^= 0xedb88320;
  177.             else
  178.                 crc >>= 1;
  179.     }
  180.     return ~crc;
  181. }
  182.  
  183. int dump_file(char *filename)
  184. {
  185.     int h = open(filename, 0);
  186.     if (h < 0) {
  187.         fprintf(stderr, "Failed to open file %s\n", filename);
  188.         return 0;
  189.     }
  190.     struct stat buf;
  191.     fstat(h, &buf);
  192.     size_t l = buf.st_size;
  193.     printf("open volume, size %zu\n", l);
  194.     uint8_t *m = mmap(NULL, l, PROT_READ, MAP_SHARED, h, 0);
  195.     if (m == MAP_FAILED)
  196.         goto _close;
  197.     size_t off = 0;
  198.     while (off < l) {
  199.         struct block *b = (struct block*)(m + off);
  200.         if (strcmp(b->ID, "BB02")) {
  201.             fprintf(stderr, "Invalid block ID\n");
  202.             break;
  203.         }
  204.         size_t bs = ntohl(b->BlockSize);
  205.         if (verbose > 1)
  206.             printf("Block %u at offset %zu, size %u\n", ntohl(b->BlockNumber), off, bs);
  207.         size_t eob = off + bs;
  208.         /* block checksum */
  209. #if 1
  210.         uint32_t bcrc = ntohl(b->CheckSum);
  211.         uint32_t ncrc = crc32(0, (char*)b + 4, bs - 4);
  212.         if (ncrc != bcrc)
  213.             fprintf(stderr, "WARNING! Block checksum failed\n");
  214. #endif
  215.         /* End-of-Block within the file? */
  216.         if (eob <= l) {
  217.             size_t roff = off + sizeof(struct block);
  218.             while (roff < eob) {
  219.                 struct record *rec = (struct record*)(m + roff);
  220.                 int32_t FileIndex = ntohl(rec->FileIndex);
  221.                 int32_t Stream = ntohl(rec->Stream);
  222.                 uint32_t DataSize = ntohl(rec->DataSize);
  223.                 /* negative file indices are used for labels */
  224.                 if (verbose > 1)
  225.                     printf("\tindex %d, stream %d, size %d\n", FileIndex, Stream, DataSize);
  226.                 /* negative stream indices is a continuation of the previous stream */
  227.                 /*
  228.                     1 - attributes
  229.                     2 - raw data
  230.                     10 - sha1
  231.                 */
  232.                 if (Stream == 1) {
  233.                     parse_attr(m + roff + sizeof(struct record));
  234.                 }
  235.                 if (Stream == 2 || Stream < 0) {
  236.                     if (last_handle >= 0) {
  237.                         write(last_handle, m + roff + sizeof(struct record), DataSize);
  238.                     } else {
  239.                         fprintf(stderr, "Orphaned data record!\n");
  240.                     }
  241.                 }
  242.                 if (Stream > 0 && Stream != 1 && Stream != 2 && Stream != 10) {
  243.                     printf("New type %d, don't know how to handle it\n");
  244.                     exit(0);
  245.                 }
  246.                 roff += sizeof(struct record) + DataSize;
  247.             }
  248.         } else
  249.             break;
  250.         off = eob;
  251.     }
  252.     close(last_handle);
  253.     if (off < l) {
  254.         printf("Next block not found. Bytes remaining %zu, file truncated?\n", l - off);
  255.     }
  256.     puts("Done.");
  257. _unmap:
  258.     munmap(m, l);
  259. _close:
  260.     close(h);
  261. }
  262.  
  263. int main(int argc, char **argv)
  264. {
  265.     dump_file(argv[1]);
  266. }
RAW Paste Data