123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- #define _GNU_SOURCE /* For O_NOFOLLOW. */
- #include <errno.h>
- #include <ioall.h>
- #include <fcntl.h>
- #include <sys/time.h>
- #include <sys/stat.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <stdio.h>
- #include "filecopy.h"
- #include "crc32.h"
- char untrusted_namebuf[MAX_PATH_LENGTH];
- long long bytes_limit = 0;
- long long files_limit = 0;
- long long total_bytes = 0;
- long long total_files = 0;
- void notify_progress(int p1, int p2)
- {
- }
- void set_size_limit(long long new_bytes_limit, long long new_files_limit)
- {
- bytes_limit = new_bytes_limit;
- files_limit = new_files_limit;
- }
- 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 global_status_fd;
- void do_exit(int code)
- {
- int codebuf = code;
- write(global_status_fd, &codebuf, sizeof codebuf);
- exit(0);
- }
- void fix_times_and_perms(struct file_header *untrusted_hdr,
- 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);
- if (utimes(untrusted_name, times)) /* as above */
- do_exit(errno);
- }
- void process_one_file_reg(struct file_header *untrusted_hdr,
- char *untrusted_name)
- {
- int ret;
- int fdout = open(untrusted_name, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0700); /* safe because of chroot */
- if (fdout < 0)
- do_exit(errno);
- total_bytes += untrusted_hdr->filelen;
- if (bytes_limit && total_bytes > bytes_limit)
- do_exit(EDQUOT);
- 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); // hopefully remote will produce error message
- else
- do_exit(errno);
- }
- close(fdout);
- fix_times_and_perms(untrusted_hdr, untrusted_name);
- }
- void process_one_file_dir(struct file_header *untrusted_hdr,
- 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
- if (!mkdir(untrusted_name, 0700)) /* safe because of chroot */
- return;
- if (errno != EEXIST)
- do_exit(errno);
- fix_times_and_perms(untrusted_hdr, untrusted_name);
- }
- void process_one_file_link(struct file_header *untrusted_hdr,
- char *untrusted_name)
- {
- char untrusted_content[MAX_PATH_LENGTH];
- unsigned int filelen;
- if (untrusted_hdr->filelen > MAX_PATH_LENGTH - 1)
- do_exit(ENAMETOOLONG);
- filelen = untrusted_hdr->filelen; /* sanitized above */
- if (!read_all_with_crc(0, untrusted_content, filelen))
- do_exit(LEGAL_EOF); // hopefully remote has produced error message
- untrusted_content[filelen] = 0;
- if (symlink(untrusted_content, untrusted_name)) /* safe because of chroot */
- do_exit(errno);
- }
- void process_one_file(struct file_header *untrusted_hdr)
- {
- unsigned int namelen;
- if (untrusted_hdr->namelen > MAX_PATH_LENGTH - 1)
- do_exit(ENAMETOOLONG);
- namelen = untrusted_hdr->namelen; /* sanitized above */
- if (!read_all_with_crc(0, untrusted_namebuf, namelen))
- do_exit(LEGAL_EOF); // 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);
- }
- void send_status_and_crc() {
- struct result_header hdr;
- int saved_errno;
- saved_errno = errno;
- hdr.error_code = errno;
- hdr.crc32 = crc32_sum;
- write_all(1, &hdr, sizeof(hdr));
- errno = saved_errno;
- }
- void do_unpack(int fd)
- {
- global_status_fd = fd;
- struct file_header untrusted_hdr;
- /* 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;
- }
- process_one_file(&untrusted_hdr);
- total_files++;
- if (files_limit && total_files > files_limit)
- do_exit(EDQUOT);
- }
- send_status_and_crc();
- if (errno)
- do_exit(errno);
- else
- do_exit(LEGAL_EOF);
- }
|