static void hmac_sha256_for_data(char *hash, const unsigned char *key, size_t key_len, const unsigned char *data, size_t data_len) { unsigned char digest[EVP_MAX_MD_SIZE]; unsigned int digest_len = 0; char *digest_str; unsigned int i; if (data == NULL) { hash_set_zeros(hash); return; } if (HMAC(EVP_sha256(), (const void *)key, key_len, data, data_len, digest, &digest_len) == NULL) { hash_set_zeros(hash); return; } digest_str = calloc((digest_len * 2) + 1, sizeof(char)); if (digest_str == NULL) { abort(); } for (i = 0; i < digest_len; i++) { sprintf(&digest_str[i * 2], "%02x", (unsigned int)digest[i]); } hash_assign(digest_str, hash); free(digest_str); }
static void hash_set_ones(char *hash) { hash_assign("1111111111111111111111111111111111111111111111111111111111111111", hash); }
int match_manifests(struct manifest *m1, struct manifest *m2) { GList *list1, *list2; struct file *file1, *file2; int must_sort = 0; int count = 0; int first = 1; if (!m1) { printf("Matching manifests up failed: No old manifest!\n"); return -1; } if (!m2) { printf("Matching manifests up failed: No new manifest!\n"); return -1; } m1->files = g_list_sort(m1->files, file_sort_filename); m2->files = g_list_sort(m2->files, file_sort_filename); list1 = g_list_first(m1->files); list2 = g_list_first(m2->files); while (list1 && list2) { int ret; file1 = list1->data; file2 = list2->data; file1->peer = NULL; file2->peer = NULL; ret = strcmp(file1->filename, file2->filename); if (ret == 0) { if (file1->is_deleted && file2->is_deleted && file1->is_rename) { file2->is_rename = file1->is_rename; hash_assign(file1->hash, file2->hash); } if (hash_compare(file1->hash, file2->hash) && file1->is_dir == file2->is_dir && file1->is_link == file2->is_link && file1->is_deleted == file2->is_deleted && file1->is_file == file2->is_file && file1->is_config == file2->is_config && file1->is_state == file2->is_state && file1->is_boot == file2->is_boot && file1->last_change >= minversion) { file2->last_change = file1->last_change; file2->is_rename = file1->is_rename; } else { account_changed_file(); if (first) { LOG(file1, "file changed", ""); first = 0; } count++; } if (!file1->is_deleted || file2->is_deleted) { file1->peer = file2; file2->peer = file1; } list1 = g_list_next(list1); list2 = g_list_next(list2); continue; } if (first) { LOG(file1, "file added? ", "(file2 is %s)", file2->filename); first = 0; } if (ret < 0) { struct file *file3; /* * if we get here, file1 got deleted... what we must do * is add a file entry for it in the target list. * However, since we're currently walking the list we * HAVE to prepend the entry.. and mark for sort at the * end. */ file3 = calloc(1, sizeof(struct file)); if (file3 == NULL) { assert(0); } file3->filename = strdup(file1->filename); hash_set_zeros(file3->hash); file3->is_deleted = 1; file3->is_config = file1->is_config; file3->is_state = file1->is_state; file3->is_boot = file1->is_boot; if (!file1->is_deleted) { file3->last_change = m2->version; } else { file3->last_change = file1->last_change; file3->is_rename = file1->is_rename; hash_assign(file1->hash, file3->hash); } file3->peer = file1; file1->peer = file3; list1 = g_list_next(list1); m2->files = g_list_prepend(m2->files, file3); m2->count++; if (!file1->is_deleted) { account_deleted_file(); count++; if (first) { LOG(file1, "file got deleted", ""); first = 0; } } must_sort = 1; continue; } /* if we get here, ret is > 0, which means this is a new file added */ /* all we do is advance the pointer */ account_new_file(); list2 = g_list_next(list2); count++; } /* now deal with the tail ends */ while (list1) { file1 = list1->data; struct file *file3; if (first) { LOG(file1, "file changed tail", ""); first = 0; } count++; /* * if we get here, file1 got deleted... what we must do is add * a file entry for it in the target list. However, since * we're currently walking the list we HAVE to prepend the * entry.. and mark for sort at the end. */ file3 = calloc(1, sizeof(struct file)); if (file3 == NULL) { assert(0); } file3->filename = strdup(file1->filename); hash_set_zeros(file3->hash); file3->is_deleted = 1; file3->is_config = file1->is_config; file3->is_state = file1->is_state; file3->is_boot = file1->is_boot; if (!file1->is_deleted) { file3->last_change = m2->version; } else { file3->last_change = file1->last_change; file3->is_rename = file1->is_rename; hash_assign(file1->hash, file3->hash); } file3->peer = file1; file1->peer = file3; list1 = g_list_next(list1); m2->files = g_list_prepend(m2->files, file3); m2->count++; if (!file1->is_deleted) { account_deleted_file(); } must_sort = 1; } while (list2) { account_new_file(); list2 = g_list_next(list2); if (first) { first = 0; } count++; } if (must_sort) { m2->files = g_list_sort(m2->files, file_sort_filename); } return count; }
static void hash_set_zeros(char *hash) { hash_assign("0000000000000000000000000000000000000000000000000000000000000000", hash); }
struct manifest *manifest_from_file(int version, char *component) { FILE *infile; GList *includes = NULL; char line[8192], *c, *c2; int count = 0; struct manifest *manifest; char *filename, *conf; int previous = 0; unsigned long long int format_number; conf = config_output_dir(); if (conf == NULL) { assert(0); } string_or_die(&filename, "%s/%i/Manifest.%s", conf, version, component); free(conf); LOG(NULL, "Reading manifest", "%s", filename); infile = fopen(filename, "rb"); if (infile == NULL) { LOG(NULL, "Cannot read manifest", "%s (%s)\n", filename, strerror(errno)); free(filename); return alloc_manifest(version, component); } /* line 1: MANIFEST\t<version> */ line[0] = 0; if (fgets(line, 8191, infile) == NULL) { fclose(infile); return NULL; } if (strncmp(line, "MANIFEST\t", 9) != 0) { printf("Invalid file format: MANIFEST line\n"); fclose(infile); return NULL; } c = &line[9]; format_number = strtoull(c, NULL, 10); if ((errno < 0) || (format_number == 0)) { //format string shall be a positive integer printf("Unknown file format version in MANIFEST line: %s\n", c); fclose(infile); return NULL; } line[0] = 0; while (strcmp(line, "\n") != 0) { /* read the header */ line[0] = 0; if (fgets(line, 8191, infile) == NULL) { break; } c = strchr(line, '\n'); if (c) { *c = 0; } if (strlen(line) == 0) { break; } c = strchr(line, '\t'); /* Make sure we're not at the end of the array before incrementing */ if (c && c <= &line[strlen(line)]) { c++; } else { printf("Manifest is corrupt\n"); assert(0); } if (strncmp(line, "version:", 8) == 0) { version = strtoull(c, NULL, 10); } if (strncmp(line, "previous:", 9) == 0) { previous = strtoull(c, NULL, 10); } if (strncmp(line, "includes:", 9) == 0) { includes = g_list_prepend(includes, strdup(c)); if (!includes->data) { abort(); } } } manifest = alloc_manifest(version, component); manifest->format = format_number; manifest->prevversion = previous; manifest->includes = includes; /* empty line */ while (!feof(infile)) { struct file *file; line[0] = 0; if (fgets(line, 8191, infile) == NULL) { break; } c = strchr(line, '\n'); if (c) { *c = 0; } if (strlen(line) == 0) { break; } file = calloc(1, sizeof(struct file)); if (file == NULL) { assert(0); } c = line; c2 = strchr(c, '\t'); if (c2) { *c2 = 0; c2++; } if (c[0] == 'F') { file->is_file = 1; } else if (c[0] == 'D') { file->is_dir = 1; } else if (c[0] == 'L') { file->is_link = 1; } else if (c[0] == 'M') { LOG(NULL, "Found a manifest!", "%s", c); file->is_manifest = 1; } else if (c[0] != '.') { assert(0); /* unknown file type */ } if (c[1] == 'd') { file->is_deleted = 1; } else if (c[1] != '.') { assert(0); /* unknown deleted status */ } if (c[2] == 'C') { file->is_config = 1; } else if (c[2] == 's') { file->is_state = 1; } else if (c[2] == 'b') { file->is_boot = 1; } else if (c[2] != '.') { assert(0); /* unknown modifier status */ } if (c[3] == 'r') { file->is_rename = 1; } else if (c[3] != '.') { ; /* field 4: ignore unknown letters */ } c = c2; if (!c) { free(file); continue; } c2 = strchr(c, '\t'); if (c2) { *c2 = 0; c2++; } hash_assign(c, file->hash); c = c2; if (!c) { free(file); continue; } c2 = strchr(c, '\t'); if (c2) { *c2 = 0; c2++; } file->last_change = strtoull(c, NULL, 10); c = c2; if (!c) { free(file); continue; } file->filename = strdup(c); if (file->is_manifest) { nest_manifest_file(manifest, file); } else { manifest->files = g_list_prepend(manifest->files, file); } manifest->count++; count++; } manifest->files = g_list_sort(manifest->files, file_sort_filename); fclose(infile); LOG(NULL, "Manifest info", "Manifest for version %i/%s contains %i files", version, component, count); free(filename); return manifest; }