X-Git-Url: https://git.ozlabs.org/?p=petitboot;a=blobdiff_plain;f=lib%2Ffile%2Ffile.c;h=0d187887c701f75183fcec4550f33cb292a9198a;hp=1bde9fb805ba906c95ca4ec24df9d1dc921994af;hb=b2bc013b141308cd0e78b47ed0b19e1c1ff6a20a;hpb=052961eb2e8279f103c091e850c317da335c0207 diff --git a/lib/file/file.c b/lib/file/file.c index 1bde9fb..0d18788 100644 --- a/lib/file/file.c +++ b/lib/file/file.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2013 Jeremy Kerr + * Copyright (C) 2016 Raptor Engineering, LLC * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,11 +24,104 @@ #include #include +#include #include "file.h" +#define MAX_FILENAME_SIZE 8192 +#define FILE_XFER_BUFFER_SIZE 8192 + static const int max_file_size = 1024 * 1024; +int copy_file_secure_dest(void *ctx, const char *source_file, + char **destination_file) +{ + char readlink_buffer[MAX_FILENAME_SIZE + 1]; + char dest_filename[MAX_FILENAME_SIZE] = ""; + char template[] = "/tmp/petitbootXXXXXX"; + FILE *destination_handle, *source_handle; + int destination_fd, result = 0; + unsigned char *buffer; + ssize_t r; + size_t l1; + mode_t oldmask; + + source_handle = fopen(source_file, "r"); + if (!source_handle) { + pb_log("%s: unable to open source file '%s': %m\n", + __func__, source_file); + return -1; + } + + oldmask = umask(0644); + destination_fd = mkstemp(template); + umask(oldmask); + if (destination_fd < 0) { + pb_log("%s: unable to create temp file, %m\n", __func__); + fclose(source_handle); + return -1; + } + destination_handle = fdopen(destination_fd, "w"); + if (!destination_handle) { + pb_log("%s: unable to open destination file, %m\n", __func__); + fclose(source_handle); + close(destination_fd); + return -1; + } + + buffer = talloc_array(ctx, unsigned char, FILE_XFER_BUFFER_SIZE); + if (!buffer) { + pb_log("%s: failed: unable to allocate file transfer buffer\n", + __func__); + result = -1; + goto out; + } + + /* Copy data */ + while ((l1 = fread(buffer, 1, FILE_XFER_BUFFER_SIZE, source_handle)) > 0) { + size_t l2 = fwrite(buffer, 1, l1, destination_handle); + if (l2 < l1) { + if (ferror(destination_handle)) { + /* General error */ + result = -1; + pb_log("%s: failed: unknown fault\n", __func__); + } + else { + /* No space on destination device */ + result = -1; + pb_log("%s: failed: temporary storage full\n", + __func__); + } + break; + } + } + + if (result) { + *destination_file = NULL; + goto out; + } + + snprintf(readlink_buffer, MAX_FILENAME_SIZE, "/proc/self/fd/%d", + destination_fd); + r = readlink(readlink_buffer, dest_filename, MAX_FILENAME_SIZE); + if (r < 0) { + /* readlink failed */ + result = -1; + r = 0; + pb_log("%s: failed: unable to obtain temporary filename\n", + __func__); + } + dest_filename[r] = '\0'; + + *destination_file = talloc_strdup(ctx, dest_filename); +out: + talloc_free(buffer); + fclose(source_handle); + fclose(destination_handle); + close(destination_fd); + return result; +} + int read_file(void *ctx, const char *filename, char **bufp, int *lenp) { struct stat statbuf;