unpack.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. #define _GNU_SOURCE /* For O_NOFOLLOW. */
  2. #include <errno.h>
  3. #include <ioall.h>
  4. #include <fcntl.h>
  5. #include <sys/time.h>
  6. #include <sys/stat.h>
  7. #include <stdlib.h>
  8. #include <unistd.h>
  9. #include <stdio.h>
  10. #include "filecopy.h"
  11. #include "crc32.h"
  12. char untrusted_namebuf[MAX_PATH_LENGTH];
  13. long long bytes_limit = 0;
  14. long long files_limit = 0;
  15. long long total_bytes = 0;
  16. long long total_files = 0;
  17. void notify_progress(int p1, int p2)
  18. {
  19. }
  20. void set_size_limit(long long new_bytes_limit, long long new_files_limit)
  21. {
  22. bytes_limit = new_bytes_limit;
  23. files_limit = new_files_limit;
  24. }
  25. unsigned long crc32_sum = 0;
  26. int read_all_with_crc(int fd, void *buf, int size) {
  27. int ret;
  28. ret = read_all(fd, buf, size);
  29. if (ret)
  30. crc32_sum = Crc32_ComputeBuf(crc32_sum, buf, size);
  31. return ret;
  32. }
  33. int global_status_fd;
  34. void do_exit(int code)
  35. {
  36. int codebuf = code;
  37. write(global_status_fd, &codebuf, sizeof codebuf);
  38. exit(0);
  39. }
  40. void fix_times_and_perms(struct file_header *untrusted_hdr,
  41. char *untrusted_name)
  42. {
  43. struct timeval times[2] =
  44. { {untrusted_hdr->atime, untrusted_hdr->atime_nsec / 1000},
  45. {untrusted_hdr->mtime,
  46. untrusted_hdr->mtime_nsec / 1000}
  47. };
  48. if (chmod(untrusted_name, untrusted_hdr->mode & 07777)) /* safe because of chroot */
  49. do_exit(errno);
  50. if (utimes(untrusted_name, times)) /* as above */
  51. do_exit(errno);
  52. }
  53. void process_one_file_reg(struct file_header *untrusted_hdr,
  54. char *untrusted_name)
  55. {
  56. int ret;
  57. int fdout = open(untrusted_name, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0700); /* safe because of chroot */
  58. if (fdout < 0)
  59. do_exit(errno);
  60. total_bytes += untrusted_hdr->filelen;
  61. if (bytes_limit && total_bytes > bytes_limit)
  62. do_exit(EDQUOT);
  63. ret = copy_file(fdout, 0, untrusted_hdr->filelen, &crc32_sum);
  64. if (ret != COPY_FILE_OK) {
  65. if (ret == COPY_FILE_READ_EOF
  66. || ret == COPY_FILE_READ_ERROR)
  67. do_exit(LEGAL_EOF); // hopefully remote will produce error message
  68. else
  69. do_exit(errno);
  70. }
  71. close(fdout);
  72. fix_times_and_perms(untrusted_hdr, untrusted_name);
  73. }
  74. void process_one_file_dir(struct file_header *untrusted_hdr,
  75. char *untrusted_name)
  76. {
  77. // fix perms only when the directory is sent for the second time
  78. // it allows to transfer r.x directory contents, as we create it rwx initially
  79. if (!mkdir(untrusted_name, 0700)) /* safe because of chroot */
  80. return;
  81. if (errno != EEXIST)
  82. do_exit(errno);
  83. fix_times_and_perms(untrusted_hdr, untrusted_name);
  84. }
  85. void process_one_file_link(struct file_header *untrusted_hdr,
  86. char *untrusted_name)
  87. {
  88. char untrusted_content[MAX_PATH_LENGTH];
  89. unsigned int filelen;
  90. if (untrusted_hdr->filelen > MAX_PATH_LENGTH - 1)
  91. do_exit(ENAMETOOLONG);
  92. filelen = untrusted_hdr->filelen; /* sanitized above */
  93. if (!read_all_with_crc(0, untrusted_content, filelen))
  94. do_exit(LEGAL_EOF); // hopefully remote has produced error message
  95. untrusted_content[filelen] = 0;
  96. if (symlink(untrusted_content, untrusted_name)) /* safe because of chroot */
  97. do_exit(errno);
  98. }
  99. void process_one_file(struct file_header *untrusted_hdr)
  100. {
  101. unsigned int namelen;
  102. if (untrusted_hdr->namelen > MAX_PATH_LENGTH - 1)
  103. do_exit(ENAMETOOLONG);
  104. namelen = untrusted_hdr->namelen; /* sanitized above */
  105. if (!read_all_with_crc(0, untrusted_namebuf, namelen))
  106. do_exit(LEGAL_EOF); // hopefully remote has produced error message
  107. untrusted_namebuf[namelen] = 0;
  108. if (S_ISREG(untrusted_hdr->mode))
  109. process_one_file_reg(untrusted_hdr, untrusted_namebuf);
  110. else if (S_ISLNK(untrusted_hdr->mode))
  111. process_one_file_link(untrusted_hdr, untrusted_namebuf);
  112. else if (S_ISDIR(untrusted_hdr->mode))
  113. process_one_file_dir(untrusted_hdr, untrusted_namebuf);
  114. else
  115. do_exit(EINVAL);
  116. }
  117. void send_status_and_crc() {
  118. struct result_header hdr;
  119. int saved_errno;
  120. saved_errno = errno;
  121. hdr.error_code = errno;
  122. hdr.crc32 = crc32_sum;
  123. write_all(1, &hdr, sizeof(hdr));
  124. errno = saved_errno;
  125. }
  126. void do_unpack(int fd)
  127. {
  128. global_status_fd = fd;
  129. struct file_header untrusted_hdr;
  130. /* initialize checksum */
  131. crc32_sum = 0;
  132. while (read_all_with_crc(0, &untrusted_hdr, sizeof untrusted_hdr)) {
  133. /* check for end of transfer marker */
  134. if (untrusted_hdr.namelen == 0) {
  135. errno = 0;
  136. break;
  137. }
  138. process_one_file(&untrusted_hdr);
  139. total_files++;
  140. if (files_limit && total_files > files_limit)
  141. do_exit(EDQUOT);
  142. }
  143. send_status_and_crc();
  144. if (errno)
  145. do_exit(errno);
  146. else
  147. do_exit(LEGAL_EOF);
  148. }