blob: 3075a61a711dc3dae2601a532f7c954d59eea4fd [file] [log] [blame]
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001/*
2** Copyright 1998-2003 University of Illinois Board of Trustees
3** Copyright 1998-2003 Mark D. Roth
4** All rights reserved.
5**
6** append.c - libtar code to append files to a tar archive
7**
8** Mark D. Roth <roth@uiuc.edu>
9** Campus Information Technologies and Educational Services
10** University of Illinois at Urbana-Champaign
11*/
12
13#include <internal.h>
14
15#include <stdio.h>
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050016#include <stdlib.h>
17#include <string.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050018#include <errno.h>
19#include <fcntl.h>
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050020#include <time.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050021#include <sys/param.h>
22#include <sys/types.h>
Ethan Yonker79f88bd2016-12-09 14:52:12 -060023#include <stdbool.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050024
Ethan Yonker71187742017-01-13 13:30:10 -060025#include <sys/capability.h>
26#include <sys/xattr.h>
bigbiff7ba75002020-04-11 20:47:09 -040027#include <linux/fs.h>
Ethan Yonker71187742017-01-13 13:30:10 -060028#include <linux/xattr.h>
29
bigbiff bigbiff9c754052013-01-09 09:09:08 -050030#ifdef STDC_HEADERS
bigbiff7ba75002020-04-11 20:47:09 -040031#include <stdlib.h>
32#include <string.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050033#endif
34
35#ifdef HAVE_UNISTD_H
bigbiff7ba75002020-04-11 20:47:09 -040036#include <unistd.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050037#endif
38
Matt Mower87413642017-01-17 21:14:46 -060039#include <selinux/selinux.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050040
Ethan Yonker79f88bd2016-12-09 14:52:12 -060041#ifdef HAVE_EXT4_CRYPT
bigbiff7ba75002020-04-11 20:47:09 -040042#include "ext4crypt_tar.h"
Ethan Yonker79f88bd2016-12-09 14:52:12 -060043#endif
bigbiff7ba75002020-04-11 20:47:09 -040044
45#ifdef USE_FSCRYPT
46#include "fscrypt_policy.h"
47#endif
48
Ethan Yonker8d039f72017-02-03 14:26:15 -060049#include "android_utils.h"
Ethan Yonker79f88bd2016-12-09 14:52:12 -060050
bigbiff bigbiff9c754052013-01-09 09:09:08 -050051struct tar_dev
52{
53 dev_t td_dev;
54 libtar_hash_t *td_h;
55};
56typedef struct tar_dev tar_dev_t;
57
58struct tar_ino
59{
60 ino_t ti_ino;
61 char ti_name[MAXPATHLEN];
62};
63typedef struct tar_ino tar_ino_t;
64
65
66/* free memory associated with a tar_dev_t */
67void
68tar_dev_free(tar_dev_t *tdp)
69{
70 libtar_hash_free(tdp->td_h, free);
71 free(tdp);
72}
73
74
75/* appends a file to the tar archive */
76int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -050077tar_append_file(TAR *t, const char *realname, const char *savename)
bigbiff bigbiff9c754052013-01-09 09:09:08 -050078{
79 struct stat s;
80 int i;
81 libtar_hashptr_t hp;
82 tar_dev_t *td = NULL;
83 tar_ino_t *ti = NULL;
84 char path[MAXPATHLEN];
85
86#ifdef DEBUG
87 printf("==> tar_append_file(TAR=0x%lx (\"%s\"), realname=\"%s\", "
88 "savename=\"%s\")\n", t, t->pathname, realname,
89 (savename ? savename : "[NULL]"));
90#endif
91
92 if (lstat(realname, &s) != 0)
93 {
94#ifdef DEBUG
95 perror("lstat()");
96#endif
97 return -1;
98 }
99
100 /* set header block */
101#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500102 puts("tar_append_file(): setting header block...");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500103#endif
104 memset(&(t->th_buf), 0, sizeof(struct tar_header));
105 th_set_from_stat(t, &s);
106
107 /* set the header path */
108#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500109 puts("tar_append_file(): setting header path...");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500110#endif
111 th_set_path(t, (savename ? savename : realname));
112
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200113 /* get selinux context */
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500114 if (t->options & TAR_STORE_SELINUX)
115 {
116 if (t->th_buf.selinux_context != NULL)
117 {
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200118 free(t->th_buf.selinux_context);
119 t->th_buf.selinux_context = NULL;
120 }
121
122 security_context_t selinux_context = NULL;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500123 if (lgetfilecon(realname, &selinux_context) >= 0)
124 {
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200125 t->th_buf.selinux_context = strdup(selinux_context);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500126 printf(" ==> set selinux context: %s\n", selinux_context);
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200127 freecon(selinux_context);
128 }
129 else
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500130 {
131#ifdef DEBUG
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200132 perror("Failed to get selinux context");
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500133#endif
134 }
Vojtech Bocek25fd68d2013-08-27 03:10:10 +0200135 }
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500136
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600137#ifdef HAVE_EXT4_CRYPT
138 if (TH_ISDIR(t) && t->options & TAR_STORE_EXT4_POL)
139 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500140 if (t->th_buf.eep != NULL)
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600141 {
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500142 free(t->th_buf.eep);
143 t->th_buf.eep = NULL;
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600144 }
145
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500146 t->th_buf.eep = (struct ext4_encryption_policy*)malloc(sizeof(struct ext4_encryption_policy));
147 if (!t->th_buf.eep) {
148 printf("malloc ext4_encryption_policy\n");
149 return -1;
150 }
bigbiff7ba75002020-04-11 20:47:09 -0400151
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500152 if (e4crypt_policy_get_struct(realname, t->th_buf.eep))
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600153 {
154 char tar_policy[EXT4_KEY_DESCRIPTOR_SIZE];
155 memset(tar_policy, 0, sizeof(tar_policy));
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500156 char policy_hex[EXT4_KEY_DESCRIPTOR_SIZE_HEX];
157 policy_to_hex(t->th_buf.eep->master_key_descriptor, policy_hex);
158 if (lookup_ref_key(t->th_buf.eep->master_key_descriptor, &tar_policy[0])) {
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600159 printf("found policy '%s' - '%s' - '%s'\n", realname, tar_policy, policy_hex);
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500160 memcpy(t->th_buf.eep->master_key_descriptor, tar_policy, EXT4_KEY_DESCRIPTOR_SIZE);
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600161 } else {
162 printf("failed to lookup tar policy for '%s' - '%s'\n", realname, policy_hex);
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500163 free(t->th_buf.eep);
164 t->th_buf.eep = NULL;
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600165 return -1;
166 }
Ethan Yonkerfefe5912017-09-30 22:22:13 -0500167 }
168 else
169 {
170 // no policy found, but this is not an error as not all dirs will have a policy
171 free(t->th_buf.eep);
172 t->th_buf.eep = NULL;
173 }
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600174 }
175#endif
bigbiff7ba75002020-04-11 20:47:09 -0400176#ifdef USE_FSCRYPT
177 if (TH_ISDIR(t) && t->options & TAR_STORE_FSCRYPT_POL)
178 {
179 if (t->th_buf.fep != NULL)
180 {
181 free(t->th_buf.fep);
182 t->th_buf.fep = NULL;
183 }
184
185 t->th_buf.fep = (struct fscrypt_encryption_policy*)malloc(sizeof(struct fscrypt_encryption_policy));
186 if (!t->th_buf.fep) {
187 printf("malloc fs_encryption_policy\n");
188 return -1;
189 }
190
191 if (fscrypt_policy_get_struct(realname, t->th_buf.fep)) {
192 uint8_t tar_policy[FS_KEY_DESCRIPTOR_SIZE];
193 memset(tar_policy, 0, sizeof(tar_policy));
194 char policy_hex[FS_KEY_DESCRIPTOR_SIZE_HEX];
195 policy_to_hex(t->th_buf.fep->master_key_descriptor, policy_hex);
196 if (lookup_ref_key(t->th_buf.fep->master_key_descriptor, &tar_policy[0])) {
197 printf("found fscrypt policy '%s' - '%s' - '%s'\n", realname, tar_policy, policy_hex);
198 memcpy(t->th_buf.fep->master_key_descriptor, tar_policy, FS_KEY_DESCRIPTOR_SIZE);
199 } else {
200 printf("failed to lookup fscrypt tar policy for '%s' - '%s'\n", realname, policy_hex);
201 free(t->th_buf.fep);
202 t->th_buf.fep = NULL;
203 return -1;
204 }
205 }
206 else {
207 // no policy found, but this is not an error as not all dirs will have a policy
208 free(t->th_buf.fep);
209 t->th_buf.fep = NULL;
210 }
211 }
212#endif
Ethan Yonker79f88bd2016-12-09 14:52:12 -0600213
Ethan Yonker71187742017-01-13 13:30:10 -0600214 /* get posix file capabilities */
215 if (TH_ISREG(t) && t->options & TAR_STORE_POSIX_CAP)
216 {
217 if (t->th_buf.has_cap_data)
218 {
219 memset(&t->th_buf.cap_data, 0, sizeof(struct vfs_cap_data));
220 t->th_buf.has_cap_data = 0;
221 }
222
223 if (getxattr(realname, XATTR_NAME_CAPS, &t->th_buf.cap_data, sizeof(struct vfs_cap_data)) >= 0)
224 {
225 t->th_buf.has_cap_data = 1;
226#if 1 //def DEBUG
227 print_caps(&t->th_buf.cap_data);
228#endif
229 }
230 }
231
Ethan Yonker8d039f72017-02-03 14:26:15 -0600232 /* get android user.default xattr */
233 if (TH_ISDIR(t) && t->options & TAR_STORE_ANDROID_USER_XATTR)
234 {
235 if (getxattr(realname, "user.default", NULL, 0) >= 0)
236 {
237 t->th_buf.has_user_default = 1;
238#if 1 //def DEBUG
239 printf("storing xattr user.default\n");
240#endif
241 }
242 if (getxattr(realname, "user.inode_cache", NULL, 0) >= 0)
243 {
244 t->th_buf.has_user_cache = 1;
245#if 1 //def DEBUG
246 printf("storing xattr user.inode_cache\n");
247#endif
248 }
249 if (getxattr(realname, "user.inode_code_cache", NULL, 0) >= 0)
250 {
251 t->th_buf.has_user_code_cache = 1;
252#if 1 //def DEBUG
253 printf("storing xattr user.inode_code_cache\n");
254#endif
255 }
256 }
257
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500258 /* check if it's a hardlink */
259#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500260 puts("tar_append_file(): checking inode cache for hardlink...");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500261#endif
262 libtar_hashptr_reset(&hp);
263 if (libtar_hash_getkey(t->h, &hp, &(s.st_dev),
264 (libtar_matchfunc_t)dev_match) != 0)
265 td = (tar_dev_t *)libtar_hashptr_data(&hp);
266 else
267 {
268#ifdef DEBUG
269 printf("+++ adding hash for device (0x%lx, 0x%lx)...\n",
270 major(s.st_dev), minor(s.st_dev));
271#endif
272 td = (tar_dev_t *)calloc(1, sizeof(tar_dev_t));
273 td->td_dev = s.st_dev;
274 td->td_h = libtar_hash_new(256, (libtar_hashfunc_t)ino_hash);
275 if (td->td_h == NULL)
276 return -1;
277 if (libtar_hash_add(t->h, td) == -1)
278 return -1;
279 }
280 libtar_hashptr_reset(&hp);
281 if (libtar_hash_getkey(td->td_h, &hp, &(s.st_ino),
282 (libtar_matchfunc_t)ino_match) != 0)
283 {
284 ti = (tar_ino_t *)libtar_hashptr_data(&hp);
285#ifdef DEBUG
286 printf(" tar_append_file(): encoding hard link \"%s\" "
287 "to \"%s\"...\n", realname, ti->ti_name);
288#endif
289 t->th_buf.typeflag = LNKTYPE;
290 th_set_link(t, ti->ti_name);
291 }
292 else
293 {
294#ifdef DEBUG
295 printf("+++ adding entry: device (0x%lx,0x%lx), inode %ld "
296 "(\"%s\")...\n", major(s.st_dev), minor(s.st_dev),
297 s.st_ino, realname);
298#endif
299 ti = (tar_ino_t *)calloc(1, sizeof(tar_ino_t));
300 if (ti == NULL)
301 return -1;
302 ti->ti_ino = s.st_ino;
303 snprintf(ti->ti_name, sizeof(ti->ti_name), "%s",
304 savename ? savename : realname);
305 libtar_hash_add(td->td_h, ti);
306 }
307
308 /* check if it's a symlink */
309 if (TH_ISSYM(t))
310 {
311 i = readlink(realname, path, sizeof(path));
312 if (i == -1)
313 return -1;
314 if (i >= MAXPATHLEN)
315 i = MAXPATHLEN - 1;
316 path[i] = '\0';
317#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500318 printf("tar_append_file(): encoding symlink \"%s\" -> "
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500319 "\"%s\"...\n", realname, path);
320#endif
321 th_set_link(t, path);
322 }
323
324 /* print file info */
325 if (t->options & TAR_VERBOSE)
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500326 printf("%s\n", th_get_pathname(t));
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500327
328#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500329 puts("tar_append_file(): writing header");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500330#endif
331 /* write header */
332 if (th_write(t) != 0)
333 {
334#ifdef DEBUG
335 printf("t->fd = %d\n", t->fd);
336#endif
337 return -1;
338 }
339#ifdef DEBUG
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500340 puts("tar_append_file(): back from th_write()");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500341#endif
342
343 /* if it's a regular file, write the contents as well */
344 if (TH_ISREG(t) && tar_append_regfile(t, realname) != 0)
345 return -1;
346
347 return 0;
348}
349
350
351/* write EOF indicator */
352int
353tar_append_eof(TAR *t)
354{
355 int i, j;
356 char block[T_BLOCKSIZE];
357
358 memset(&block, 0, T_BLOCKSIZE);
359 for (j = 0; j < 2; j++)
360 {
361 i = tar_block_write(t, &block);
362 if (i != T_BLOCKSIZE)
363 {
364 if (i != -1)
365 errno = EINVAL;
366 return -1;
367 }
368 }
369
370 return 0;
371}
372
373
374/* add file contents to a tarchive */
375int
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500376tar_append_regfile(TAR *t, const char *realname)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500377{
378 char block[T_BLOCKSIZE];
379 int filefd;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500380 int64_t i, size;
381 ssize_t j;
382 int rv = -1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500383
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500384#if defined(O_BINARY)
385 filefd = open(realname, O_RDONLY|O_BINARY);
386#else
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500387 filefd = open(realname, O_RDONLY);
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500388#endif
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500389 if (filefd == -1)
390 {
391#ifdef DEBUG
392 perror("open()");
393#endif
394 return -1;
395 }
396
397 size = th_get_size(t);
398 for (i = size; i > T_BLOCKSIZE; i -= T_BLOCKSIZE)
399 {
400 j = read(filefd, &block, T_BLOCKSIZE);
401 if (j != T_BLOCKSIZE)
402 {
403 if (j != -1)
404 errno = EINVAL;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500405 goto fail;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500406 }
407 if (tar_block_write(t, &block) == -1)
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500408 goto fail;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500409 }
410
411 if (i > 0)
412 {
413 j = read(filefd, &block, i);
414 if (j == -1)
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500415 goto fail;
416 memset(&(block[i]), 0, T_BLOCKSIZE - i);
417 if (tar_block_write(t, &block) == -1)
418 goto fail;
419 }
420
421 /* success! */
422 rv = 0;
423fail:
424 close(filefd);
425
426 return rv;
427}
428
429
430/* add file contents to a tarchive */
431int
432tar_append_file_contents(TAR *t, const char *savename, mode_t mode,
433 uid_t uid, gid_t gid, void *buf, size_t len)
434{
435 struct stat st;
436
437 memset(&st, 0, sizeof(st));
438 st.st_mode = S_IFREG | mode;
439 st.st_uid = uid;
440 st.st_gid = gid;
441 st.st_mtime = time(NULL);
442 st.st_size = len;
443
444 th_set_from_stat(t, &st);
445 th_set_path(t, savename);
446
447 /* write header */
448 if (th_write(t) != 0)
449 {
450#ifdef DEBUG
451 fprintf(stderr, "tar_append_file_contents(): could not write header, t->fd = %d\n", t->fd);
452#endif
453 return -1;
454 }
455
456 return tar_append_buffer(t, buf, len);
457}
458
459int
460tar_append_buffer(TAR *t, void *buf, size_t len)
461{
462 char block[T_BLOCKSIZE];
Ethan Yonker58f21322018-08-24 11:17:36 -0500463 int i;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500464 size_t size = len;
465
466 for (i = size; i > T_BLOCKSIZE; i -= T_BLOCKSIZE)
467 {
468 if (tar_block_write(t, buf) == -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500469 return -1;
James Christopher Adduono6f57f7c2016-03-01 16:01:53 -0500470 buf = (char *)buf + T_BLOCKSIZE;
471 }
472
473 if (i > 0)
474 {
475 memcpy(block, buf, i);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500476 memset(&(block[i]), 0, T_BLOCKSIZE - i);
477 if (tar_block_write(t, &block) == -1)
478 return -1;
479 }
480
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500481 return 0;
482}
483