diff --git a/qrexec-lib/buffer.c b/qrexec-lib/buffer.c index 12bc4eb..09687e4 100644 --- a/qrexec-lib/buffer.c +++ b/qrexec-lib/buffer.c @@ -28,88 +28,88 @@ static int total_mem; static char *limited_malloc(int len) { - char *ret; - total_mem += len; - if (total_mem > BUFFER_LIMIT) { - fprintf(stderr, "attempt to allocate >BUFFER_LIMIT\n"); - exit(1); - } - ret = malloc(len); - if (!ret) { - perror("malloc"); - exit(1); - } - return ret; + char *ret; + total_mem += len; + if (total_mem > BUFFER_LIMIT) { + fprintf(stderr, "attempt to allocate >BUFFER_LIMIT\n"); + exit(1); + } + ret = malloc(len); + if (!ret) { + perror("malloc"); + exit(1); + } + return ret; } static void limited_free(char *ptr, int len) { - free(ptr); - total_mem -= len; + free(ptr); + total_mem -= len; } void buffer_init(struct buffer *b) { - b->buflen = 0; - b->data = NULL; + b->buflen = 0; + b->data = NULL; } void buffer_free(struct buffer *b) { - if (b->buflen) - limited_free(b->data, b->buflen); - buffer_init(b); + if (b->buflen) + limited_free(b->data, b->buflen); + buffer_init(b); } /* -The following two functions can be made much more efficient. -Yet the profiling output show they are not significant CPU hogs, so -we keep them so simple to make them obviously correct. -*/ + The following two functions can be made much more efficient. + Yet the profiling output show they are not significant CPU hogs, so + we keep them so simple to make them obviously correct. + */ void buffer_append(struct buffer *b, const char *data, int len) { - int newsize; - char *qdata; - if (len < 0 || len > BUFFER_LIMIT) { - fprintf(stderr, "buffer_append %d\n", len); - exit(1); - } - if (len == 0) - return; - newsize = len + b->buflen; - qdata = limited_malloc(len + b->buflen); - memcpy(qdata, b->data, b->buflen); - memcpy(qdata + b->buflen, data, len); - buffer_free(b); - b->buflen = newsize; - b->data = qdata; + int newsize; + char *qdata; + if (len < 0 || len > BUFFER_LIMIT) { + fprintf(stderr, "buffer_append %d\n", len); + exit(1); + } + if (len == 0) + return; + newsize = len + b->buflen; + qdata = limited_malloc(len + b->buflen); + memcpy(qdata, b->data, b->buflen); + memcpy(qdata + b->buflen, data, len); + buffer_free(b); + b->buflen = newsize; + b->data = qdata; } void buffer_remove(struct buffer *b, int len) { - int newsize; - char *qdata = NULL; - if (len < 0 || len > b->buflen) { - fprintf(stderr, "buffer_remove %d/%d\n", len, b->buflen); - exit(1); - } - newsize = b->buflen - len; - if (newsize > 0) { - qdata = limited_malloc(newsize); - memcpy(qdata, b->data + len, newsize); - } - buffer_free(b); - b->buflen = newsize; - b->data = qdata; + int newsize; + char *qdata = NULL; + if (len < 0 || len > b->buflen) { + fprintf(stderr, "buffer_remove %d/%d\n", len, b->buflen); + exit(1); + } + newsize = b->buflen - len; + if (newsize > 0) { + qdata = limited_malloc(newsize); + memcpy(qdata, b->data + len, newsize); + } + buffer_free(b); + b->buflen = newsize; + b->data = qdata; } int buffer_len(struct buffer *b) { - return b->buflen; + return b->buflen; } void *buffer_data(struct buffer *b) { - return b->data; + return b->data; } diff --git a/qrexec-lib/copy-file.c b/qrexec-lib/copy-file.c index 6b94742..9c1111f 100644 --- a/qrexec-lib/copy-file.c +++ b/qrexec-lib/copy-file.c @@ -6,44 +6,44 @@ notify_progress_t *notify_progress_func = NULL; void register_notify_progress(notify_progress_t *func) { - notify_progress_func = func; + notify_progress_func = func; } int copy_file(int outfd, int infd, long long size, unsigned long *crc32) { - char buf[4096]; - long long written = 0; - int ret; - int count; - while (written < size) { - if (size - written > (int)sizeof(buf)) - count = sizeof buf; - else - count = size - written; - ret = read(infd, buf, count); - if (!ret) - return COPY_FILE_READ_EOF; - if (ret < 0) - return COPY_FILE_READ_ERROR; - /* acumulate crc32 if requested */ - if (crc32) - *crc32 = Crc32_ComputeBuf(*crc32, buf, ret); - if (!write_all(outfd, buf, ret)) - return COPY_FILE_WRITE_ERROR; - if (notify_progress_func != NULL) - notify_progress_func(ret, 0); - written += ret; - } - return COPY_FILE_OK; + char buf[4096]; + long long written = 0; + int ret; + int count; + while (written < size) { + if (size - written > (int)sizeof(buf)) + count = sizeof buf; + else + count = size - written; + ret = read(infd, buf, count); + if (!ret) + return COPY_FILE_READ_EOF; + if (ret < 0) + return COPY_FILE_READ_ERROR; + /* acumulate crc32 if requested */ + if (crc32) + *crc32 = Crc32_ComputeBuf(*crc32, buf, ret); + if (!write_all(outfd, buf, ret)) + return COPY_FILE_WRITE_ERROR; + if (notify_progress_func != NULL) + notify_progress_func(ret, 0); + written += ret; + } + return COPY_FILE_OK; } const char * copy_file_status_to_str(int status) { - switch (status) { - case COPY_FILE_OK: return "OK"; - case COPY_FILE_READ_EOF: return "Unexpected end of data while reading"; - case COPY_FILE_READ_ERROR: return "Error reading"; - case COPY_FILE_WRITE_ERROR: return "Error writing"; - default: return "????????"; - } + switch (status) { + case COPY_FILE_OK: return "OK"; + case COPY_FILE_READ_EOF: return "Unexpected end of data while reading"; + case COPY_FILE_READ_ERROR: return "Error reading"; + case COPY_FILE_WRITE_ERROR: return "Error writing"; + default: return "????????"; + } } diff --git a/qrexec-lib/exec.c b/qrexec-lib/exec.c index b6518f0..890c242 100644 --- a/qrexec-lib/exec.c +++ b/qrexec-lib/exec.c @@ -28,56 +28,56 @@ static do_exec_t *exec_func = NULL; void register_exec_func(do_exec_t *func) { - exec_func = func; + exec_func = func; } void fix_fds(int fdin, int fdout, int fderr) { - int i; - for (i = 0; i < 256; i++) - if (i != fdin && i != fdout && i != fderr) - close(i); - dup2(fdin, 0); - dup2(fdout, 1); - dup2(fderr, 2); - close(fdin); - close(fdout); - if (fderr != 2) - close(fderr); + int i; + for (i = 0; i < 256; i++) + if (i != fdin && i != fdout && i != fderr) + close(i); + dup2(fdin, 0); + dup2(fdout, 1); + dup2(fderr, 2); + close(fdin); + close(fdout); + if (fderr != 2) + close(fderr); } void do_fork_exec(const char *cmdline, int *pid, int *stdin_fd, int *stdout_fd, - int *stderr_fd) + int *stderr_fd) { - int inpipe[2], outpipe[2], errpipe[2]; + int inpipe[2], outpipe[2], errpipe[2]; - if (socketpair(AF_UNIX, SOCK_STREAM, 0, inpipe) || - socketpair(AF_UNIX, SOCK_STREAM, 0, outpipe) || - (stderr_fd && socketpair(AF_UNIX, SOCK_STREAM, 0, errpipe))) { - perror("socketpair"); - exit(1); - } - switch (*pid = fork()) { - case -1: - perror("fork"); - exit(-1); - case 0: - if (stderr_fd) { - fix_fds(inpipe[0], outpipe[1], errpipe[1]); - } else - fix_fds(inpipe[0], outpipe[1], 2); + if (socketpair(AF_UNIX, SOCK_STREAM, 0, inpipe) || + socketpair(AF_UNIX, SOCK_STREAM, 0, outpipe) || + (stderr_fd && socketpair(AF_UNIX, SOCK_STREAM, 0, errpipe))) { + perror("socketpair"); + exit(1); + } + switch (*pid = fork()) { + case -1: + perror("fork"); + exit(-1); + case 0: + if (stderr_fd) { + fix_fds(inpipe[0], outpipe[1], errpipe[1]); + } else + fix_fds(inpipe[0], outpipe[1], 2); - if (exec_func != NULL) - exec_func(cmdline); - exit(-1); - default:; - } - close(inpipe[0]); - close(outpipe[1]); - *stdin_fd = inpipe[1]; - *stdout_fd = outpipe[0]; - if (stderr_fd) { - close(errpipe[1]); - *stderr_fd = errpipe[0]; - } + if (exec_func != NULL) + exec_func(cmdline); + exit(-1); + default:; + } + close(inpipe[0]); + close(outpipe[1]); + *stdin_fd = inpipe[1]; + *stdout_fd = outpipe[0]; + if (stderr_fd) { + close(errpipe[1]); + *stderr_fd = errpipe[0]; + } } diff --git a/qrexec-lib/ioall.c b/qrexec-lib/ioall.c index ef04e0b..7a3f249 100644 --- a/qrexec-lib/ioall.c +++ b/qrexec-lib/ioall.c @@ -27,90 +27,90 @@ void perror_wrapper(const char * msg) { - int prev=errno; - perror(msg); - errno=prev; + int prev=errno; + perror(msg); + errno=prev; } void set_nonblock(int fd) { - int fl = fcntl(fd, F_GETFL, 0); - if (fl & O_NONBLOCK) - return; - fcntl(fd, F_SETFL, fl | O_NONBLOCK); + int fl = fcntl(fd, F_GETFL, 0); + if (fl & O_NONBLOCK) + return; + fcntl(fd, F_SETFL, fl | O_NONBLOCK); } void set_block(int fd) { - int fl = fcntl(fd, F_GETFL, 0); - if (!(fl & O_NONBLOCK)) - return; - fcntl(fd, F_SETFL, fl & ~O_NONBLOCK); + int fl = fcntl(fd, F_GETFL, 0); + if (!(fl & O_NONBLOCK)) + return; + fcntl(fd, F_SETFL, fl & ~O_NONBLOCK); } int write_all(int fd, const void *buf, int size) { - int written = 0; - int ret; - while (written < size) { - ret = write(fd, (char *) buf + written, size - written); - if (ret == -1 && errno == EINTR) - continue; - if (ret <= 0) { - return 0; - } - written += ret; - } -// fprintf(stderr, "sent %d bytes\n", size); - return 1; + int written = 0; + int ret; + while (written < size) { + ret = write(fd, (char *) buf + written, size - written); + if (ret == -1 && errno == EINTR) + continue; + if (ret <= 0) { + return 0; + } + written += ret; + } + // fprintf(stderr, "sent %d bytes\n", size); + return 1; } int read_all(int fd, void *buf, int size) { - int got_read = 0; - int ret; - while (got_read < size) { - ret = read(fd, (char *) buf + got_read, size - got_read); - if (ret == -1 && errno == EINTR) - continue; - if (ret == 0) { - errno = 0; - fprintf(stderr, "EOF\n"); - return 0; - } - if (ret < 0) { - if (errno != EAGAIN) - perror_wrapper("read"); - return 0; - } - if (got_read == 0) { - // force blocking operation on further reads - set_block(fd); - } - got_read += ret; - } -// fprintf(stderr, "read %d bytes\n", size); - return 1; + int got_read = 0; + int ret; + while (got_read < size) { + ret = read(fd, (char *) buf + got_read, size - got_read); + if (ret == -1 && errno == EINTR) + continue; + if (ret == 0) { + errno = 0; + fprintf(stderr, "EOF\n"); + return 0; + } + if (ret < 0) { + if (errno != EAGAIN) + perror_wrapper("read"); + return 0; + } + if (got_read == 0) { + // force blocking operation on further reads + set_block(fd); + } + got_read += ret; + } + // fprintf(stderr, "read %d bytes\n", size); + return 1; } int copy_fd_all(int fdout, int fdin) { - int ret; - char buf[4096]; - for (;;) { - ret = read(fdin, buf, sizeof(buf)); - if (ret == -1 && errno == EINTR) - continue; - if (!ret) - break; - if (ret < 0) { - perror_wrapper("read"); - return 0; - } - if (!write_all(fdout, buf, ret)) { - perror_wrapper("write"); - return 0; - } - } - return 1; + int ret; + char buf[4096]; + for (;;) { + ret = read(fdin, buf, sizeof(buf)); + if (ret == -1 && errno == EINTR) + continue; + if (!ret) + break; + if (ret < 0) { + perror_wrapper("read"); + return 0; + } + if (!write_all(fdout, buf, ret)) { + perror_wrapper("write"); + return 0; + } + } + return 1; } diff --git a/qrexec-lib/libqrexec-utils.h b/qrexec-lib/libqrexec-utils.h index e0c0788..bd34afc 100644 --- a/qrexec-lib/libqrexec-utils.h +++ b/qrexec-lib/libqrexec-utils.h @@ -24,8 +24,8 @@ #include struct buffer { - char *data; - int buflen; + char *data; + int buflen; }; /* return codes for buffered writes */ @@ -48,7 +48,7 @@ int write_stdin(int fd, const char *data, int len, struct buffer *buffer); int fork_and_flush_stdin(int fd, struct buffer *buffer); void do_fork_exec(const char *cmdline, int *pid, int *stdin_fd, int *stdout_fd, - int *stderr_fd); + int *stderr_fd); void wait_for_vchan_or_argfd(libvchan_t *vchan, int max, fd_set * rdset, fd_set * wrset); int read_vchan_all(libvchan_t *vchan, void *data, size_t size); int write_vchan_all(libvchan_t *vchan, const void *data, size_t size); diff --git a/qrexec-lib/libqubes-rpc-filecopy.h b/qrexec-lib/libqubes-rpc-filecopy.h index 1fbaaf8..a0732b7 100644 --- a/qrexec-lib/libqubes-rpc-filecopy.h +++ b/qrexec-lib/libqubes-rpc-filecopy.h @@ -35,32 +35,32 @@ #include struct file_header { - unsigned int namelen; - unsigned int mode; - unsigned long long filelen; - unsigned int atime; - unsigned int atime_nsec; - unsigned int mtime; - unsigned int mtime_nsec; + unsigned int namelen; + unsigned int mode; + unsigned long long filelen; + unsigned int atime; + unsigned int atime_nsec; + unsigned int mtime; + unsigned int mtime_nsec; }; struct result_header { - uint32_t error_code; - uint32_t _pad; - uint64_t crc32; + uint32_t error_code; + uint32_t _pad; + uint64_t crc32; } __attribute__((packed)); /* optional info about last processed file */ struct result_header_ext { - uint32_t last_namelen; - char last_name[0]; + uint32_t last_namelen; + char last_name[0]; } __attribute__((packed)); enum { - COPY_FILE_OK, - COPY_FILE_READ_EOF, - COPY_FILE_READ_ERROR, - COPY_FILE_WRITE_ERROR + COPY_FILE_OK, + COPY_FILE_READ_EOF, + COPY_FILE_READ_ERROR, + COPY_FILE_WRITE_ERROR }; /* feedback handling */ diff --git a/qrexec-lib/pack.c b/qrexec-lib/pack.c index 2a30f45..e5f7f19 100644 --- a/qrexec-lib/pack.c +++ b/qrexec-lib/pack.c @@ -34,91 +34,91 @@ _Noreturn static void call_error_handler(const char *fmt, ...) static int write_all_with_crc(int fd, const void *buf, int size) { - crc32_sum = Crc32_ComputeBuf(crc32_sum, buf, size); - return write_all(fd, buf, size); + crc32_sum = Crc32_ComputeBuf(crc32_sum, buf, size); + return write_all(fd, buf, size); } void notify_end_and_wait_for_result(void) { - struct file_header end_hdr; + struct file_header end_hdr; - /* nofity end of transfer */ - memset(&end_hdr, 0, sizeof(end_hdr)); - end_hdr.namelen = 0; - end_hdr.filelen = 0; - write_all_with_crc(1, &end_hdr, sizeof(end_hdr)); + /* nofity end of transfer */ + memset(&end_hdr, 0, sizeof(end_hdr)); + end_hdr.namelen = 0; + end_hdr.filelen = 0; + write_all_with_crc(1, &end_hdr, sizeof(end_hdr)); - set_block(0); - wait_for_result(); + set_block(0); + wait_for_result(); } void wait_for_result(void) { - struct result_header hdr; - struct result_header_ext hdr_ext; - char last_filename[MAX_PATH_LENGTH + 1]; - char last_filename_prefix[] = "; Last file: "; + struct result_header hdr; + struct result_header_ext hdr_ext; + char last_filename[MAX_PATH_LENGTH + 1]; + char last_filename_prefix[] = "; Last file: "; - if (!read_all(0, &hdr, sizeof(hdr))) { - if (errno == EAGAIN) { - // no result sent and stdin still open - return; - } else { - // other read error or EOF - exit(1); // hopefully remote has produced error message - } - } - if (!read_all(0, &hdr_ext, sizeof(hdr_ext))) { - // remote used old result_header struct - hdr_ext.last_namelen = 0; - } - if (hdr_ext.last_namelen > MAX_PATH_LENGTH) { - // read only at most MAX_PATH_LENGTH chars - hdr_ext.last_namelen = MAX_PATH_LENGTH; - } - if (!read_all(0, last_filename, hdr_ext.last_namelen)) { - fprintf(stderr, "Failed to get last filename\n"); - hdr_ext.last_namelen = 0; - } - last_filename[hdr_ext.last_namelen] = '\0'; - if (!hdr_ext.last_namelen) - /* set prefix to empty string */ - last_filename_prefix[0] = '\0'; + if (!read_all(0, &hdr, sizeof(hdr))) { + if (errno == EAGAIN) { + // no result sent and stdin still open + return; + } else { + // other read error or EOF + exit(1); // hopefully remote has produced error message + } + } + if (!read_all(0, &hdr_ext, sizeof(hdr_ext))) { + // remote used old result_header struct + hdr_ext.last_namelen = 0; + } + if (hdr_ext.last_namelen > MAX_PATH_LENGTH) { + // read only at most MAX_PATH_LENGTH chars + hdr_ext.last_namelen = MAX_PATH_LENGTH; + } + if (!read_all(0, last_filename, hdr_ext.last_namelen)) { + fprintf(stderr, "Failed to get last filename\n"); + hdr_ext.last_namelen = 0; + } + last_filename[hdr_ext.last_namelen] = '\0'; + if (!hdr_ext.last_namelen) + /* set prefix to empty string */ + last_filename_prefix[0] = '\0'; - errno = hdr.error_code; - if (hdr.error_code != 0) { - switch (hdr.error_code) { - case EEXIST: - call_error_handler("File copy: not overwriting existing file. Clean QubesIncoming dir, and retry copy%s%s", last_filename_prefix, last_filename); - break; - case EINVAL: - call_error_handler("File copy: Corrupted data from packer%s%s", last_filename_prefix, last_filename); - break; - case EDQUOT: - if (ignore_quota_error) { - /* skip also CRC check as sender and receiver might be - * desynchronized in this case */ - return; - } - /* fall though */ - default: - call_error_handler("File copy: %s%s%s", - strerror(hdr.error_code), last_filename_prefix, last_filename); - } - } - if (hdr.crc32 != crc32_sum) { - call_error_handler("File transfer failed: checksum mismatch"); - } + errno = hdr.error_code; + if (hdr.error_code != 0) { + switch (hdr.error_code) { + case EEXIST: + call_error_handler("File copy: not overwriting existing file. Clean QubesIncoming dir, and retry copy%s%s", last_filename_prefix, last_filename); + break; + case EINVAL: + call_error_handler("File copy: Corrupted data from packer%s%s", last_filename_prefix, last_filename); + break; + case EDQUOT: + if (ignore_quota_error) { + /* skip also CRC check as sender and receiver might be + * desynchronized in this case */ + return; + } + /* fall though */ + default: + call_error_handler("File copy: %s%s%s", + strerror(hdr.error_code), last_filename_prefix, last_filename); + } + } + if (hdr.crc32 != crc32_sum) { + call_error_handler("File transfer failed: checksum mismatch"); + } } void write_headers(const struct file_header *hdr, const char *filename) { - if (!write_all_with_crc(1, hdr, sizeof(*hdr)) - || !write_all_with_crc(1, filename, hdr->namelen)) { - set_block(0); - wait_for_result(); - exit(1); - } + if (!write_all_with_crc(1, hdr, sizeof(*hdr)) + || !write_all_with_crc(1, filename, hdr->namelen)) { + set_block(0); + wait_for_result(); + exit(1); + } } int copy_file_with_crc(int outfd, int infd, long long size) { @@ -127,100 +127,100 @@ int copy_file_with_crc(int outfd, int infd, long long size) { int single_file_processor(const char *filename, const struct stat *st) { - struct file_header hdr; - int fd; - mode_t mode = st->st_mode; + struct file_header hdr; + int fd; + mode_t mode = st->st_mode; - hdr.namelen = strlen(filename) + 1; - hdr.mode = mode; - hdr.atime = st->st_atim.tv_sec; - hdr.atime_nsec = st->st_atim.tv_nsec; - hdr.mtime = st->st_mtim.tv_sec; - hdr.mtime_nsec = st->st_mtim.tv_nsec; + hdr.namelen = strlen(filename) + 1; + hdr.mode = mode; + hdr.atime = st->st_atim.tv_sec; + hdr.atime_nsec = st->st_atim.tv_nsec; + hdr.mtime = st->st_mtim.tv_sec; + hdr.mtime_nsec = st->st_mtim.tv_nsec; - if (S_ISREG(mode)) { - int ret; - fd = open(filename, O_RDONLY); - if (fd < 0) - call_error_handler("open %s", filename); - hdr.filelen = st->st_size; - write_headers(&hdr, filename); - ret = copy_file(1, fd, hdr.filelen, &crc32_sum); - if (ret != COPY_FILE_OK) { - if (ret != COPY_FILE_WRITE_ERROR) - call_error_handler("Copying file %s: %s", filename, - copy_file_status_to_str(ret)); - else { - set_block(0); - wait_for_result(); - exit(1); - } - } - close(fd); - } - if (S_ISDIR(mode)) { - hdr.filelen = 0; - write_headers(&hdr, filename); - } - if (S_ISLNK(mode)) { - char name[st->st_size + 1]; - if (readlink(filename, name, sizeof(name)) != st->st_size) - call_error_handler("readlink %s", filename); - hdr.filelen = st->st_size; - write_headers(&hdr, filename); - if (!write_all_with_crc(1, name, st->st_size)) { - set_block(0); - wait_for_result(); - exit(1); - } - } - // check for possible error from qfile-unpacker - wait_for_result(); - return 0; + if (S_ISREG(mode)) { + int ret; + fd = open(filename, O_RDONLY); + if (fd < 0) + call_error_handler("open %s", filename); + hdr.filelen = st->st_size; + write_headers(&hdr, filename); + ret = copy_file(1, fd, hdr.filelen, &crc32_sum); + if (ret != COPY_FILE_OK) { + if (ret != COPY_FILE_WRITE_ERROR) + call_error_handler("Copying file %s: %s", filename, + copy_file_status_to_str(ret)); + else { + set_block(0); + wait_for_result(); + exit(1); + } + } + close(fd); + } + if (S_ISDIR(mode)) { + hdr.filelen = 0; + write_headers(&hdr, filename); + } + if (S_ISLNK(mode)) { + char name[st->st_size + 1]; + if (readlink(filename, name, sizeof(name)) != st->st_size) + call_error_handler("readlink %s", filename); + hdr.filelen = st->st_size; + write_headers(&hdr, filename); + if (!write_all_with_crc(1, name, st->st_size)) { + set_block(0); + wait_for_result(); + exit(1); + } + } + // check for possible error from qfile-unpacker + wait_for_result(); + return 0; } int do_fs_walk(const char *file, int ignore_symlinks) { - char *newfile; - struct stat st; - struct dirent *ent; - DIR *dir; + char *newfile; + struct stat st; + struct dirent *ent; + DIR *dir; - if (lstat(file, &st)) - call_error_handler("stat %s", file); + if (lstat(file, &st)) + call_error_handler("stat %s", file); if (S_ISLNK(st.st_mode) && ignore_symlinks) return 0; - single_file_processor(file, &st); - if (!S_ISDIR(st.st_mode)) - return 0; - dir = opendir(file); - if (!dir) - call_error_handler("opendir %s", file); - while ((ent = readdir(dir))) { - char *fname = ent->d_name; - if (!strcmp(fname, ".") || !strcmp(fname, "..")) - continue; - if (asprintf(&newfile, "%s/%s", file, fname) >= 0) { - do_fs_walk(newfile, ignore_symlinks); - free(newfile); - } else { - fprintf(stderr, "asprintf failed\n"); - exit(1); - } - } - closedir(dir); - // directory metadata is resent; this makes the code simple, - // and the atime/mtime is set correctly at the second time - single_file_processor(file, &st); - return 0; + single_file_processor(file, &st); + if (!S_ISDIR(st.st_mode)) + return 0; + dir = opendir(file); + if (!dir) + call_error_handler("opendir %s", file); + while ((ent = readdir(dir))) { + char *fname = ent->d_name; + if (!strcmp(fname, ".") || !strcmp(fname, "..")) + continue; + if (asprintf(&newfile, "%s/%s", file, fname) >= 0) { + do_fs_walk(newfile, ignore_symlinks); + free(newfile); + } else { + fprintf(stderr, "asprintf failed\n"); + exit(1); + } + } + closedir(dir); + // directory metadata is resent; this makes the code simple, + // and the atime/mtime is set correctly at the second time + single_file_processor(file, &st); + return 0; } void qfile_pack_init(void) { crc32_sum = 0; ignore_quota_error = 0; - // this will allow checking for possible feedback packet in the middle of transfer - set_nonblock(0); - signal(SIGPIPE, SIG_IGN); + // this will allow checking for possible feedback packet in the middle of transfer + set_nonblock(0); + signal(SIGPIPE, SIG_IGN); error_handler = NULL; } diff --git a/qrexec-lib/txrx-vchan.c b/qrexec-lib/txrx-vchan.c index fc6f774..8c21cce 100644 --- a/qrexec-lib/txrx-vchan.c +++ b/qrexec-lib/txrx-vchan.c @@ -28,51 +28,51 @@ int wait_for_vchan_or_argfd_once(libvchan_t *ctrl, int max, fd_set * rdset, fd_set * wrset) { - int vfd, ret; - struct timespec tv = { 1, 100000000 }; - sigset_t empty_set; + int vfd, ret; + struct timespec tv = { 1, 100000000 }; + sigset_t empty_set; - sigemptyset(&empty_set); + sigemptyset(&empty_set); - vfd = libvchan_fd_for_select(ctrl); - FD_SET(vfd, rdset); - if (vfd > max) - max = vfd; - max++; - ret = pselect(max, rdset, wrset, NULL, &tv, &empty_set); - if (ret < 0) { - if (errno != EINTR) { - perror("select"); - exit(1); - } else { - FD_ZERO(rdset); - FD_ZERO(wrset); - fprintf(stderr, "eintr\n"); - return 1; - } + vfd = libvchan_fd_for_select(ctrl); + FD_SET(vfd, rdset); + if (vfd > max) + max = vfd; + max++; + ret = pselect(max, rdset, wrset, NULL, &tv, &empty_set); + if (ret < 0) { + if (errno != EINTR) { + perror("select"); + exit(1); + } else { + FD_ZERO(rdset); + FD_ZERO(wrset); + fprintf(stderr, "eintr\n"); + return 1; + } - } - if (!libvchan_is_open(ctrl)) { - fprintf(stderr, "libvchan_is_eof\n"); - exit(0); - } - if (FD_ISSET(vfd, rdset)) - // the following will never block; we need to do this to - // clear libvchan_fd pending state - libvchan_wait(ctrl); - if (libvchan_data_ready(ctrl)) - return 1; - return ret; + } + if (!libvchan_is_open(ctrl)) { + fprintf(stderr, "libvchan_is_eof\n"); + exit(0); + } + if (FD_ISSET(vfd, rdset)) + // the following will never block; we need to do this to + // clear libvchan_fd pending state + libvchan_wait(ctrl); + if (libvchan_data_ready(ctrl)) + return 1; + return ret; } void wait_for_vchan_or_argfd(libvchan_t *ctrl, int max, fd_set * rdset, fd_set * wrset) { - fd_set r = *rdset, w = *wrset; - do { - *rdset = r; - *wrset = w; - } - while (wait_for_vchan_or_argfd_once(ctrl, max, rdset, wrset) == 0); + fd_set r = *rdset, w = *wrset; + do { + *rdset = r; + *wrset = w; + } + while (wait_for_vchan_or_argfd_once(ctrl, max, rdset, wrset) == 0); } int write_vchan_all(libvchan_t *vchan, const void *data, size_t size) { diff --git a/qrexec-lib/unix-server.c b/qrexec-lib/unix-server.c index 5adf2b4..a861b83 100644 --- a/qrexec-lib/unix-server.c +++ b/qrexec-lib/unix-server.c @@ -29,45 +29,45 @@ int get_server_socket(const char *socket_address) { - struct sockaddr_un sockname; - int s; + struct sockaddr_un sockname; + int s; - unlink(socket_address); + unlink(socket_address); - s = socket(AF_UNIX, SOCK_STREAM, 0); - if (s < 0) { - printf("socket() failed\n"); - exit(1); - } - memset(&sockname, 0, sizeof(sockname)); - sockname.sun_family = AF_UNIX; - strncpy(sockname.sun_path, socket_address, sizeof sockname.sun_path); - sockname.sun_path[sizeof sockname.sun_path - 1] = 0; + s = socket(AF_UNIX, SOCK_STREAM, 0); + if (s < 0) { + printf("socket() failed\n"); + exit(1); + } + memset(&sockname, 0, sizeof(sockname)); + sockname.sun_family = AF_UNIX; + strncpy(sockname.sun_path, socket_address, sizeof sockname.sun_path); + sockname.sun_path[sizeof sockname.sun_path - 1] = 0; - if (bind(s, (struct sockaddr *) &sockname, sizeof(sockname)) == -1) { - printf("bind() failed\n"); - close(s); - exit(1); - } -// chmod(sockname.sun_path, 0666); - if (listen(s, 5) == -1) { - perror("listen() failed\n"); - close(s); - exit(1); - } - return s; + if (bind(s, (struct sockaddr *) &sockname, sizeof(sockname)) == -1) { + printf("bind() failed\n"); + close(s); + exit(1); + } + // chmod(sockname.sun_path, 0666); + if (listen(s, 5) == -1) { + perror("listen() failed\n"); + close(s); + exit(1); + } + return s; } int do_accept(int s) { - struct sockaddr_un peer; - unsigned int addrlen; - int fd; - addrlen = sizeof(peer); - fd = accept(s, (struct sockaddr *) &peer, &addrlen); - if (fd == -1) { - perror("unix accept"); - exit(1); - } - return fd; + struct sockaddr_un peer; + unsigned int addrlen; + int fd; + addrlen = sizeof(peer); + fd = accept(s, (struct sockaddr *) &peer, &addrlen); + if (fd == -1) { + perror("unix accept"); + exit(1); + } + return fd; } diff --git a/qrexec-lib/unpack.c b/qrexec-lib/unpack.c index 9c3fa48..3f548da 100644 --- a/qrexec-lib/unpack.c +++ b/qrexec-lib/unpack.c @@ -39,206 +39,206 @@ void send_status_and_crc(int code, const char *last_filename); void do_exit(int code, const char *last_filename) { - close(0); - send_status_and_crc(code, last_filename); - exit(code); + close(0); + send_status_and_crc(code, last_filename); + exit(code); } void set_size_limit(unsigned long long new_bytes_limit, unsigned long long new_files_limit) { - bytes_limit = new_bytes_limit; - files_limit = new_files_limit; + bytes_limit = new_bytes_limit; + files_limit = new_files_limit; } void set_verbose(int value) { - verbose = value; + verbose = value; } void set_procfs_fd(int value) { - procdir_fd = value; - use_tmpfile = 1; + procdir_fd = value; + use_tmpfile = 1; } unsigned long crc32_sum = 0; int read_all_with_crc(int fd, void *buf, int size) { - int ret; - ret = read_all(fd, buf, size); - if (ret) - crc32_sum = Crc32_ComputeBuf(crc32_sum, buf, size); - return ret; + int ret; + ret = read_all(fd, buf, size); + if (ret) + crc32_sum = Crc32_ComputeBuf(crc32_sum, buf, size); + return ret; } void send_status_and_crc(int code, const char *last_filename) { - struct result_header hdr; - struct result_header_ext hdr_ext; - int saved_errno; + struct result_header hdr; + struct result_header_ext hdr_ext; + int saved_errno; - saved_errno = errno; - hdr.error_code = code; - hdr.crc32 = crc32_sum; - if (!write_all(1, &hdr, sizeof(hdr))) - perror("write status"); - if (last_filename) { - hdr_ext.last_namelen = strlen(last_filename); - if (!write_all(1, &hdr_ext, sizeof(hdr_ext))) - perror("write status ext"); - if (!write_all(1, last_filename, hdr_ext.last_namelen)) - perror("write last_filename"); - } - errno = saved_errno; + saved_errno = errno; + hdr.error_code = code; + hdr.crc32 = crc32_sum; + if (!write_all(1, &hdr, sizeof(hdr))) + perror("write status"); + if (last_filename) { + hdr_ext.last_namelen = strlen(last_filename); + if (!write_all(1, &hdr_ext, sizeof(hdr_ext))) + perror("write status ext"); + if (!write_all(1, last_filename, hdr_ext.last_namelen)) + perror("write last_filename"); + } + errno = saved_errno; } void fix_times_and_perms(struct file_header *untrusted_hdr, - const char *untrusted_name) + const char *untrusted_name) { - struct timeval times[2] = - { {untrusted_hdr->atime, untrusted_hdr->atime_nsec / 1000}, - {untrusted_hdr->mtime, - untrusted_hdr->mtime_nsec / 1000} - }; - if (chmod(untrusted_name, untrusted_hdr->mode & 07777)) /* safe because of chroot */ - do_exit(errno, untrusted_name); - if (utimes(untrusted_name, times)) /* as above */ - do_exit(errno, untrusted_name); + struct timeval times[2] = + { + {untrusted_hdr->atime, untrusted_hdr->atime_nsec / 1000}, + {untrusted_hdr->mtime, untrusted_hdr->mtime_nsec / 1000} + }; + if (chmod(untrusted_name, untrusted_hdr->mode & 07777)) /* safe because of chroot */ + do_exit(errno, untrusted_name); + if (utimes(untrusted_name, times)) /* as above */ + do_exit(errno, untrusted_name); } void process_one_file_reg(struct file_header *untrusted_hdr, - const char *untrusted_name) + const char *untrusted_name) { - int ret; - int fdout = -1; + int ret; + int fdout = -1; - /* make the file inaccessible until fully written */ - if (use_tmpfile) { - fdout = open(".", O_WRONLY | O_TMPFILE, 0700); - if (fdout < 0) { - if (errno==ENOENT || /* most likely, kernel too old for O_TMPFILE */ - errno==EOPNOTSUPP) /* filesystem has no support for O_TMPFILE */ - use_tmpfile = 0; - else - do_exit(errno, untrusted_name); - } - } - if (fdout < 0) - fdout = open(untrusted_name, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0000); /* safe because of chroot */ - if (fdout < 0) - do_exit(errno, untrusted_name); - /* sizes are signed elsewhere */ - if (untrusted_hdr->filelen > LLONG_MAX || (bytes_limit && untrusted_hdr->filelen > bytes_limit)) - do_exit(EDQUOT, untrusted_name); - if (bytes_limit && total_bytes > bytes_limit - untrusted_hdr->filelen) - do_exit(EDQUOT, untrusted_name); - total_bytes += untrusted_hdr->filelen; - ret = copy_file(fdout, 0, untrusted_hdr->filelen, &crc32_sum); - if (ret != COPY_FILE_OK) { - if (ret == COPY_FILE_READ_EOF - || ret == COPY_FILE_READ_ERROR) - do_exit(LEGAL_EOF, untrusted_name); // hopefully remote will produce error message - else - do_exit(errno, untrusted_name); - } - if (use_tmpfile) { - char fd_str[7]; - snprintf(fd_str, sizeof(fd_str), "%d", fdout); - if (linkat(procdir_fd, fd_str, AT_FDCWD, untrusted_name, AT_SYMLINK_FOLLOW) < 0) - do_exit(errno, untrusted_name); - } - close(fdout); - fix_times_and_perms(untrusted_hdr, untrusted_name); + /* make the file inaccessible until fully written */ + if (use_tmpfile) { + fdout = open(".", O_WRONLY | O_TMPFILE, 0700); + if (fdout < 0) { + if (errno==ENOENT || /* most likely, kernel too old for O_TMPFILE */ + errno==EOPNOTSUPP) /* filesystem has no support for O_TMPFILE */ + use_tmpfile = 0; + else + do_exit(errno, untrusted_name); + } + } + if (fdout < 0) + fdout = open(untrusted_name, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0000); /* safe because of chroot */ + if (fdout < 0) + do_exit(errno, untrusted_name); + /* sizes are signed elsewhere */ + if (untrusted_hdr->filelen > LLONG_MAX || (bytes_limit && untrusted_hdr->filelen > bytes_limit)) + do_exit(EDQUOT, untrusted_name); + if (bytes_limit && total_bytes > bytes_limit - untrusted_hdr->filelen) + do_exit(EDQUOT, untrusted_name); + total_bytes += untrusted_hdr->filelen; + ret = copy_file(fdout, 0, untrusted_hdr->filelen, &crc32_sum); + if (ret != COPY_FILE_OK) { + if (ret == COPY_FILE_READ_EOF + || ret == COPY_FILE_READ_ERROR) + do_exit(LEGAL_EOF, untrusted_name); // hopefully remote will produce error message + else + do_exit(errno, untrusted_name); + } + if (use_tmpfile) { + char fd_str[7]; + snprintf(fd_str, sizeof(fd_str), "%d", fdout); + if (linkat(procdir_fd, fd_str, AT_FDCWD, untrusted_name, AT_SYMLINK_FOLLOW) < 0) + do_exit(errno, untrusted_name); + } + close(fdout); + fix_times_and_perms(untrusted_hdr, untrusted_name); } void process_one_file_dir(struct file_header *untrusted_hdr, - const char *untrusted_name) + const char *untrusted_name) { -// fix perms only when the directory is sent for the second time -// it allows to transfer r.x directory contents, as we create it rwx initially - struct stat buf; - if (!mkdir(untrusted_name, 0700)) /* safe because of chroot */ - return; - if (errno != EEXIST) - do_exit(errno, untrusted_name); - if (stat(untrusted_name,&buf) < 0) - do_exit(errno, untrusted_name); - total_bytes += buf.st_size; - /* size accumulated after the fact, so don't check limit here */ - fix_times_and_perms(untrusted_hdr, untrusted_name); + // fix perms only when the directory is sent for the second time + // it allows to transfer r.x directory contents, as we create it rwx initially + struct stat buf; + if (!mkdir(untrusted_name, 0700)) /* safe because of chroot */ + return; + if (errno != EEXIST) + do_exit(errno, untrusted_name); + if (stat(untrusted_name,&buf) < 0) + do_exit(errno, untrusted_name); + total_bytes += buf.st_size; + /* size accumulated after the fact, so don't check limit here */ + fix_times_and_perms(untrusted_hdr, untrusted_name); } void process_one_file_link(struct file_header *untrusted_hdr, - const char *untrusted_name) + const char *untrusted_name) { - char untrusted_content[MAX_PATH_LENGTH]; - unsigned int filelen; - if (untrusted_hdr->filelen > MAX_PATH_LENGTH - 1) - do_exit(ENAMETOOLONG, untrusted_name); - filelen = untrusted_hdr->filelen; /* sanitized above */ - total_bytes += filelen; - if (bytes_limit && total_bytes > bytes_limit) - do_exit(EDQUOT, untrusted_name); - if (!read_all_with_crc(0, untrusted_content, filelen)) - do_exit(LEGAL_EOF, untrusted_name); // hopefully remote has produced error message - untrusted_content[filelen] = 0; - if (symlink(untrusted_content, untrusted_name)) /* safe because of chroot */ - do_exit(errno, untrusted_name); + char untrusted_content[MAX_PATH_LENGTH]; + unsigned int filelen; + if (untrusted_hdr->filelen > MAX_PATH_LENGTH - 1) + do_exit(ENAMETOOLONG, untrusted_name); + filelen = untrusted_hdr->filelen; /* sanitized above */ + total_bytes += filelen; + if (bytes_limit && total_bytes > bytes_limit) + do_exit(EDQUOT, untrusted_name); + if (!read_all_with_crc(0, untrusted_content, filelen)) + do_exit(LEGAL_EOF, untrusted_name); // hopefully remote has produced error message + untrusted_content[filelen] = 0; + if (symlink(untrusted_content, untrusted_name)) /* safe because of chroot */ + do_exit(errno, untrusted_name); } void process_one_file(struct file_header *untrusted_hdr) { - unsigned int namelen; - if (untrusted_hdr->namelen > MAX_PATH_LENGTH - 1) - do_exit(ENAMETOOLONG, NULL); /* filename too long so not received at all */ - namelen = untrusted_hdr->namelen; /* sanitized above */ - if (!read_all_with_crc(0, untrusted_namebuf, namelen)) - do_exit(LEGAL_EOF, NULL); // hopefully remote has produced error message - untrusted_namebuf[namelen] = 0; - if (S_ISREG(untrusted_hdr->mode)) - process_one_file_reg(untrusted_hdr, untrusted_namebuf); - else if (S_ISLNK(untrusted_hdr->mode)) - process_one_file_link(untrusted_hdr, untrusted_namebuf); - else if (S_ISDIR(untrusted_hdr->mode)) - process_one_file_dir(untrusted_hdr, untrusted_namebuf); - else - do_exit(EINVAL, untrusted_namebuf); - if (verbose && !S_ISDIR(untrusted_hdr->mode)) - fprintf(stderr, "%s\n", untrusted_namebuf); + unsigned int namelen; + if (untrusted_hdr->namelen > MAX_PATH_LENGTH - 1) + do_exit(ENAMETOOLONG, NULL); /* filename too long so not received at all */ + namelen = untrusted_hdr->namelen; /* sanitized above */ + if (!read_all_with_crc(0, untrusted_namebuf, namelen)) + do_exit(LEGAL_EOF, NULL); // hopefully remote has produced error message + untrusted_namebuf[namelen] = 0; + if (S_ISREG(untrusted_hdr->mode)) + process_one_file_reg(untrusted_hdr, untrusted_namebuf); + else if (S_ISLNK(untrusted_hdr->mode)) + process_one_file_link(untrusted_hdr, untrusted_namebuf); + else if (S_ISDIR(untrusted_hdr->mode)) + process_one_file_dir(untrusted_hdr, untrusted_namebuf); + else + do_exit(EINVAL, untrusted_namebuf); + if (verbose && !S_ISDIR(untrusted_hdr->mode)) + fprintf(stderr, "%s\n", untrusted_namebuf); } int do_unpack(void) { - struct file_header untrusted_hdr; + struct file_header untrusted_hdr; #ifdef HAVE_SYNCFS - int cwd_fd; - int saved_errno; + int cwd_fd; + int saved_errno; #endif - total_bytes = total_files = 0; - /* initialize checksum */ - crc32_sum = 0; - while (read_all_with_crc(0, &untrusted_hdr, sizeof untrusted_hdr)) { - /* check for end of transfer marker */ - if (untrusted_hdr.namelen == 0) { - errno = 0; - break; - } - total_files++; - if (files_limit && total_files > files_limit) - do_exit(EDQUOT, untrusted_namebuf); - process_one_file(&untrusted_hdr); - } + total_bytes = total_files = 0; + /* initialize checksum */ + crc32_sum = 0; + while (read_all_with_crc(0, &untrusted_hdr, sizeof untrusted_hdr)) { + /* check for end of transfer marker */ + if (untrusted_hdr.namelen == 0) { + errno = 0; + break; + } + total_files++; + if (files_limit && total_files > files_limit) + do_exit(EDQUOT, untrusted_namebuf); + process_one_file(&untrusted_hdr); + } #ifdef HAVE_SYNCFS - saved_errno = errno; - cwd_fd = open(".", O_RDONLY); - if (cwd_fd >= 0 && syncfs(cwd_fd) == 0 && close(cwd_fd) == 0) - errno = saved_errno; + saved_errno = errno; + cwd_fd = open(".", O_RDONLY); + if (cwd_fd >= 0 && syncfs(cwd_fd) == 0 && close(cwd_fd) == 0) + errno = saved_errno; #endif - send_status_and_crc(errno, untrusted_namebuf); - return errno; + send_status_and_crc(errno, untrusted_namebuf); + return errno; } diff --git a/qrexec-lib/write-stdin.c b/qrexec-lib/write-stdin.c index ebf32bf..356f1da 100644 --- a/qrexec-lib/write-stdin.c +++ b/qrexec-lib/write-stdin.c @@ -34,86 +34,86 @@ reports that "fd" is writable. Write as much as possible to fd. */ int flush_client_data(int fd, struct buffer *buffer) { - int ret; - int len; - for (;;) { - len = buffer_len(buffer); - if (!len) { - return WRITE_STDIN_OK; - } - if (len > MAX_DATA_CHUNK) - len = MAX_DATA_CHUNK; - ret = write(fd, buffer_data(buffer), len); - if (ret == -1) { - if (errno != EAGAIN) { - return WRITE_STDIN_ERROR; - } else - return WRITE_STDIN_BUFFERED; - } - // we previously called buffer_remove(buffer, len) - // it will be wrong if we change MAX_DATA_CHUNK to something large - // as pipes writes are atomic only to PIPE_MAX limit - buffer_remove(buffer, ret); - } + int ret; + int len; + for (;;) { + len = buffer_len(buffer); + if (!len) { + return WRITE_STDIN_OK; + } + if (len > MAX_DATA_CHUNK) + len = MAX_DATA_CHUNK; + ret = write(fd, buffer_data(buffer), len); + if (ret == -1) { + if (errno != EAGAIN) { + return WRITE_STDIN_ERROR; + } else + return WRITE_STDIN_BUFFERED; + } + // we previously called buffer_remove(buffer, len) + // it will be wrong if we change MAX_DATA_CHUNK to something large + // as pipes writes are atomic only to PIPE_MAX limit + buffer_remove(buffer, ret); + } } /* -Write "len" bytes from "data" to "fd". If not all written, buffer the rest -to "buffer". -*/ + * Write "len" bytes from "data" to "fd". If not all written, buffer the rest + * to "buffer". + */ int write_stdin(int fd, const char *data, int len, struct buffer *buffer) { - int ret; - int written = 0; + int ret; + int written = 0; - if (buffer_len(buffer)) { - buffer_append(buffer, data, len); - return WRITE_STDIN_BUFFERED; - } - while (written < len) { - ret = write(fd, data + written, len - written); - if (ret == 0) { - perror("write_stdin: write returns 0 ???"); - exit(1); - } - if (ret == -1) { - if (errno != EAGAIN) - return WRITE_STDIN_ERROR; + if (buffer_len(buffer)) { + buffer_append(buffer, data, len); + return WRITE_STDIN_BUFFERED; + } + while (written < len) { + ret = write(fd, data + written, len - written); + if (ret == 0) { + perror("write_stdin: write returns 0 ???"); + exit(1); + } + if (ret == -1) { + if (errno != EAGAIN) + return WRITE_STDIN_ERROR; - buffer_append(buffer, data + written, - len - written); + buffer_append(buffer, data + written, + len - written); - return WRITE_STDIN_BUFFERED; - } - written += ret; - } - return WRITE_STDIN_OK; + return WRITE_STDIN_BUFFERED; + } + written += ret; + } + return WRITE_STDIN_OK; } /* -Data feed process has exited, so we need to clear all control structures for -the client. However, if we have buffered data for the client (which is rare btw), -fire&forget a separate process to flush them. -*/ + * Data feed process has exited, so we need to clear all control structures for + * the client. However, if we have buffered data for the client (which is rare btw), + * fire&forget a separate process to flush them. + */ int fork_and_flush_stdin(int fd, struct buffer *buffer) { - int i; - if (!buffer_len(buffer)) - return 0; - switch (fork()) { - case -1: - perror("fork"); - exit(1); - case 0: - break; - default: - return 1; - } - for (i = 0; i < MAX_FDS; i++) - if (i != fd && i != 2) - close(i); - set_block(fd); - write_all(fd, buffer_data(buffer), buffer_len(buffer)); - _exit(0); + int i; + if (!buffer_len(buffer)) + return 0; + switch (fork()) { + case -1: + perror("fork"); + exit(1); + case 0: + break; + default: + return 1; + } + for (i = 0; i < MAX_FDS; i++) + if (i != fd && i != 2) + close(i); + set_block(fd); + write_all(fd, buffer_data(buffer), buffer_len(buffer)); + _exit(0); }