static int32_t e2prop_get(xar_file_t f, const char *name, char **value) { char v[1024]; memset(v, 0, sizeof(v)); snprintf(v, sizeof(v)-1, "%s/%s", XAR_ATTR_FORK, name); return xar_prop_get(f, v, (const char**)value); }
int32_t xar_data_extract(xar_t x, xar_file_t f, const char *file, char *buffer, size_t len) { const char *opt; int32_t retval = 0; struct _data_context context; xar_prop_t tmpp; memset(&context,0,sizeof(struct _data_context)); /* Only regular files are copied in and out of the heap here */ xar_prop_get(f, "type", &opt); if( !opt ) return 0; if( strcmp(opt, "file") != 0 ) { if( strcmp(opt, "hardlink") == 0 ) { opt = xar_attr_get(f, "type", "link"); if( !opt ) return 0; if( strcmp(opt, "original") != 0 ) return 0; /* else, we're an original hardlink, so keep going */ } else return 0; } if ( len ){ context.length = len; context.buffer = buffer; context.offset = 0; }else{ /* mode 600 since other modules may need to operate on the file * prior to the real permissions being set. */ context.fd = open(file, O_RDWR|O_TRUNC|O_EXLOCK, 0600); if( context.fd < 0 ) { xar_err_new(x); xar_err_set_file(x, f); xar_err_set_string(x, "io: Could not create file"); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); return -1; } } tmpp = xar_prop_pfirst(f); if( tmpp ) tmpp = xar_prop_find(tmpp, "data"); if( !tmpp ) { close(context.fd); return 0; } retval = xar_attrcopy_from_heap(x, f, tmpp, xar_data_write, (void *)(&context)); if( context.fd > 0 ){ close(context.fd); context.fd = -1; } return retval; }
/* xar_data_archive * This is the arcmod archival entry point for archiving the file's * data into the heap file. */ int32_t xar_data_archive(xar_t x, xar_file_t f, const char *file, const char *buffer, size_t len) { const char *opt; int32_t retval = 0; struct _data_context context; xar_prop_t tmpp; memset(&context,0,sizeof(struct _data_context)); if( !xar_check_prop(x, "data") ) return 0; xar_prop_get(f, "type", &opt); if(!opt) return 0; if( strcmp(opt, "file") != 0 ) { if( strcmp(opt, "hardlink") == 0 ) { opt = xar_attr_get(f, "type", "link"); if( !opt ) return 0; if( strcmp(opt, "original") != 0 ) return 0; /* else, we're an original hardlink, so keep going */ } else return 0; } if( 0 == len ){ context.fd = open(file, O_RDONLY); if( context.fd < 0 ) { xar_err_new(x); xar_err_set_file(x, f); xar_err_set_string(x, "io: Could not open file"); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_CREATION); return -1; } }else{ context.buffer = (void *)buffer; context.length = len; context.offset = 0; } #ifdef F_NOCACHE fcntl(context.fd, F_NOCACHE, 1); #endif tmpp = xar_prop_pset(f, NULL, "data", NULL); retval = xar_attrcopy_to_heap(x, f, tmpp, xar_data_read,(void *)(&context)); if( context.total == 0 ) xar_prop_unset(f, "data"); if(context.fd > 0){ close(context.fd); context.fd = -1; } return retval; }
void prop_check(int fd, xar_t x, xar_file_t f) { xar_iter_t i; const char *key, *value; const char *name = NULL; char *tmp; off_t offset = 0, length = 0; const char *origcsum = NULL; i = xar_iter_new(); if( !i ) { fprintf(stderr, "Error creating new prop iter\n"); exit(1); } xar_prop_get(f, "name", &name); for( key = xar_prop_first(f, i); key; key = xar_prop_next(i) ) { asprintf(&tmp, "%s/offset", key); if( xar_prop_get(f, tmp, &value) == 0 ) { offset = strtoll(value, NULL, 10); } free(tmp); asprintf(&tmp, "%s/length", key); if( xar_prop_get(f, tmp, &value) == 0 ) { length = strtoll(value, NULL, 10); } free(tmp); asprintf(&tmp, "%s/archived-checksum", key); if( xar_prop_get(f, tmp, &value) == 0 ) { origcsum = value; } free(tmp); if( offset && length && origcsum ) { heap_check(fd, name, key, offset, length, origcsum); offset = 0; length = 0; origcsum = NULL; } } }
int32_t xar_flags_extract(xar_t x, xar_file_t f, const char *file, char *buffer, size_t len) { #ifdef HAVE_CHFLAGS char *tmp; u_int flags = 0; if( xar_prop_get(f, XAR_FLAG_FORK, NULL) ) return 0; #ifdef UF_NODUMP if( x_getprop(f, "UserNoDump", (char **)&tmp) == 0 ) flags |= UF_NODUMP; #endif #ifdef UF_IMMUTABLE if( x_getprop(f, "UserImmutable", (char **)&tmp) == 0 ) flags |= UF_IMMUTABLE; #endif #ifdef UF_APPEND if( x_getprop(f, "UserAppend", (char **)&tmp) == 0 ) flags |= UF_APPEND; #endif #ifdef UF_OPAQUE if( x_getprop(f, "UserOpaque", (char **)&tmp) == 0 ) flags |= UF_OPAQUE; #endif #ifdef SF_ARCHIVED if( x_getprop(f, "SystemArchived", (char **)&tmp) == 0 ) flags |= SF_ARCHIVED; #endif #ifdef SF_IMMUTABLE if( x_getprop(f, "SystemImmutable", (char **)&tmp) == 0 ) flags |= SF_IMMUTABLE; #endif #ifdef SF_APPEND if( x_getprop(f, "SystemAppend", (char **)&tmp) == 0 ) flags |= SF_APPEND; #endif if( !flags ) return 0; if( chflags(file, flags) != 0 ) { char e[1024]; memset(e, 0, sizeof(e)); snprintf(e, sizeof(e)-1, "chflags: %s", strerror(errno)); xar_err_new(x); xar_err_set_file(x, f); xar_err_set_string(x, e); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); return -1; } #endif return 0; }
int32_t xar_data_verify(xar_t x, xar_file_t f) { const char *opt; struct _data_context context; xar_prop_t tmpp; memset(&context,0,sizeof(struct _data_context)); /* Only regular files are copied in and out of the heap here */ xar_prop_get(f, "type", &opt); if( !opt ) return 0; if( strcmp(opt, "directory") == 0 ) { return 0; } tmpp = xar_prop_pfirst(f); if( tmpp ) tmpp = xar_prop_find(tmpp, "data"); if (!tmpp) // It appears that xar can have truely empty files, aka, no data. We should just fail to verify these files. return 0; // After all, the checksum of blank is meaningless. So, failing to do so will cause a crash. return xar_attrcopy_from_heap(x, f, tmpp, NULL , (void *)(&context)); }
int xar_ext2attr_archive(xar_t x, xar_file_t f, const char* file, const char *buffer, size_t len) { int ret = 0; /* if archiving from a buffer, then there is no place to get extattr */ if ( len ) return 0; #if defined(HAVE_EXT2FS_EXT2_FS_H) || defined(HAVE_LINUX_EXT2_FS_H) int fd, flags=0, version; char *vstr; const char *opt; xar_prop_get(f, "type", &opt); if(!opt) return 0; if( strcmp(opt, "file") != 0 ) { if( strcmp(opt, "hardlink") != 0 ) if( strcmp(opt, "directory") != 0 ) return 0; } fd = open(file, O_RDONLY); if( fd < 0 ) { return 0; } if( ioctl(fd, EXT2_IOC_GETVERSION, &version) < 0 ) { ret = 0; goto BAIL; } if( ioctl(fd, EXT2_IOC_GETFLAGS, &flags) < 0 ) { ret = 0; goto BAIL; } if( flags == 0 ) goto BAIL; xar_prop_set(f, XAR_EXT2_FORK, NULL); asprintf(&vstr, "%d", version); xar_attr_set(f, XAR_EXT2_FORK, "version", vstr); free(vstr); if(! (flags & ~EXT2_SECRM_FL) ) x_addprop(f, "SecureDeletion"); if(! (flags & ~EXT2_UNRM_FL) ) x_addprop(f, "Undelete"); if(! (flags & ~EXT2_COMPR_FL) ) x_addprop(f, "Compress"); if(! (flags & ~EXT2_SYNC_FL) ) x_addprop(f, "Synchronous"); if(! (flags & ~EXT2_IMMUTABLE_FL) ) x_addprop(f, "Immutable"); if(! (flags & ~EXT2_APPEND_FL) ) x_addprop(f, "AppendOnly"); if(! (flags & ~EXT2_NODUMP_FL) ) x_addprop(f, "NoDump"); if(! (flags & ~EXT2_NOATIME_FL) ) x_addprop(f, "NoAtime"); if(! (flags & ~EXT2_DIRTY_FL) ) x_addprop(f, "CompDirty"); if(! (flags & ~EXT2_COMPRBLK_FL) ) x_addprop(f, "CompBlock"); #ifdef EXT2_NOCOMPR_FL if(! (flags & ~EXT2_NOCOMPR_FL) ) x_addprop(f, "NoCompBlock"); #endif if(! (flags & ~EXT2_ECOMPR_FL) ) x_addprop(f, "CompError"); if(! (flags & ~EXT2_BTREE_FL) ) x_addprop(f, "BTree"); if(! (flags & ~EXT2_INDEX_FL) ) x_addprop(f, "HashIndexed"); if(! (flags & ~EXT2_IMAGIC_FL) ) x_addprop(f, "iMagic"); #ifdef EXT3_JOURNAL_DATA_FL if(! (flags & ~EXT3_JOURNAL_DATA_FL) ) x_addprop(f, "Journaled"); #endif if(! (flags & ~EXT2_NOTAIL_FL) ) x_addprop(f, "NoTail"); if(! (flags & ~EXT2_DIRSYNC_FL) ) x_addprop(f, "DirSync"); if(! (flags & ~EXT2_TOPDIR_FL) ) x_addprop(f, "TopDir"); if(! (flags & ~EXT2_RESERVED_FL) ) x_addprop(f, "Reserved"); BAIL: close(fd); #endif return ret; }
int xar_ext2attr_extract(xar_t x, xar_file_t f, const char* file, char *buffer, size_t len) { /* if extracting to a buffer, then there is no place to write extattr */ if ( len ) return 0; #if defined(HAVE_EXT2FS_EXT2_FS_H) || defined(HAVE_LINUX_EXT2_FS_H) int fd = -1, version, flags = 0; char *tmp; if( xar_prop_get(f, XAR_EXT2_FORK, NULL) == 0 ) { const char *temp; temp = xar_attr_get(f, XAR_EXT2_FORK, "version"); version = strtol(temp, NULL, 10); fd = open(file, O_RDONLY); if( fd < 0 ) return 0; ioctl(fd, EXT2_IOC_SETVERSION, &version); } if( xar_prop_get(f, XAR_ATTR_FORK, NULL) ) { if( fd >= 0 ) close(fd); return 0; } if( e2prop_get(f, "SecureDeletion", (char **)&tmp) == 0 ) flags |= EXT2_SECRM_FL; if( e2prop_get(f, "Undelete", (char **)&tmp) == 0 ) flags |= EXT2_UNRM_FL ; if( e2prop_get(f, "Compress", (char **)&tmp) == 0 ) flags |= EXT2_COMPR_FL ; if( e2prop_get(f, "Synchronous", (char **)&tmp) == 0 ) flags |= EXT2_SYNC_FL ; if( e2prop_get(f, "SystemImmutable", (char **)&tmp) == 0 ) flags |= EXT2_IMMUTABLE_FL ; if( e2prop_get(f, "AppendOnly", (char **)&tmp) == 0 ) flags |= EXT2_APPEND_FL ; if( e2prop_get(f, "NoDump", (char **)&tmp) == 0 ) flags |= EXT2_NODUMP_FL ; if( e2prop_get(f, "NoAtime", (char **)&tmp) == 0 ) flags |= EXT2_NOATIME_FL ; if( e2prop_get(f, "CompDirty", (char **)&tmp) == 0 ) flags |= EXT2_DIRTY_FL ; if( e2prop_get(f, "CompBlock", (char **)&tmp) == 0 ) flags |= EXT2_COMPRBLK_FL ; #ifdef EXT2_NOCOMPR_FL if( e2prop_get(f, "NoCompBlock", (char **)&tmp) == 0 ) flags |= EXT2_NOCOMPR_FL ; #endif if( e2prop_get(f, "CompError", (char **)&tmp) == 0 ) flags |= EXT2_ECOMPR_FL ; if( e2prop_get(f, "BTree", (char **)&tmp) == 0 ) flags |= EXT2_BTREE_FL ; if( e2prop_get(f, "HashIndexed", (char **)&tmp) == 0 ) flags |= EXT2_INDEX_FL ; if( e2prop_get(f, "iMagic", (char **)&tmp) == 0 ) flags |= EXT2_IMAGIC_FL ; #ifdef EXT3_JOURNAL_DATA_FL if( e2prop_get(f, "Journaled", (char **)&tmp) == 0 ) flags |= EXT3_JOURNAL_DATA_FL ; #endif if( e2prop_get(f, "NoTail", (char **)&tmp) == 0 ) flags |= EXT2_NOTAIL_FL ; if( e2prop_get(f, "DirSync", (char **)&tmp) == 0 ) flags |= EXT2_DIRSYNC_FL ; if( e2prop_get(f, "TopDir", (char **)&tmp) == 0 ) flags |= EXT2_TOPDIR_FL ; if( fd < 0 ) { fd = open(file, O_RDONLY); if( fd < 0 ) return 0; } ioctl(fd, EXT2_IOC_SETFLAGS, &flags); close(fd); #endif return 0; }
std::map<std::string, std::string> Extract(std::string file, std::string prefix) { std::map<std::string, std::string> files; #ifdef HAVE_LIBXAR xar_t x; xar_iter_t xi; xar_file_t xf; xar_stream xs; char buffer[8192]; x = xar_open(file.c_str(), READ); if (x == nullptr) { std::cerr << "Could not open xar archive" << std::endl; } xi = xar_iter_new(); if (xi == nullptr) { xar_close(x); std::cerr << "Could not read xar archive" << std::endl; } for (xf = xar_file_first(x, xi); xf != nullptr; xf = xar_file_next(xi)) { char *path = xar_get_path(xf); const char *type; xar_prop_get(xf, "type", &type); if (type == nullptr) { std::cerr << "File has no type" << std::endl; free(path); continue; } if (std::strcmp(type, "file") != 0) { free(path); continue; } if (xar_extract_tostream_init(x, xf, &xs) != XAR_STREAM_OK) { std::cerr << "Error initializing stream" << std::endl; free(path); continue; } const std::string fileName = prefix + util::uuid::UuidToString(util::uuid::GenerateUUID()); // Write bitcode to file std::FILE *output = std::fopen(fileName.c_str(), "wb"); if (output == nullptr) { std::cerr << "Error opening output file" << std::endl; continue; } xs.avail_out = sizeof(buffer); xs.next_out = buffer; int32_t ret; while ((ret = xar_extract_tostream(&xs)) != XAR_STREAM_END) { if (ret == XAR_STREAM_ERR) { std::cerr << "Error extracting stream" << std::endl; break; } std::fwrite(buffer, sizeof(char), sizeof(buffer) - xs.avail_out, output); xs.avail_out = sizeof(buffer); xs.next_out = buffer; } if (xar_extract_tostream_end(&xs) != XAR_STREAM_OK) { std::cerr << "Error ending stream" << std::endl; } std::fclose(output); // Add to list of extracted files files[std::string(path)] = fileName; free(path); } xar_iter_free(xi); xar_close(x); #endif return files; }
static int32_t eacls(xar_t x, xar_file_t f, const char *file) { #ifdef HAVE_SYS_ACL_H #if !defined(__APPLE__) const char *t; acl_t a; const char *type; xar_prop_get(f, "type", &type); if( !type || (strcmp(type, "symlink") == 0) ) return 0; xar_prop_get(f, "acl/default", &t); if( t ) { a = acl_from_text(t); if( !a ) { xar_err_new(x); xar_err_set_errno(x, errno); xar_err_set_string(x, "Error extracting default acl from toc"); xar_err_set_file(x, f); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); } else { if( acl_set_file(file, ACL_TYPE_DEFAULT, a) != 0 ) { xar_err_new(x); xar_err_set_errno(x, errno); xar_err_set_string(x, "Error setting default acl"); xar_err_set_file(x, f); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); } } } xar_prop_get(f, "acl/access", &t); if( t ) { a = acl_from_text(t); if( !a ) { xar_err_new(x); xar_err_set_errno(x, errno); xar_err_set_string(x, "Error extracting access acl from toc"); xar_err_set_file(x, f); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); } else { if( acl_set_file(file, ACL_TYPE_ACCESS, a) != 0 ) { xar_err_new(x); xar_err_set_errno(x, errno); xar_err_set_string(x, "Error setting access acl"); xar_err_set_file(x, f); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); } acl_free(a); } } #else /* !__APPLE__ */ const char *t; acl_t a; xar_prop_get(f, "acl/appleextended", &t); if( t ) { a = acl_from_text(t); if( !a ) { xar_err_new(x); xar_err_set_errno(x, errno); xar_err_set_string(x, "Error extracting access acl from toc"); xar_err_set_file(x, f); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); } else { if( acl_set_file(file, ACL_TYPE_ACCESS, a) != 0 ) { xar_err_new(x); xar_err_set_errno(x, errno); xar_err_set_string(x, "Error setting access acl"); xar_err_set_file(x, f); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); } acl_free(a); } } #endif /* !__APPLE__ */ #endif return 0; }
int main(int argc, char *argv[]) { xar_t x; xar_iter_t i; xar_file_t f; xar_stream s; char buffer[8192]; x = xar_open(argv[1], READ); if( !x ) { fprintf(stderr, "Error opening archive\n"); exit(1); } xar_register_errhandler(x, err_callback, NULL); i = xar_iter_new(); if( !i ) { fprintf(stderr, "Error creating xar iterator\n"); exit(1); } for(f = xar_file_first(x, i); f; f = xar_file_next(i)) { char *path; const char *type; int32_t ret; int fd; path = xar_get_path(f); xar_prop_get(f, "type", &type); if( !type ) { fprintf(stderr, "File has no type %s\n", path); free(path); continue; } if( strcmp(type, "file") != 0 ) { fprintf(stderr, "Skipping %s\n", path); free(path); continue; } fprintf(stderr, "Extracting %s\n", path); if( xar_extract_tostream_init(x, f, &s) != XAR_STREAM_OK ) { fprintf(stderr, "Error initializing stream %s\n", path); free(path); continue; } fd = open(path, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR); if( !fd ) { fprintf(stderr, "Error opening output file %s\n", path); free(path); continue; } s.avail_out = sizeof(buffer); s.next_out = buffer; while( (ret = xar_extract_tostream(&s)) != XAR_STREAM_END ) { if( ret == XAR_STREAM_ERR ) { fprintf(stderr, "Error extracting stream %s\n", path); exit(2); } write(fd, buffer, sizeof(buffer)-s.avail_out); s.avail_out = sizeof(buffer); s.next_out = buffer; } if( xar_extract_tostream_end(&s) != XAR_STREAM_OK ) { fprintf(stderr, "Error ending stream %s\n", path); } close(fd); free(path); } }
/* replace_sign: rip out all current signatures and certs and insert a new pair Since libxar is currently not capable of doing this directly, we have to create a new xar archive, copy all the files and options from the current archive, and sign the new archive */ static void replace_sign(const char *filename) { xar_t old_xar, new_xar; xar_signature_t sig; char *new_xar_path = (char *)malloc(15); strncpy(new_xar_path, "/tmp/xar.XXXXX", 15); new_xar_path = mktemp(new_xar_path); char *systemcall; int err; // open both archives old_xar = xar_open(filename, READ); if ( old_xar == NULL ) { fprintf(stderr, "Could not open archive %s!\n", filename); exit(1); } new_xar = xar_open(new_xar_path, WRITE); if( !new_xar ) { fprintf(stderr, "Error creating new archive %s\n", new_xar_path); exit(1); } // install new signature and new certs in new_xar sig = xar_signature_new(new_xar, "RSA", SigSize, &signingCallback, NULL); if ( LeafCertPath ) insert_cert(sig, LeafCertPath); if ( IntermediateCertPath ) insert_cert(sig, IntermediateCertPath); // copy options char *opts[6] = {XAR_OPT_TOCCKSUM, XAR_OPT_COMPRESSION, XAR_OPT_COALESCE, XAR_OPT_LINKSAME, XAR_OPT_RSIZE, XAR_OPT_OWNERSHIP}; int i; const char *opt; for (i=0; i<6; i++) { opt = xar_opt_get(old_xar, opts[i]); if (opt) xar_opt_set(new_xar, opts[i], opt); } // skip copy subdocs for now since we don't use them yet // copy files xar_iter_t iter = xar_iter_new(); xar_file_t f = xar_file_first(old_xar, iter); // xar_file_next iterates the archive depth-first, i.e. all children are enumerated before the siblings. const char *name; char *f_dirname, *stack_top_dirname; stack s_new = stack_new(); stack s_old = stack_new(); xar_file_t last_copied = NULL, last_added; xar_iter_t loopIter = xar_iter_new(); xar_file_t current_xar_file; for (current_xar_file = xar_file_first(old_xar, loopIter); current_xar_file; current_xar_file = xar_file_next(loopIter)) { printf("old_xar -> %s (parent: %s)\n",xar_get_path(current_xar_file),XAR_FILE(current_xar_file)->parent?xar_get_path(XAR_FILE(current_xar_file)->parent):"(nil)"); } do { // parent is the parent in the new archive! // 3 cases: // 1. the file has no parent. Happens for every file at the top level of the archive. // 2. the file's parent is the last file we added. Happens while descending down a path // 3. the file's parent is one of the ancestors of the last file (and not NULL, that would be case 1) // that means we either go back up the tree and add a sibling of one of the ancestors, or we add a // sibling on the same level xar_prop_get(f, "name", &name); // filename, without any path info if (!XAR_FILE(f)->parent) { // case 1 printf("root: %s\n",xar_get_path(f)); last_added = xar_add_from_archive(new_xar, NULL, name, old_xar, f); last_copied = f; stack_push(s_new, (void *)last_added); stack_push(s_old, (void *)last_copied); } else if (f->parent == last_copied) { // case 2 printf("child: %s -> %s\n",xar_get_path(f->parent),xar_get_path(f)); last_added = xar_add_from_archive(new_xar, last_added, name, old_xar, f); last_copied = f; stack_push(s_new, (void *)last_added); stack_push(s_old, (void *)last_copied); } else { // case 3 printf("searching for parent: %s ?\n",xar_get_path(f)); while (XAR_FILE(f)->parent != XAR_FILE(s_old->top->data)->parent) { printf("popping: %s\n",xar_get_path(XAR_FILE(s_old->top->data))); stack_pop(s_new); stack_pop(s_old); } printf("found: %s -> %s\n",xar_get_path(XAR_FILE(s_new->top->data)),xar_get_path(f)); stack_pop(s_new); stack_pop(s_old); last_added = xar_add_from_archive(new_xar, (xar_file_t)(s_new->top->data), name, old_xar, f); last_copied = f; stack_push(s_new, (void *)last_added); stack_push(s_old, (void *)last_copied); } } while (f = xar_file_next(iter)); loopIter = xar_iter_new(); for (current_xar_file = xar_file_first(new_xar, loopIter); current_xar_file; current_xar_file = xar_file_next(loopIter)) { char * current_path = xar_get_path(current_xar_file); printf("new_xar -> %s\n",current_path); } xar_iter_free(iter); stack_free(s_new); stack_free(s_old); if( xar_close(new_xar) != 0 ) { fprintf(stderr, "Error creating the archive\n"); if( !Err ) Err = 42; } xar_close(old_xar); // write signature offset to file (have to re-open so xar_close can figure out the correct offset) new_xar = xar_open(new_xar_path, READ); if( !new_xar ) { fprintf(stderr, "Error re-opening new archive %s\n", new_xar_path); unlink(new_xar_path); exit(1); } if (extract_sig_offset(new_xar, SigOffsetDumpPath)) { xar_close(new_xar); unlink(new_xar_path); exit(1); } xar_close(new_xar); // delete old archive, move new in its place unlink(filename); asprintf(&systemcall, "cp \"%s\" \"%s\"", new_xar_path, filename); err = system(systemcall); if (err) { fprintf(stderr, "Could not copy new archive to final location (system() returned %i)\n", err); unlink(new_xar_path); exit(1); } // Delete the tmp archive unlink(new_xar_path); free(systemcall); }
static void extract_data_to_sign(const char *filename) { xar_signature_t sig; off_t signatureOffset; FILE *file; xar_t x; int i; uint32_t dataToSignOffset = 0; uint32_t dataToSignSize = 0; char *buffer = NULL; const char *value; // find signature stub x = xar_open(filename, READ); if ( x == NULL ) { fprintf(stderr, "Could not open %s to extract data to sign!\n", filename); exit(1); } sig = xar_signature_first(x); if ( !sig ) { fprintf(stderr, "No signatures found to extract data from.\n"); exit(E_NOSIG); } // locate data to sign if( 0 != xar_prop_get((xar_file_t)x, "checksum/offset" ,&value) ){ fprintf(stderr, "Could not locate checksum/offset in archive.\n"); exit(1); } dataToSignOffset = xar_get_heap_offset(x); dataToSignOffset += strtoull(value, (char **)NULL, 10); if( 0 != xar_prop_get((xar_file_t)x, "checksum/size" ,&value) ){ fprintf(stderr, "Could not locate checksum/size in archive.\n"); exit(1); } dataToSignSize = strtoull(value, (char **)NULL, 10); // get signature offset (inject signature here) xar_signature_copy_signed_data(sig, NULL, NULL, NULL, NULL, &signatureOffset); signatureOffset += xar_get_heap_offset(x); xar_close(x); // now get data to be signed, using offset and size file = fopen(filename, "r"); if (!file) { fprintf(stderr, "Could not open %s for reading data to sign!\n", filename); exit(1); } fseek(file, dataToSignOffset, SEEK_SET); buffer = malloc(dataToSignSize); i = fread(buffer, dataToSignSize, 1, file); if (i != 1) { fprintf(stderr, "Failed to read data to sign from %s!\n", filename); exit(1); } fclose(file); // save data to sign file = fopen(DataToSignDumpPath, "w"); if (!file) { fprintf(stderr, "Could not open %s for saving data to sign!\n", DataToSignDumpPath); exit(1); } i = fwrite(buffer, dataToSignSize, 1, file); if (i != 1) { fprintf(stderr, "Failed to write data to sign to %s (fwrite() returned %i)!\n", DataToSignDumpPath, i); exit(1); } fclose(file); // save signature offset file = fopen(SigOffsetDumpPath, "w"); if (!file) { fprintf(stderr, "Could not open %s for saving signature offset!\n", SigOffsetDumpPath); exit(1); } i = fprintf(file, "%lli\n", signatureOffset); if (i < 0) { fprintf(stderr, "Failed to write signature offset to %s (fprintf() returned %i)!\n", SigOffsetDumpPath, i); exit(1); } fclose(file); free(buffer); }
static int extract(const char *filename, int arglen, char *args[]) { xar_t x; xar_iter_t i; xar_file_t f; int files_extracted = 0; int argi; struct lnode *extract_files = NULL; struct lnode *extract_tail = NULL; struct lnode *lnodei = NULL; struct lnode *dirs = NULL; for(argi = 0; args[argi]; argi++) { struct lnode *tmp; int err; tmp = malloc(sizeof(struct lnode)); tmp->str = strdup(args[argi]); tmp->next = NULL; err = regcomp(&tmp->reg, tmp->str, REG_NOSUB); if( err ) { char errstr[1024]; regerror(err, &tmp->reg, errstr, sizeof(errstr)); printf("Error with regular expression %s: %s\n", tmp->str, errstr); exit(1); } if( extract_files == NULL ) { extract_files = tmp; extract_tail = tmp; } else { extract_tail->next = tmp; extract_tail = tmp; } /* Add a clause for recursive extraction */ tmp = malloc(sizeof(struct lnode)); asprintf(&tmp->str, "%s/.*", args[argi]); tmp->next = NULL; err = regcomp(&tmp->reg, tmp->str, REG_NOSUB); if( err ) { char errstr[1024]; regerror(err, &tmp->reg, errstr, sizeof(errstr)); printf("Error with regular expression %s: %s\n", tmp->str, errstr); exit(1); } if( extract_files == NULL ) { extract_files = tmp; extract_tail = tmp; } else { extract_tail->next = tmp; extract_tail = tmp; } } x = xar_open(filename, READ); if( !x ) { fprintf(stderr, "Error opening xar archive: %s\n", filename); exit(1); } if(Chdir) { if( chdir(Chdir) != 0 ) { fprintf(stderr, "Unable to chdir to %s\n", Chdir); exit(1); } } xar_register_errhandler(x, err_callback, NULL); if( Perms == SYMBOLIC ) { xar_opt_set(x, XAR_OPT_OWNERSHIP, XAR_OPT_VAL_SYMBOLIC); } if( Perms == NUMERIC ) { xar_opt_set(x, XAR_OPT_OWNERSHIP, XAR_OPT_VAL_NUMERIC); } if ( Rsize != NULL ) { xar_opt_set(x, XAR_OPT_RSIZE, Rsize); } if( SaveSuid ) { xar_opt_set(x, XAR_OPT_SAVESUID, XAR_OPT_VAL_TRUE); } i = xar_iter_new(); if( !i ) { fprintf(stderr, "Error creating xar iterator\n"); exit(1); } for(f = xar_file_first(x, i); f; f = xar_file_next(i)) { int matched = 0; int exclude_match = 1; struct lnode *i; char *path = xar_get_path(f); if( args[0] ) { for(i = extract_files; i != NULL; i = i->next) { int extract_match = 1; extract_match = regexec(&i->reg, path, 0, NULL, 0); if( !extract_match ) { matched = 1; break; } } } else { matched = 1; } for( i = Exclude; i; i=i->next ) { exclude_match = regexec(&i->reg, path, 0, NULL, 0); if( !exclude_match ) break; } if( !exclude_match ) { if( Verbose ) printf("Excluding %s\n", path); free(path); continue; } if (!xar_path_issane(path)) { if (Verbose) printf("Warning, not extracting file \"%s\" because it's path is invalid.\n", path); free(path); continue; } if( matched ) { struct stat sb; if( NoOverwrite && (lstat(path, &sb) == 0) ) { printf("%s already exists, not overwriting\n", path); } else { const char *prop = NULL; int deferred = 0; if( xar_prop_get(f, "type", &prop) == 0 ) { if( strcmp(prop, "directory") == 0 ) { struct lnode *tmpl = calloc(sizeof(struct lnode),1); tmpl->str = (char *)f; tmpl->next = dirs; dirs = tmpl; deferred = 1; } } if( ! deferred ) { files_extracted++; print_file(x, f); xar_extract(x, f); } } } free(path); } for(lnodei = dirs; lnodei; lnodei = lnodei->next) { files_extracted++; print_file(x,(xar_file_t)lnodei->str); xar_extract(x, (xar_file_t)lnodei->str); } if( args[0] && (files_extracted == 0) ) { fprintf(stderr, "No files matched extraction criteria.\n"); Err = 3; } if( Subdoc ) extract_subdoc(x, NULL); xar_iter_free(i); if( xar_close(x) != 0 ) { fprintf(stderr, "Error extracting the archive\n"); if( !Err ) Err = 42; } for(lnodei = extract_files; lnodei != NULL; ) { struct lnode *tmp; free(lnodei->str); regfree(&lnodei->reg); tmp = lnodei; lnodei = lnodei->next; free(tmp); } return Err; }
int32_t xar_stat_extract(xar_t x, xar_file_t f, const char *file, char *buffer, size_t len) { const char *opt; int ret, fd; mode_t modet = 0; xar_prop_get(f, "type", &opt); if(opt && (strcmp(opt, "character special") == 0)) modet = S_IFCHR; if(opt && (strcmp(opt, "block special") == 0)) modet = S_IFBLK; if( modet ) { uint32_t major, minor; long long tmpll; dev_t devt; xar_prop_get(f, "device/major", &opt); tmpll = strtoll(opt, NULL, 10); if( ( (tmpll == LLONG_MIN) || (tmpll == LLONG_MAX) ) && (errno == ERANGE) ) return -1; if( (tmpll < 0) || (tmpll > 255) ) return -1; major = tmpll; xar_prop_get(f, "device/minor", &opt); tmpll = strtoll(opt, NULL, 10); if( ( (tmpll == LLONG_MIN) || (tmpll == LLONG_MAX) ) && (errno == ERANGE) ) return -1; if( (tmpll < 0) || (tmpll > 255) ) return -1; minor = tmpll; devt = xar_makedev(major, minor); unlink(file); if( mknod(file, modet, devt) ) { xar_err_new(x); xar_err_set_file(x, f); xar_err_set_string(x, "mknod: Could not create character device"); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); return -1; } return 0; } if(opt && (strcmp(opt, "directory") == 0)) { ret = mkdir(file, 0700); if( (ret != 0) && (errno != EEXIST) ) { xar_err_new(x); xar_err_set_file(x, f); xar_err_set_string(x, "stat: Could not create directory"); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); return ret; } return 0; } if(opt && (strcmp(opt, "symlink") == 0)) { xar_prop_get(f, "link", &opt); if( opt ) { unlink(file); ret = symlink(opt, file); if( ret != 0 ) { xar_err_new(x); xar_err_set_file(x, f); xar_err_set_string(x, "stat: Could not create symlink"); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); } return ret; } } if(opt && (strcmp(opt, "hardlink") == 0)) { xar_file_t tmpf; opt = xar_attr_get(f, "type", "link"); if( !opt ) return 0; if( strcmp(opt, "original") == 0 ) goto CREATEFILE; tmpf = xmlHashLookup(XAR(x)->link_hash, BAD_CAST(opt)); if( !tmpf ) { xar_err_new(x); xar_err_set_file(x, f); xar_err_set_string(x, "stat: Encountered hardlink with no original"); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); return -1; } unlink(file); if( link(XAR_FILE(tmpf)->fspath, file) != 0 ) { if( errno == ENOENT ) { xar_iter_t i; const char *ptr; i = xar_iter_new(x); for(ptr = xar_prop_first(tmpf, i); ptr; ptr = xar_prop_next(i)) { xar_iter_t a; const char *val = NULL; const char *akey, *aval; if( strncmp("data", ptr, 4) != 0 ) continue; if( xar_prop_get(tmpf, ptr, &val) ) continue; xar_prop_set(f, ptr, val); a = xar_iter_new(x); for(akey = xar_attr_first(tmpf, ptr, a); akey; akey = xar_attr_next(a)) { aval = xar_attr_get(tmpf, ptr, akey); xar_attr_set(f, ptr, akey, aval); } xar_iter_free(a); } xar_iter_free(i); xar_attr_set(f, "type", "link", "original"); return 0; } else { xar_err_new(x); xar_err_set_file(x, f); xar_err_set_string(x, "stat: Could not link hardlink to original"); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); return -1; } } return 0; } if(opt && (strcmp(opt, "fifo") == 0)) { unlink(file); if( mkfifo(file, 0) ) { xar_err_new(x); xar_err_set_file(x, f); xar_err_set_string(x, "mkfifo: Could not create fifo"); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); return -1; } return 0; } /* skip sockets */ if(opt && (strcmp(opt, "socket") == 0)) { return 0; } CREATEFILE: unlink(file); fd = open(file, O_RDWR|O_CREAT|O_TRUNC, 0600); if( fd > 0 ) close(fd); return 0; }
int32_t xar_set_perm(xar_t x, xar_file_t f, const char *file, char *buffer, size_t len) { const char *opt; int32_t m=0, mset=0; uid_t u; gid_t g; const char *timestr; struct tm t; enum {ATIME=0, MTIME}; struct timeval tv[2]; /* when writing to a buffer, there are no permissions to set */ if ( len ) return 0; /* in case we don't find anything useful in the archive */ u = geteuid(); g = getegid(); opt = xar_opt_get(x, XAR_OPT_OWNERSHIP); if( opt && (strcmp(opt, XAR_OPT_VAL_SYMBOLIC) == 0) ) { struct passwd *pw; struct group *gr; xar_prop_get(f, "user", &opt); if( opt ) { pw = getpwnam(opt); if( pw ) { u = pw->pw_uid; } } xar_prop_get(f, "group", &opt); if( opt ) { gr = getgrnam(opt); if( gr ) { g = gr->gr_gid; } } } if( opt && (strcmp(opt, XAR_OPT_VAL_NUMERIC) == 0) ) { xar_prop_get(f, "uid", &opt); if( opt ) { long long tmp; tmp = strtol(opt, NULL, 10); if( ( (tmp == LLONG_MIN) || (tmp == LLONG_MAX) ) && (errno == ERANGE) ) { return -1; } u = (uid_t)tmp; } xar_prop_get(f, "gid", &opt); if( opt ) { long long tmp; tmp = strtol(opt, NULL, 10); if( ( (tmp == LLONG_MIN) || (tmp == LLONG_MAX) ) && (errno == ERANGE) ) { return -1; } g = (gid_t)tmp; } } xar_prop_get(f, "mode", &opt); if( opt ) { long long tmp; tmp = strtoll(opt, NULL, 8); if( ( (tmp == LLONG_MIN) || (tmp == LLONG_MAX) ) && (errno == ERANGE) ) { return -1; } m = (mode_t)tmp; mset = 1; } xar_prop_get(f, "type", &opt); if( opt && !mset ) { mode_t u = umask(0); umask(u); if( strcmp(opt, "directory") == 0 ) { m = (mode_t)(0777 & ~u); } else { m = (mode_t)(0666 & ~u); } mset = 1; } if( opt && (strcmp(opt, "symlink") == 0) ) { #ifdef HAVE_LCHOWN if( lchown(file, u, g) ) { xar_err_new(x); xar_err_set_file(x, f); xar_err_set_string(x, "perm: could not lchown symlink"); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); } #ifdef HAVE_LCHMOD if( mset ) if( lchmod(file, m) ) { xar_err_new(x); xar_err_set_file(x, f); xar_err_set_string(x, "perm: could not lchmod symlink"); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); } #endif #endif } else { if( chown(file, u, g) ) { xar_err_new(x); xar_err_set_file(x, f); xar_err_set_string(x, "perm: could not chown file"); xar_err_set_errno(x, errno); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); } if( mset ) if( chmod(file, m) ) { xar_err_new(x); xar_err_set_file(x, f); xar_err_set_string(x, "perm: could not chmod file"); xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); } } eacls(x, f, file); memset(tv, 0, sizeof(struct timeval) * 2); xar_prop_get(f, "atime", ×tr); if( timestr ) { memset(&t, 0, sizeof(t)); strptime(timestr, "%FT%T", &t); tv[ATIME].tv_sec = timegm(&t); } else { tv[ATIME].tv_sec = time(NULL); } xar_prop_get(f, "mtime", ×tr); if( timestr ) { memset(&t, 0, sizeof(t)); strptime(timestr, "%FT%T", &t); tv[MTIME].tv_sec = timegm(&t); } else { tv[MTIME].tv_sec = time(NULL); } utimes(file, tv); return 0; }
int pkg_toc_process(const char *path, const char *toc) { u_int32_t pkgid; xar_t x; xar_iter_t i; xar_file_t f; struct vfs_fake_stat sb; if (!(x = xar_open(path, READ))) { Log(LOG_ERROR, "failed opening package %s", path); return EXIT_FAILURE; } xar_register_errhandler(x, pkg_xar_err_callback, NULL); if (!(i = xar_iter_new())) { Log(LOG_ERROR, "failed getting new xar iter in pkg %s", path); return EXIT_FAILURE; } db_pkg_remove(path); pkgid = db_pkg_add(path); fprintf(stderr, "id: %d\n", pkgid); for (f = xar_file_first(x, i); f; f = xar_file_next(i)) { char *size = xar_get_size(x, f); char *xpath = xar_get_path(f); char *xtype = xar_get_type(x, f); char *mode = xar_get_mode(x, f); char *user = xar_get_owner(x, f); char *group = xar_get_group(x, f); char *mtime = xar_get_mtime(x, f); const char *offset; char type = 'u'; /* * (f)ile, (d)irectory, (l)ink, (p)ipe * f(i)fo, (c)haracter, (b)lock, (s)ocket, * (u)ndefined */ if (!strcasecmp(xtype, "file")) { xar_prop_get(f, "data/offset", &offset); type = 'f'; } else { offset = "0"; if (!strcasecmp(xtype, "directory")) type = 'd'; else if (!strcasecmp(xtype, "hardlink")) type = 'l'; else if (!strcasecmp(xtype, "symlink")) type = 'l'; } #if 0 /* * what we gonna do with target? */ printf("%s: %s %8s/%-8s %10s %s %s @ %s\n", xtype, mode, user, group, size, mtime, xpath, offset); db_query(QUERY_INT, "INSERT INTO files (package, path, type, owner, group, size, offset, ctime, mode) VALUES (%lu, '%s', '%s', %s, %s, %s, %s, %s, %s, %s);", pkgid, xpath, type, user, group, size, offset, mtime); #endif free(mtime); free(group); free(user); free(mode); free(xtype); free(xpath); free(size); } return EXIT_SUCCESS; }
static int32_t aacls(xar_file_t f, const char *file) { #ifdef HAVE_SYS_ACL_H #if !defined(__APPLE__) acl_t a; const char *type; xar_prop_get(f, "type", &type); if( !type || (strcmp(type, "symlink") == 0) ) return 0; a = acl_get_file(file, ACL_TYPE_DEFAULT); if( a ) { char *t; acl_entry_t e; /* If the acl is empty, or not valid, skip it */ if( acl_get_entry(a, ACL_FIRST_ENTRY, &e) != 1 ) goto NEXT; t = acl_to_text(a, NULL); if( t ) { xar_prop_set(f, "acl/default", t); acl_free(t); } acl_free(a); } NEXT: a = acl_get_file(file, ACL_TYPE_ACCESS); if( a ) { char *t; acl_entry_t e; /* If the acl is empty, or not valid, skip it */ if( acl_get_entry(a, ACL_FIRST_ENTRY, &e) != 1 ) goto DONE; t = acl_to_text(a, NULL); if( t ) { xar_prop_set(f, "acl/access", t); acl_free(t); } acl_free(a); } DONE: #else /* !__AAPLE__ */ acl_entry_t e = NULL; acl_t a; int i; a = acl_get_file(file, ACL_TYPE_EXTENDED); if( !a ) return 0; for( i = 0; acl_get_entry(a, e == NULL ? ACL_FIRST_ENTRY : ACL_NEXT_ENTRY, &e) == 0; i++ ) { char *t; t = acl_to_text(a, NULL); if( t ) { xar_prop_set(f, "acl/appleextended", t); acl_free(t); } } acl_free(a); #endif /* !__APPLE__ */ #endif return 0; }