tarfn.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. /*
  2. * libdpkg - Debian packaging suite library routines
  3. * tarfn.c - tar archive extraction functions
  4. *
  5. * Copyright © 1995 Bruce Perens
  6. * Copyright © 2007-2011, 2013-2015 Guillem Jover <guillem@debian.org>
  7. *
  8. * This is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. */
  21. #include <config.h>
  22. #include <compat.h>
  23. #include <sys/stat.h>
  24. #include <errno.h>
  25. #include <string.h>
  26. #include <pwd.h>
  27. #include <grp.h>
  28. #include <unistd.h>
  29. #include <inttypes.h>
  30. #include <stdlib.h>
  31. #include <stdio.h>
  32. #include <dpkg/macros.h>
  33. #include <dpkg/dpkg.h>
  34. #include <dpkg/tarfn.h>
  35. #define TAR_MAGIC_USTAR "ustar\0" "00"
  36. #define TAR_MAGIC_GNU "ustar " " \0"
  37. struct tar_header {
  38. char name[100];
  39. char mode[8];
  40. char uid[8];
  41. char gid[8];
  42. char size[12];
  43. char mtime[12];
  44. char checksum[8];
  45. char linkflag;
  46. char linkname[100];
  47. /* Only valid on ustar and gnu. */
  48. char magic[8];
  49. char user[32];
  50. char group[32];
  51. char devmajor[8];
  52. char devminor[8];
  53. /* Only valid on ustar. */
  54. char prefix[155];
  55. };
  56. /**
  57. * Convert an ASCII octal string to an intmax_t.
  58. */
  59. static intmax_t
  60. OtoM(const char *s, int size)
  61. {
  62. intmax_t n = 0;
  63. while (*s == ' ') {
  64. s++;
  65. size--;
  66. }
  67. while (--size >= 0 && *s >= '0' && *s <= '7')
  68. n = (n * 010) + (*s++ - '0');
  69. return n;
  70. }
  71. static char *
  72. get_prefix_name(struct tar_header *h)
  73. {
  74. char *path;
  75. m_asprintf(&path, "%.*s/%.*s", (int)sizeof(h->prefix), h->prefix,
  76. (int)sizeof(h->name), h->name);
  77. return path;
  78. }
  79. static mode_t
  80. get_unix_mode(struct tar_header *h)
  81. {
  82. mode_t mode;
  83. enum tar_filetype type;
  84. type = (enum tar_filetype)h->linkflag;
  85. switch (type) {
  86. case TAR_FILETYPE_FILE0:
  87. case TAR_FILETYPE_FILE:
  88. case TAR_FILETYPE_HARDLINK:
  89. mode = S_IFREG;
  90. break;
  91. case TAR_FILETYPE_SYMLINK:
  92. mode = S_IFLNK;
  93. break;
  94. case TAR_FILETYPE_DIR:
  95. mode = S_IFDIR;
  96. break;
  97. case TAR_FILETYPE_CHARDEV:
  98. mode = S_IFCHR;
  99. break;
  100. case TAR_FILETYPE_BLOCKDEV:
  101. mode = S_IFBLK;
  102. break;
  103. case TAR_FILETYPE_FIFO:
  104. mode = S_IFIFO;
  105. break;
  106. default:
  107. mode = 0;
  108. break;
  109. }
  110. mode |= OtoM(h->mode, sizeof(h->mode));
  111. return mode;
  112. }
  113. static long
  114. tar_header_checksum(struct tar_header *h)
  115. {
  116. unsigned char *s = (unsigned char *)h;
  117. unsigned int i;
  118. const size_t checksum_offset = offsetof(struct tar_header, checksum);
  119. long sum;
  120. /* Treat checksum field as all blank. */
  121. sum = ' ' * sizeof(h->checksum);
  122. for (i = checksum_offset; i > 0; i--)
  123. sum += *s++;
  124. /* Skip the real checksum field. */
  125. s += sizeof(h->checksum);
  126. for (i = TARBLKSZ - checksum_offset - sizeof(h->checksum); i > 0; i--)
  127. sum += *s++;
  128. return sum;
  129. }
  130. static int
  131. tar_header_decode(struct tar_header *h, struct tar_entry *d)
  132. {
  133. long checksum;
  134. if (memcmp(h->magic, TAR_MAGIC_GNU, 6) == 0)
  135. d->format = TAR_FORMAT_GNU;
  136. else if (memcmp(h->magic, TAR_MAGIC_USTAR, 6) == 0)
  137. d->format = TAR_FORMAT_USTAR;
  138. else
  139. d->format = TAR_FORMAT_OLD;
  140. d->type = (enum tar_filetype)h->linkflag;
  141. if (d->type == TAR_FILETYPE_FILE0)
  142. d->type = TAR_FILETYPE_FILE;
  143. /* Concatenate prefix and name to support ustar style long names. */
  144. if (d->format == TAR_FORMAT_USTAR && h->prefix[0] != '\0')
  145. d->name = get_prefix_name(h);
  146. else
  147. d->name = m_strndup(h->name, sizeof(h->name));
  148. d->linkname = m_strndup(h->linkname, sizeof(h->linkname));
  149. d->stat.mode = get_unix_mode(h);
  150. d->size = (off_t)OtoM(h->size, sizeof(h->size));
  151. d->mtime = (time_t)OtoM(h->mtime, sizeof(h->mtime));
  152. d->dev = makedev(OtoM(h->devmajor, sizeof(h->devmajor)),
  153. OtoM(h->devminor, sizeof(h->devminor)));
  154. if (*h->user)
  155. d->stat.uname = m_strndup(h->user, sizeof(h->user));
  156. else
  157. d->stat.uname = NULL;
  158. d->stat.uid = (uid_t)OtoM(h->uid, sizeof(h->uid));
  159. if (*h->group)
  160. d->stat.gname = m_strndup(h->group, sizeof(h->group));
  161. else
  162. d->stat.gname = NULL;
  163. d->stat.gid = (gid_t)OtoM(h->gid, sizeof(h->gid));
  164. checksum = OtoM(h->checksum, sizeof(h->checksum));
  165. return tar_header_checksum(h) == checksum;
  166. }
  167. /**
  168. * Decode a GNU longlink or longname from the tar archive.
  169. *
  170. * The way the GNU long{link,name} stuff works is like this:
  171. *
  172. * - The first header is a “dummy” header that contains the size of the
  173. * filename.
  174. * - The next N headers contain the filename.
  175. * - After the headers with the filename comes the “real” header with a
  176. * bogus name or link.
  177. */
  178. static int
  179. tar_gnu_long(void *ctx, const struct tar_operations *ops, struct tar_entry *te,
  180. char **longp)
  181. {
  182. char buf[TARBLKSZ];
  183. char *bp;
  184. int status = 0;
  185. int long_read;
  186. free(*longp);
  187. *longp = bp = m_malloc(te->size);
  188. for (long_read = te->size; long_read > 0; long_read -= TARBLKSZ) {
  189. int copysize;
  190. status = ops->read(ctx, buf, TARBLKSZ);
  191. if (status == TARBLKSZ)
  192. status = 0;
  193. else {
  194. /* Read partial header record? */
  195. if (status > 0) {
  196. errno = 0;
  197. status = -1;
  198. }
  199. /* If we didn't get TARBLKSZ bytes read, punt. */
  200. break;
  201. }
  202. copysize = min(long_read, TARBLKSZ);
  203. memcpy(bp, buf, copysize);
  204. bp += copysize;
  205. }
  206. return status;
  207. }
  208. static void
  209. tar_entry_copy(struct tar_entry *dst, struct tar_entry *src)
  210. {
  211. memcpy(dst, src, sizeof(struct tar_entry));
  212. dst->name = m_strdup(src->name);
  213. dst->linkname = m_strdup(src->linkname);
  214. if (src->stat.uname)
  215. dst->stat.uname = m_strdup(src->stat.uname);
  216. if (src->stat.gname)
  217. dst->stat.gname = m_strdup(src->stat.gname);
  218. }
  219. static void
  220. tar_entry_destroy(struct tar_entry *te)
  221. {
  222. free(te->name);
  223. free(te->linkname);
  224. free(te->stat.uname);
  225. free(te->stat.gname);
  226. }
  227. struct tar_symlink_entry {
  228. struct tar_symlink_entry *next;
  229. struct tar_entry h;
  230. };
  231. /**
  232. * Update the tar entry from system information.
  233. *
  234. * Normalize UID and GID relative to the current system.
  235. */
  236. void
  237. tar_entry_update_from_system(struct tar_entry *te)
  238. {
  239. struct passwd *passwd;
  240. struct group *group;
  241. if (te->stat.uname) {
  242. passwd = getpwnam(te->stat.uname);
  243. if (passwd)
  244. te->stat.uid = passwd->pw_uid;
  245. }
  246. if (te->stat.gname) {
  247. group = getgrnam(te->stat.gname);
  248. if (group)
  249. te->stat.gid = group->gr_gid;
  250. }
  251. }
  252. int
  253. tar_extractor(void *ctx, const struct tar_operations *ops)
  254. {
  255. int status;
  256. char buffer[TARBLKSZ];
  257. struct tar_entry h;
  258. char *next_long_name, *next_long_link;
  259. struct tar_symlink_entry *symlink_head, *symlink_tail, *symlink_node;
  260. next_long_name = NULL;
  261. next_long_link = NULL;
  262. symlink_tail = symlink_head = NULL;
  263. h.name = NULL;
  264. h.linkname = NULL;
  265. h.stat.uname = NULL;
  266. h.stat.gname = NULL;
  267. while ((status = ops->read(ctx, buffer, TARBLKSZ)) == TARBLKSZ) {
  268. int name_len;
  269. if (!tar_header_decode((struct tar_header *)buffer, &h)) {
  270. if (h.name[0] == '\0') {
  271. /* End of tape. */
  272. status = 0;
  273. } else {
  274. /* Indicates broken tarfile:
  275. * “Header checksum error”. */
  276. errno = 0;
  277. status = -1;
  278. }
  279. tar_entry_destroy(&h);
  280. break;
  281. }
  282. if (h.type != TAR_FILETYPE_GNU_LONGLINK &&
  283. h.type != TAR_FILETYPE_GNU_LONGNAME) {
  284. if (next_long_name)
  285. h.name = next_long_name;
  286. if (next_long_link)
  287. h.linkname = next_long_link;
  288. next_long_link = NULL;
  289. next_long_name = NULL;
  290. }
  291. if (h.name[0] == '\0') {
  292. /* Indicates broken tarfile: “Bad header data”. */
  293. errno = 0;
  294. status = -1;
  295. tar_entry_destroy(&h);
  296. break;
  297. }
  298. name_len = strlen(h.name);
  299. switch (h.type) {
  300. case TAR_FILETYPE_FILE:
  301. /* Compatibility with pre-ANSI ustar. */
  302. if (h.name[name_len - 1] != '/') {
  303. status = ops->extract_file(ctx, &h);
  304. break;
  305. }
  306. /* Else, fall through. */
  307. case TAR_FILETYPE_DIR:
  308. if (h.name[name_len - 1] == '/') {
  309. h.name[name_len - 1] = '\0';
  310. }
  311. status = ops->mkdir(ctx, &h);
  312. break;
  313. case TAR_FILETYPE_HARDLINK:
  314. status = ops->link(ctx, &h);
  315. break;
  316. case TAR_FILETYPE_SYMLINK:
  317. symlink_node = m_malloc(sizeof(*symlink_node));
  318. symlink_node->next = NULL;
  319. tar_entry_copy(&symlink_node->h, &h);
  320. if (symlink_head)
  321. symlink_tail->next = symlink_node;
  322. else
  323. symlink_head = symlink_node;
  324. symlink_tail = symlink_node;
  325. status = 0;
  326. break;
  327. case TAR_FILETYPE_CHARDEV:
  328. case TAR_FILETYPE_BLOCKDEV:
  329. case TAR_FILETYPE_FIFO:
  330. status = ops->mknod(ctx, &h);
  331. break;
  332. case TAR_FILETYPE_GNU_LONGLINK:
  333. status = tar_gnu_long(ctx, ops, &h, &next_long_link);
  334. break;
  335. case TAR_FILETYPE_GNU_LONGNAME:
  336. status = tar_gnu_long(ctx, ops, &h, &next_long_name);
  337. break;
  338. default:
  339. /* Indicates broken tarfile: “Bad header field”. */
  340. errno = 0;
  341. status = -1;
  342. }
  343. tar_entry_destroy(&h);
  344. if (status != 0)
  345. /* Pass on status from coroutine. */
  346. break;
  347. }
  348. while (symlink_head) {
  349. symlink_node = symlink_head->next;
  350. if (status == 0)
  351. status = ops->symlink(ctx, &symlink_head->h);
  352. tar_entry_destroy(&symlink_head->h);
  353. free(symlink_head);
  354. symlink_head = symlink_node;
  355. }
  356. /* Make sure we free the long names, in case of a bogus or truncated
  357. * tar archive with long entries not followed by a normal entry. */
  358. free(next_long_name);
  359. free(next_long_link);
  360. if (status > 0) {
  361. /* Indicates broken tarfile: “Read partial header record”. */
  362. errno = 0;
  363. return -1;
  364. } else {
  365. /* Return whatever I/O function returned. */
  366. return status;
  367. }
  368. }