X-Git-Url: http://git.osdn.net/view?p=lha%2Flha.git;a=blobdiff_plain;f=src%2Flhext.c;h=ad6ec1bd9017c4847ccf4463bb0440345f6e4a00;hp=bbfd95831a9886061691a8ab9310a4c2e624ea76;hb=cac04476fbf56b8b99ea857ffde147e682f06ab8;hpb=7310b2088a8d9cb6c9e9bca3444e225c839182ff diff --git a/src/lhext.c b/src/lhext.c index bbfd958..ad6ec1b 100644 --- a/src/lhext.c +++ b/src/lhext.c @@ -22,6 +22,7 @@ static char *methods[] = LZHUFF4_METHOD, LZHUFF5_METHOD, LZHUFF6_METHOD, LZHUFF7_METHOD, LARC_METHOD, LARC5_METHOD, LARC4_METHOD, LZHDIRS_METHOD, + PMARC0_METHOD, PMARC2_METHOD, NULL }; @@ -82,6 +83,49 @@ inquire_extract(name) return TRUE; } +static boolean +make_name_with_pathcheck(char *name, size_t namesz, const char *q) +{ + int offset = 0; + const char *p; + int sz; + struct stat stbuf; + + if (extract_directory) { + sz = xsnprintf(name, namesz, "%s/", extract_directory); + if (sz == -1) { + return FALSE; + } + offset += sz; + } + +#ifdef S_IFLNK + while ((p = strchr(q, '/')) != NULL) { + if (namesz - offset < (p - q) + 2) { + return FALSE; + } + memcpy(name + offset, q, (p - q)); + name[offset + (p - q)] = 0; + + offset += (p - q); + q = p + 1; + + if (lstat(name, &stbuf) < 0) { + name[offset++] = '/'; + break; + } + if (is_symlink(&stbuf)) { + return FALSE; + } + name[offset++] = '/'; + } +#endif + + str_safe_copy(name + offset, q, namesz - offset); + + return TRUE; +} + /* ------------------------------------------------------------------------ */ static boolean make_parent_path(name) @@ -154,6 +198,23 @@ open_with_make_path(name) } /* ------------------------------------------------------------------------ */ +static int +symlink_with_make_path(realname, name) + const char *realname; + const char *name; +{ + int l_code; + + l_code = symlink(realname, name); + if (l_code < 0) { + make_parent_path(name); + l_code = symlink(realname, name); + } + + return l_code; +} + +/* ------------------------------------------------------------------------ */ static void adjust_info(name, hdr) char *name; @@ -232,8 +293,8 @@ extract_one(afp, hdr) } else { if (is_directory_traversal(q)) { - fprintf(stderr, "Possible directory traversal hack attempt in %s\n", q); - exit(111); + error("Possible directory traversal hack attempt in %s", q); + exit(1); } if (*q == '/') { @@ -253,16 +314,16 @@ extract_one(afp, hdr) } } - if (extract_directory) - xsnprintf(name, sizeof(name), "%s/%s", extract_directory, q); - else - str_safe_copy(name, q, sizeof(name)); + if (!make_name_with_pathcheck(name, sizeof(name), q)) { + error("Possible symlink traversal hack attempt in %s", q); + exit(1); + } - /* LZHDIRS_METHOD¤ò»ý¤Ä¥Ø¥Ã¥À¤ò¥Á¥§¥Ã¥¯¤¹¤ë */ + /* LZHDIRS_METHODを持つヘッダをチェックする */ /* 1999.4.30 t.okamoto */ for (method = 0;; method++) { if (methods[method] == NULL) { - error("Unknown method \"%.*s\"; \"%s\" will be skiped ...", + error("Unknown method \"%.*s\"; \"%s\" will be skipped ...", 5, hdr->method, name); return read_size; } @@ -276,7 +337,7 @@ extract_one(afp, hdr) #if 0 for (method = 0;; method++) { if (methods[method] == NULL) { - error("Unknown method \"%.*s\"; \"%s\" will be skiped ...", + error("Unknown method \"%.*s\"; \"%s\" will be skipped ...", 5, hdr->method, name); return read_size; } @@ -437,8 +498,8 @@ extract_one(afp, hdr) else if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_DIRECTORY || (hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_SYMLINK || method == LZHDIRS_METHOD_NUM) { - /* ¢¬¤³¤ì¤Ç¡¢Symbolic Link ¤Ï¡¢Âç¾æÉפ«¡© */ - if (!ignore_directory && !verify_mode) { + /* ↑これで、Symbolic Link は、大丈夫か? */ + if (!ignore_directory && !verify_mode && !output_to_stdout) { if (noexec) { if (quiet != TRUE) printf("EXTRACT %s (directory)\n", name); @@ -465,8 +526,7 @@ extract_one(afp, hdr) } unlink(name); - make_parent_path(name); - l_code = symlink(hdr->realname, name); + l_code = symlink_with_make_path(hdr->realname, name); if (l_code < 0) { if (quiet != TRUE) warning("Can't make Symbolic Link \"%s\" -> \"%s\"", @@ -483,7 +543,7 @@ extract_one(afp, hdr) #endif } else { /* make directory */ - if (!output_to_stdout && !make_parent_path(name)) + if (!make_parent_path(name)) return read_size; /* save directory information */ add_dirinfo(name, hdr); @@ -497,7 +557,7 @@ extract_one(afp, hdr) error("Unknown file type: \"%s\". use `f' option to force extract.", name); } - if (!output_to_stdout) { + if (!output_to_stdout && !verify_mode) { if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) != UNIX_FILE_DIRECTORY) adjust_info(name, hdr); } @@ -505,6 +565,25 @@ extract_one(afp, hdr) return read_size; } +static int +skip_to_nextpos(FILE *fp, off_t pos, off_t off, off_t read_size) +{ + if (pos != -1) { + if (fseeko(fp, pos + off, SEEK_SET) != 0) { + return -1; + } + } + else { + off_t i = off - read_size; + while (i--) { + if (fgetc(fp) == EOF) { + return -1; + } + } + } + return 0; +} + /* ------------------------------------------------------------------------ */ /* EXTRACT COMMAND MAIN */ /* ------------------------------------------------------------------------ */ @@ -525,25 +604,19 @@ cmd_extract() /* extract each files */ while (get_header(afp, &hdr)) { + pos = ftello(afp); if (need_file(hdr.name)) { - pos = ftello(afp); read_size = extract_one(afp, &hdr); if (read_size != hdr.packed_size) { /* when error occurred in extract_one(), should adjust point of file stream */ - if (pos != -1 && afp != stdin) - fseeko(afp, pos + hdr.packed_size - read_size, SEEK_SET); - else { - off_t i = hdr.packed_size - read_size; - while (i--) fgetc(afp); + if (skip_to_nextpos(afp, pos, hdr.packed_size, read_size) == -1) { + fatal_error("Cannot seek to next header position from \"%s\"", hdr.name); } } } else { - if (afp != stdin) - fseeko(afp, hdr.packed_size, SEEK_CUR); - else { - off_t i = hdr.packed_size; - while (i--) fgetc(afp); + if (skip_to_nextpos(afp, pos, hdr.packed_size, 0) == -1) { + fatal_error("Cannot seek to next header position from \"%s\"", hdr.name); } } }