Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- Bacula dirty extractor
- This is a quick hack to extract everything we could from the Bacula backup files.
- It doesn't care about sessions, volumes, configs, databases and other mess, which
- in many cases would lead to terrible consequences. It assumes that the files were
- stored sequentially and took care about filenames, links, directory and raw data.
- The other types of records are not supported.
- */
- #define _GNU_SOURCE
- #include <stdint.h>
- #include <stdio.h>
- #include <sys/mman.h>
- #include <sys/stat.h>
- #include <ctype.h>
- #include <stdlib.h>
- #include <string.h>
- #include <fcntl.h>
- int verbose = 0;
- struct block {
- uint32_t CheckSum; /* Block check sum */
- uint32_t BlockSize; /* Block byte size including the header */
- uint32_t BlockNumber; /* Block number */
- char ID[4]; /* Identification and block level "BB02" */
- uint32_t VolSessionId; /* Session Id for Job */
- uint32_t VolSessionTime; /* Session Time for Job */
- };
- struct record {
- int32_t FileIndex; /* File index supplied by File daemon */
- int32_t Stream; /* Stream number supplied by File daemon */
- uint32_t DataSize; /* size of following data record in bytes */
- };
- static char **read_array_from_string(char *string, int *count)
- {
- char *p, *q, *t = string;
- char **r = NULL;
- int c = 0;
- *count = 0;
- if (string == NULL)
- return NULL;
- while (*t) {
- p = t;
- while (*p && isspace(*p))
- p++;
- if (! *p)
- break;
- q = p;
- while (*q && *q != ' ')
- q++;
- int l = q - p;
- if (l) {
- char *x = realloc(NULL, l + 1);
- if (x == NULL)
- break;
- r = realloc(r, sizeof(char*)*(c + 2));
- if (r == NULL)
- break;
- memcpy(x, p, l);
- /* trim trailing spaces */
- x[l] = 0;
- while (l && isspace(x[--l]))
- x[l] = 0;
- r[c] = x;
- r[c + 1] = NULL;
- c++;
- }
- t = q;
- }
- *count = c;
- return r;
- }
- static void _mkdir(const char *dir) {
- char tmp[1024];
- char *p = NULL;
- size_t len;
- struct stat sb;
- if (stat(dir, &sb) == 0)
- return;
- snprintf(tmp, sizeof(tmp),"%s",dir);
- len = strlen(tmp);
- if (tmp[len - 1] == '/')
- tmp[len - 1] = 0;
- for (p = tmp + 1; *p; p++)
- if (*p == '/') {
- *p = 0;
- mkdir(tmp, S_IRWXU);
- *p = '/';
- }
- mkdir(tmp, S_IRWXU);
- }
- int last_handle = -1;
- int parse_attr(uint8_t *str)
- {
- char *s = str;
- int c;
- /* <File-Index> <Type> <Filename> */
- char **part1 = read_array_from_string(s, &c);
- if (c != 3) {
- fprintf(stderr, "Malformed file record %s (%d)\n", s, c);
- return 0;
- }
- s += strlen(s) + 1;
- /* <File-Attributes> (16 x base64 of stat buf) */
- char **part2 = read_array_from_string(s, &c);
- if (c != 16) {
- fprintf(stderr, "Malformed attributes %s (%d)\n", s, c);
- return 0;
- }
- s += strlen(s) + 1;
- char *link = s;
- struct stat buf;
- bzero(&buf, sizeof(buf));
- int type = atoi(part1[1]);
- char *filename = part1[2];
- char *path = strdup(filename);
- char *pathname = dirname(path);
- char *trim_root(char *path) {
- if (path && *path == '/')
- return path + 1;
- return path;
- }
- pathname = trim_root(pathname);
- filename = trim_root(filename);
- link = trim_root(link);
- _mkdir(pathname);
- free(path);
- printf("%d %s %s\n", type, filename, link);
- if (link && *link) {
- if (symlink(link, filename) != 0)
- perror("symlink");
- } else
- if (type == 5) {
- /* do nothing, we already created directory */
- } else
- if (type == 3) {
- /* regualr file */
- if (last_handle >= 0) {
- close(last_handle);
- last_handle = -1;
- }
- last_handle = open(filename, O_WRONLY | O_CREAT, 0644);
- if (last_handle < 0)
- perror("open");
- }
- void free_array(char **list) {
- int i = 0;
- if (list == NULL)
- return;
- while (list[i]) {
- free(list[i]);
- i++;
- }
- free(list);
- }
- free_array(part1);
- free_array(part2);
- }
- static uint32_t crc32(uint32_t crc, const void *data, int len)
- {
- int i;
- uint8_t *tmp = (uint8_t*)data;
- crc = ~crc;
- while (len--) {
- crc ^= *tmp++;
- for (i = 0; i < 8; i++)
- if (crc & 1)
- crc >>= 1, crc ^= 0xedb88320;
- else
- crc >>= 1;
- }
- return ~crc;
- }
- int dump_file(char *filename)
- {
- int h = open(filename, 0);
- if (h < 0) {
- fprintf(stderr, "Failed to open file %s\n", filename);
- return 0;
- }
- struct stat buf;
- fstat(h, &buf);
- size_t l = buf.st_size;
- printf("open volume, size %zu\n", l);
- uint8_t *m = mmap(NULL, l, PROT_READ, MAP_SHARED, h, 0);
- if (m == MAP_FAILED)
- goto _close;
- size_t off = 0;
- while (off < l) {
- struct block *b = (struct block*)(m + off);
- if (strcmp(b->ID, "BB02")) {
- fprintf(stderr, "Invalid block ID\n");
- break;
- }
- size_t bs = ntohl(b->BlockSize);
- if (verbose > 1)
- printf("Block %u at offset %zu, size %u\n", ntohl(b->BlockNumber), off, bs);
- size_t eob = off + bs;
- /* block checksum */
- #if 1
- uint32_t bcrc = ntohl(b->CheckSum);
- uint32_t ncrc = crc32(0, (char*)b + 4, bs - 4);
- if (ncrc != bcrc)
- fprintf(stderr, "WARNING! Block checksum failed\n");
- #endif
- /* End-of-Block within the file? */
- if (eob <= l) {
- size_t roff = off + sizeof(struct block);
- while (roff < eob) {
- struct record *rec = (struct record*)(m + roff);
- int32_t FileIndex = ntohl(rec->FileIndex);
- int32_t Stream = ntohl(rec->Stream);
- uint32_t DataSize = ntohl(rec->DataSize);
- /* negative file indices are used for labels */
- if (verbose > 1)
- printf("\tindex %d, stream %d, size %d\n", FileIndex, Stream, DataSize);
- /* negative stream indices is a continuation of the previous stream */
- /*
- 1 - attributes
- 2 - raw data
- 10 - sha1
- */
- if (Stream == 1) {
- parse_attr(m + roff + sizeof(struct record));
- }
- if (Stream == 2 || Stream < 0) {
- if (last_handle >= 0) {
- write(last_handle, m + roff + sizeof(struct record), DataSize);
- } else {
- fprintf(stderr, "Orphaned data record!\n");
- }
- }
- if (Stream > 0 && Stream != 1 && Stream != 2 && Stream != 10) {
- printf("New type %d, don't know how to handle it\n");
- exit(0);
- }
- roff += sizeof(struct record) + DataSize;
- }
- } else
- break;
- off = eob;
- }
- close(last_handle);
- if (off < l) {
- printf("Next block not found. Bytes remaining %zu, file truncated?\n", l - off);
- }
- puts("Done.");
- _unmap:
- munmap(m, l);
- _close:
- close(h);
- }
- int main(int argc, char **argv)
- {
- dump_file(argv[1]);
- }
Add Comment
Please, Sign In to add comment