/* skip regfile */ int tar_skip_regfile(TAR *t) { int i, k; size_t size; char buf[T_BLOCKSIZE]; if (!TH_ISREG(t)) { errno = EINVAL; return -1; } size = th_get_size(t); for (i = size; i > 0; i -= T_BLOCKSIZE) { k = tar_block_read(t, buf); if (k != T_BLOCKSIZE) { if (k != -1) errno = EINVAL; return -1; } } return 0; }
int tar_extract_glob(TAR *t, char *globname, char *prefix) { char *filename; char buf[MAXPATHLEN]; int i; while ((i = th_read(t)) == 0) { filename = th_get_pathname(t); if (fnmatch(globname, filename, FNM_PATHNAME | FNM_PERIOD)) { if (TH_ISREG(t) && tar_skip_regfile(t)) return -1; continue; } if (t->options & TAR_VERBOSE) th_print_long_ls(t); if (prefix != NULL) snprintf(buf, sizeof(buf), "%s/%s", prefix, filename); else strlcpy(buf, filename, sizeof(buf)); if (tar_extract_file(t, filename) != 0) return -1; } return (i == 1 ? 0 : -1); }
static int par_list(char *file) { PAR *t; int i; if (par_open(&t, file, 1, O_RDONLY, 0, 0) == -1) { fprintf(stderr, "tar_open(): %s\n", strerror(errno)); return -1; } if (par_read_header(t) != 0) { fprintf(stderr, "par_read_header(): %s\n", strerror(errno)); par_close(t); return -1; } while ((i = th_read(t)) == 0) { th_print_long_ls(t); #ifdef DEBUG th_print(t); #endif if (TH_ISREG(t) && par_skip_regfile(t) != 0) { fprintf(stderr, "tar_skip_regfile(): %s\n", strerror(errno)); return -1; } } if (par_close(t) != 0) { fprintf(stderr, "tar_close(): %s\n", strerror(errno)); return -1; } return 0; }
static int list(char *tarfile) { TAR *t; int i; if (tar_open(&t, tarfile, #ifdef HAVE_LIBZ (use_zlib ? &gztype : NULL), #else NULL, #endif O_RDONLY, 0, (verbose ? TAR_VERBOSE : 0) | (use_gnu ? TAR_GNU : 0)) == -1) { fprintf(stderr, "tar_open(): %s\n", strerror(errno)); return -1; } while ((i = th_read(t)) == 0) { th_print_long_ls(t); #ifdef DEBUG th_print(t); #endif if (TH_ISREG(t) && tar_skip_regfile(t) != 0) { fprintf(stderr, "tar_skip_regfile(): %s\n", strerror(errno)); return -1; } } #ifdef DEBUG printf("th_read() returned %d\n", i); printf("EOF mark encountered after %ld bytes\n", # ifdef HAVE_LIBZ (use_zlib ? gzseek((gzFile) t->fd, 0, SEEK_CUR) : # endif lseek(t->fd, 0, SEEK_CUR) # ifdef HAVE_LIBZ ) # endif ); #endif if (tar_close(t) != 0) { fprintf(stderr, "tar_close(): %s\n", strerror(errno)); return -1; } (void)i; return 0; }
/* \internal Checks whether a tar file is valid. A valid tar file does not contains files that start with ./ or contain .. This is intended to prevent malicious packages placing binaries outside of the sandbox directory */ bool check_tar_valid( const QString &tarfile ) { TAR *tarHandle = get_tar_ptr( tarfile ); bool ret=true; QString filename; int i; while ( (i = th_read(tarHandle)) == 0) { filename = th_get_pathname( tarHandle ); if ( !filename.startsWith("./") || filename.contains( "..") ) { ret = false; qWarning() << "check_tar_valid:- tar contains invalid file path: " << filename << "\nAll paths must begin with ./ and not contain .." ; break; } else if ( TH_ISBLK(tarHandle) || TH_ISCHR(tarHandle) ) { ret = false; qWarning() << "check_tar_valid:-tar invalid, contains device special file:" << filename; break; } else if ( TH_ISLNK(tarHandle) ) { ret = false; qWarning() << "check_tar_valid:-tar invalid, contains hard link:" << filename; break; } else if (TH_ISSYM(tarHandle) ) { QString target; if ((tarHandle->options & TAR_GNU) && tarHandle->th_buf.gnu_longlink != NULL) target = tarHandle->th_buf.gnu_longlink; else target = tarHandle->th_buf.linkname; if ( target.startsWith("/") || target.contains( "..") ) { ret = false; qWarning() << "check_tar_valid:tar invalid, contains symlink whose target" << (target.startsWith("/")?"is an absolute path.":"references " "a parent directory.") << "Link:" << filename << "Target:" << target; break; } } if( TH_ISREG(tarHandle) ) tar_skip_regfile(tarHandle); } tar_close( tarHandle ); return ret; }
qlonglong targz_archive_size( const QString &tarfile ) { TAR *tarHandle = get_tar_ptr( tarfile ); qlonglong size = 0; int i; while ((i = th_read(tarHandle)) == 0) { size += th_get_size(tarHandle); if( TH_ISREG(tarHandle) ) tar_skip_regfile(tarHandle); } tar_close( tarHandle ); return size; }
/* appends a file to the tar archive */ int tar_append_file(TAR *t, char *realname, char *savename) { struct stat s; int i; libtar_hashptr_t hp; tar_dev_t *td = NULL; tar_ino_t *ti = NULL; char path[MAXPATHLEN]; #ifdef DEBUG printf("==> tar_append_file(TAR=0x%lx (\"%s\"), realname=\"%s\", " "savename=\"%s\")\n", t, t->pathname, realname, (savename ? savename : "[NULL]")); #endif if (lstat(realname, &s) != 0) { #ifdef DEBUG perror("lstat()"); #endif return -1; } /* set header block */ #ifdef DEBUG puts(" tar_append_file(): setting header block..."); #endif memset(&(t->th_buf), 0, sizeof(struct tar_header)); th_set_from_stat(t, &s); /* set the header path */ #ifdef DEBUG puts(" tar_append_file(): setting header path..."); #endif th_set_path(t, (savename ? savename : realname)); #ifdef HAVE_SELINUX /* get selinux context */ if(t->options & TAR_STORE_SELINUX) { if(t->th_buf.selinux_context != NULL) { free(t->th_buf.selinux_context); t->th_buf.selinux_context = NULL; } security_context_t selinux_context = NULL; if (lgetfilecon(realname, &selinux_context) >= 0) { t->th_buf.selinux_context = strdup(selinux_context); printf("setting selinux context: %s\n", selinux_context); freecon(selinux_context); } else perror("Failed to get selinux context"); } #endif /* check if it's a hardlink */ #ifdef DEBUG puts(" tar_append_file(): checking inode cache for hardlink..."); #endif libtar_hashptr_reset(&hp); if (libtar_hash_getkey(t->h, &hp, &(s.st_dev), (libtar_matchfunc_t)dev_match) != 0) td = (tar_dev_t *)libtar_hashptr_data(&hp); else { #ifdef DEBUG printf("+++ adding hash for device (0x%lx, 0x%lx)...\n", major(s.st_dev), minor(s.st_dev)); #endif td = (tar_dev_t *)calloc(1, sizeof(tar_dev_t)); td->td_dev = s.st_dev; td->td_h = libtar_hash_new(256, (libtar_hashfunc_t)ino_hash); if (td->td_h == NULL) return -1; if (libtar_hash_add(t->h, td) == -1) return -1; } libtar_hashptr_reset(&hp); if (libtar_hash_getkey(td->td_h, &hp, &(s.st_ino), (libtar_matchfunc_t)ino_match) != 0) { ti = (tar_ino_t *)libtar_hashptr_data(&hp); #ifdef DEBUG printf(" tar_append_file(): encoding hard link \"%s\" " "to \"%s\"...\n", realname, ti->ti_name); #endif t->th_buf.typeflag = LNKTYPE; th_set_link(t, ti->ti_name); } else { #ifdef DEBUG printf("+++ adding entry: device (0x%lx,0x%lx), inode %ld " "(\"%s\")...\n", major(s.st_dev), minor(s.st_dev), s.st_ino, realname); #endif ti = (tar_ino_t *)calloc(1, sizeof(tar_ino_t)); if (ti == NULL) return -1; ti->ti_ino = s.st_ino; snprintf(ti->ti_name, sizeof(ti->ti_name), "%s", savename ? savename : realname); libtar_hash_add(td->td_h, ti); } /* check if it's a symlink */ if (TH_ISSYM(t)) { i = readlink(realname, path, sizeof(path)); if (i == -1) return -1; if (i >= MAXPATHLEN) i = MAXPATHLEN - 1; path[i] = '\0'; #ifdef DEBUG printf(" tar_append_file(): encoding symlink \"%s\" -> " "\"%s\"...\n", realname, path); #endif th_set_link(t, path); } /* print file info */ if (t->options & TAR_VERBOSE) th_print_long_ls(t); #ifdef DEBUG puts(" tar_append_file(): writing header"); #endif /* write header */ if (th_write(t) != 0) { #ifdef DEBUG printf("t->fd = %d\n", t->fd); #endif return -1; } #ifdef DEBUG puts(" tar_append_file(): back from th_write()"); #endif /* if it's a regular file, write the contents as well */ if (TH_ISREG(t) && tar_append_regfile(t, realname) != 0) return -1; return 0; }
/* extract regular file */ int tar_extract_regfile(TAR *t, char *realname) { mode_t mode; size_t size; uid_t uid; gid_t gid; int fdout; int i, k; char buf[T_BLOCKSIZE]; char *filename; #ifdef DEBUG printf("==> tar_extract_regfile(t=0x%lx, realname=\"%s\")\n", t, realname); #endif if (!TH_ISREG(t)) { errno = EINVAL; return -1; } filename = (realname ? realname : th_get_pathname(t)); mode = th_get_mode(t); size = th_get_size(t); uid = th_get_uid(t); gid = th_get_gid(t); if (mkdirhier(dirname(filename)) == -1) return -1; #ifdef DEBUG printf(" ==> extracting: %s (mode %04o, uid %d, gid %d, %d bytes)\n", filename, mode, uid, gid, size); #endif fdout = open(filename, O_WRONLY | O_CREAT | O_TRUNC #ifdef O_BINARY | O_BINARY #endif , 0666); if (fdout == -1) { #ifdef DEBUG perror("open()"); #endif return -1; } #if 0 /* change the owner. (will only work if run as root) */ if (fchown(fdout, uid, gid) == -1 && errno != EPERM) { #ifdef DEBUG perror("fchown()"); #endif return -1; } /* make sure the mode isn't inheritted from a file we're overwriting */ if (fchmod(fdout, mode & 07777) == -1) { #ifdef DEBUG perror("fchmod()"); #endif return -1; } #endif /* extract the file */ for (i = size; i > 0; i -= T_BLOCKSIZE) { k = tar_block_read(t, buf); if (k != T_BLOCKSIZE) { if (k != -1) errno = EINVAL; return -1; } /* write block to output file */ if (write(fdout, buf, ((i > T_BLOCKSIZE) ? T_BLOCKSIZE : i)) == -1) return -1; } /* close output file */ if (close(fdout) == -1) return -1; #ifdef DEBUG printf("### done extracting %s\n", filename); #endif return 0; }
static int sandbox_attr(void *fpctx,void *handle,const char *attr,glite_jp_attrval_t **attrval) { glite_jp_error_t err; glite_jp_context_t ctx = fpctx; glite_jp_attrval_t *out = NULL; int i,nout = 0, count = 0; sb_handle *h = handle; printf("sandbox_attr() called\n"); memset(&err,0,sizeof err); err.source = __FUNCTION__; glite_jp_clear_error(ctx); *attrval = NULL; if (!strcmp(attr, GLITE_JP_ATTR_ISB_FILENAME)) { while ((i = th_read(h->t)) == 0) { printf("-- %s\n", th_get_pathname(h->t)); if ( !(count % ALLOC_CHUNK) ) { *attrval = realloc(*attrval, (count + ALLOC_CHUNK + 1) * sizeof(**attrval) ); memset( (*attrval) + count, 0, (ALLOC_CHUNK + 1) * sizeof(**attrval)); } (*attrval)[count].name = strdup(GLITE_JP_ATTR_ISB_FILENAME); (*attrval)[count].value = strdup(th_get_pathname(h->t)); (*attrval)[count].origin = GLITE_JP_ATTR_ORIG_FILE; (*attrval)[count].timestamp = th_get_mtime(h->t); count++; if (TH_ISREG(h->t) && tar_skip_regfile(h->t) != 0) { err.code = EIO; err.desc = "tar_skip_regfile"; return glite_jp_stack_error(ctx,&err); } } } else if (!strcmp(attr, GLITE_JP_ATTR_OSB_FILENAME)) { printf("Namespace %s not implemented yet\n", GLITE_JP_ATTR_OSB_FILENAME); } else if (strstr(attr,GLITE_JP_OSB_CONTENT_NS)) { printf("Namespace %s not implemented yet\n", GLITE_JP_OSB_CONTENT_NS); } else if (strstr(attr,GLITE_JP_ISB_CONTENT_NS)) { char *fileName = (char *) attr + sizeof(GLITE_JP_ISB_CONTENT_NS); printf("untaring file: %s\n", fileName); while (th_read(h->t) == 0) { if ( !strcmp(fileName, th_get_pathname(h->t)) ) { /* extract the file */ int k; size_t size; char buf[T_BLOCKSIZE]; char *value; if (!TH_ISREG(h->t)) assert(0); // not a regular file size = th_get_size(h->t); value = (char *) malloc(size * sizeof(char) + 1); memset( value, 0, size * sizeof(char) + 1); for (i = 0; i < size; i += T_BLOCKSIZE) { k = tar_block_read(h->t, buf); if (k == -1) { err.code = errno; err.desc = "tar_block_read"; return glite_jp_stack_error(ctx,&err); } // tar_block_read calls glite_jppsbe_pread, which usually // returns whole block (read from the middle of uploaded // tar file // so cut k in order to the last chunk had correct size if (i + T_BLOCKSIZE > size) { k = size - i; } strncpy(value + i, buf, k); } *attrval = malloc(2 * sizeof(**attrval) ); memset( (*attrval), 0, 2 * sizeof(**attrval)); (*attrval)[0].name = strdup(attr); (*attrval)[0].value = value; (*attrval)[0].origin = GLITE_JP_ATTR_ORIG_FILE; (*attrval)[0].timestamp = th_get_mtime(h->t); } else if (TH_ISREG(h->t) && tar_skip_regfile(h->t) != 0) { err.code = EIO; err.desc = "tar_skip_regfile"; return glite_jp_stack_error(ctx,&err); } } } return glite_jp_stack_error(ctx,&err); }