diff --git a/src/client/client_cli.c b/src/client/client_cli.c index 891afeb..0ebc391 100644 --- a/src/client/client_cli.c +++ b/src/client/client_cli.c @@ -70,10 +70,14 @@ int main(int argc, char* argv[]) { save_to_disk = true; } - Config* config = config_create(str_dup(PROTOCOL_VERSION), NULL, NULL, save_to_disk, false, false, - false, false, 5, false, 0); int exit_code = 0; bool config_owned_by_pipeline = false; + Config* config = config_create(str_dup(PROTOCOL_VERSION), NULL, NULL, save_to_disk, false, false, + false, false, 5, false, 0); + if (config == NULL) { + exit_code = 1; + goto cleanup; + } int positional_args[2]; int positional_count = 0; diff --git a/src/client/scanner.c b/src/client/scanner.c index 0f56f68..f4e48ad 100644 --- a/src/client/scanner.c +++ b/src/client/scanner.c @@ -91,7 +91,19 @@ DirectoryScanner* directory_scanner_create_full(char* root_directory, bool use_m scanner->max_size = max_size; scanner->min_size = min_size; scanner->follow_symlinks = follow_symlinks; - queue_enqueue(scanner->directories, str_dup(root_directory)); + char* root_copy = str_dup(root_directory); + if (root_copy == NULL) { + for (int i = 0; i < scanner->include_count; i++) + free(scanner->include_patterns[i]); + free(scanner->include_patterns); + for (int i = 0; i < scanner->exclude_count; i++) + free(scanner->exclude_patterns[i]); + free(scanner->exclude_patterns); + queue_destroy(scanner->directories); + free(scanner); + return NULL; + } + queue_enqueue(scanner->directories, root_copy); return scanner; } diff --git a/src/server/server.c b/src/server/server.c index 9df4e92..141ecdc 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -247,10 +247,9 @@ int main(int argc, char* argv[]) { server_listen(g_server, handler); } - /* Graceful shutdown: if a signal requested cleanup, delete the server */ - if (g_server_cleanup_requested) { + /* Graceful shutdown: delete the server */ + if (g_server_cleanup_requested) log_message(LOG_LEVEL_INFO, "Shutdown requested, cleaning up"); - server_delete(&g_server); - } + server_delete(&g_server); return 0; } diff --git a/src/shared/config.c b/src/shared/config.c index b9ff23c..e4654b3 100644 --- a/src/shared/config.c +++ b/src/shared/config.c @@ -82,6 +82,8 @@ void config_parse_ssh_dest(Config* config) { } void config_delete(Config* config) { + if (config == NULL) + return; free(config->version); free(config->send_directory); free(config->receive_root_directory); @@ -260,10 +262,6 @@ Config* config_receive(int file_descriptor) { MAX_PATTERN_COUNT); goto error; } - if ((size_t)ec > SIZE_MAX / sizeof(char*)) { - log_message(LOG_LEVEL_ERROR, "Exclude pattern count %d would cause integer overflow", ec); - goto error; - } config->exclude_count = ec; if (ec > 0) { config->exclude_patterns = malloc((size_t)ec * sizeof(char*)); @@ -293,10 +291,6 @@ Config* config_receive(int file_descriptor) { MAX_PATTERN_COUNT); goto error; } - if ((size_t)ic > SIZE_MAX / sizeof(char*)) { - log_message(LOG_LEVEL_ERROR, "Include pattern count %d would cause integer overflow", ic); - goto error; - } config->include_count = ic; if (ic > 0) { config->include_patterns = malloc((size_t)ic * sizeof(char*)); @@ -340,6 +334,16 @@ error: free(config->version); free(config->send_directory); free(config->receive_root_directory); + for (int i = 0; i < config->exclude_count; i++) + free(config->exclude_patterns[i]); + free(config->exclude_patterns); + for (int i = 0; i < config->include_count; i++) + free(config->include_patterns[i]); + free(config->include_patterns); + free(config->tls_cert); + free(config->tls_key); + free(config->tls_ca); + free(config->ssh_destination); free(config->server_host); free(config); return NULL; diff --git a/src/shared/file.c b/src/shared/file.c index 7f41fe2..2d9f922 100644 --- a/src/shared/file.c +++ b/src/shared/file.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -109,6 +110,9 @@ bool file_load_data(File* file) { size_t bytes_read = file_content_to_buffer(file); if (bytes_read != file->data->size) { log_message(LOG_LEVEL_ERROR, "Did not read expected amount of bytes from file"); + free(file->data->data); + file->data->data = NULL; + file->data->size = 0; return false; } return true; @@ -140,11 +144,13 @@ static bool file_send_streaming(File* file, int file_descriptor) { if (ferror(fp)) { perror("Read error during streaming"); } + send_status(file_descriptor, STATUS_ERROR); free(buf); fclose(fp); return false; } if (!send_n_data(file_descriptor, buf, nread)) { + send_status(file_descriptor, STATUS_ERROR); free(buf); fclose(fp); return false; @@ -626,8 +632,13 @@ bool file_send_sendfile(File* file, int file_descriptor, bool use_metadata, int off_t offset = 0; while ((unsigned long long)offset < file_size) { - ssize_t sent = sendfile(file_descriptor, fd, &offset, file_size - offset); + size_t send_count = (size_t)(file_size - (unsigned long long)offset); + if ((unsigned long long)send_count != file_size - (unsigned long long)offset) + send_count = SIZE_MAX; + ssize_t sent = sendfile(file_descriptor, fd, &offset, send_count); if (sent == -1) { + if (errno == EINTR) + continue; perror("sendfile failed"); close(fd); return false; diff --git a/src/shared/log.c b/src/shared/log.c index bc8ffed..bb7590a 100644 --- a/src/shared/log.c +++ b/src/shared/log.c @@ -16,6 +16,8 @@ void log_message(LogLevel log_level, const char* format, ...) { time_t now = time(NULL); struct tm result_buf; const struct tm* t = localtime_r(&now, &result_buf); + if (t == NULL) + return; fprintf(stderr, "%04d-%02d-%02d %02d:%02d:%02d [%s]: ", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, log_level_strings[log_level]); diff --git a/src/shared/metadata.h b/src/shared/metadata.h index f15570f..28312f5 100644 --- a/src/shared/metadata.h +++ b/src/shared/metadata.h @@ -20,6 +20,9 @@ * serialized as fixed-width integers. */ +/* Size of metadata fields on wire, excluding the int32_t `present` field that + * is always sent first. The total wire size for present metadata is + * sizeof(int32_t) + FILE_METADATA_WIRE_SIZE (32 bytes on most platforms). */ #define FILE_METADATA_WIRE_SIZE (sizeof(int32_t) * 3 + sizeof(int64_t) * 2) void metadata_to_buf(char** buf, const FileMetadata* m); diff --git a/src/shared/protocol.c b/src/shared/protocol.c index 1e5cb7f..de99d55 100644 --- a/src/shared/protocol.c +++ b/src/shared/protocol.c @@ -10,7 +10,7 @@ static __thread int io_read_fd = -1; static __thread int io_write_fd = -1; -static SSL* io_ssl = NULL; +static __thread SSL* io_ssl = NULL; static unsigned long long io_bwlimit = 0; static long long bw_tokens = 0; diff --git a/src/shared/transport_ssh.c b/src/shared/transport_ssh.c index 9b7950e..377fa63 100644 --- a/src/shared/transport_ssh.c +++ b/src/shared/transport_ssh.c @@ -119,10 +119,13 @@ Client* client_connect_ssh(const char* destination, int port) { close(sv[1]); char ssh_user[512]; + int needed; if (r.user && r.user[0] != '\0') - snprintf(ssh_user, sizeof(ssh_user), "%s@%s", r.user, r.host); + needed = snprintf(ssh_user, sizeof(ssh_user), "%s@%s", r.user, r.host); else - snprintf(ssh_user, sizeof(ssh_user), "%s", r.host); + needed = snprintf(ssh_user, sizeof(ssh_user), "%s", r.host); + if ((size_t)needed >= sizeof(ssh_user)) + fprintf(stderr, "Warning: ssh_user string truncated\n"); size_t ssh_argv_max = 32; char** ssh_argv = calloc(ssh_argv_max, sizeof(char*));