Skip to content

Commit

Permalink
Make sure we use and report the modification time consistently.
Browse files Browse the repository at this point in the history
This is important, since it is used for password verification.

Adresses issue #394.
  • Loading branch information
dillof committed Aug 23, 2023
1 parent b9cb7e2 commit d148b0e
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 6 deletions.
5 changes: 5 additions & 0 deletions lib/zip_close.c
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,11 @@ add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de, zip_uint32_t changed) {
src_final = src;
zip_source_keep(src_final);

if (!needs_decrypt && de->encryption_method == ZIP_EM_TRAD_PKWARE && (de->changed & ZIP_DIRENT_LAST_MOD)) {
/* PKWare encryption uses the last modification time for password verification, therefore we can't change it without re-encrypting. Ignoring the requested modification time change seems more sensible than failing to close the archive. */
de->changed &= ~ZIP_DIRENT_LAST_MOD;
}

if (needs_decrypt) {
zip_encryption_implementation impl;

Expand Down
35 changes: 29 additions & 6 deletions lib/zip_source_pkware_encode.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ struct trad_pkware {
zip_pkware_keys_t keys;
zip_buffer_t *buffer;
bool eof;
bool mtime_set;
time_t mtime;
zip_error_t error;
};

Expand All @@ -50,7 +52,7 @@ static int encrypt_header(zip_source_t *, struct trad_pkware *);
static zip_int64_t pkware_encrypt(zip_source_t *, void *, void *, zip_uint64_t, zip_source_cmd_t);
static void trad_pkware_free(struct trad_pkware *);
static struct trad_pkware *trad_pkware_new(const char *password, zip_error_t *error);

static void set_mtime(struct trad_pkware* ctx, zip_stat_t* st);

zip_source_t *
zip_source_pkware_encode(zip_t *za, zip_source_t *src, zip_uint16_t em, int flags, const char *password) {
Expand Down Expand Up @@ -81,16 +83,19 @@ zip_source_pkware_encode(zip_t *za, zip_source_t *src, zip_uint16_t em, int flag

static int
encrypt_header(zip_source_t *src, struct trad_pkware *ctx) {
struct zip_stat st;
unsigned short dostime, dosdate;
zip_uint8_t *header;

if (zip_source_stat(src, &st) != 0) {
zip_error_set_from_source(&ctx->error, src);
return -1;
if (!ctx->mtime_set) {
struct zip_stat st;
if (zip_source_stat(src, &st) != 0) {
zip_error_set_from_source(&ctx->error, src);
return -1;
}
set_mtime(ctx, &st);
}

_zip_u2d_time(st.mtime, &dostime, &dosdate);
_zip_u2d_time(ctx->mtime, &dostime, &dosdate);

if ((ctx->buffer = _zip_buffer_new(NULL, ZIP_CRYPTO_PKWARE_HEADERLEN)) == NULL) {
zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
Expand Down Expand Up @@ -182,6 +187,9 @@ pkware_encrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t length, zip
if (st->valid & ZIP_STAT_COMP_SIZE) {
st->comp_size += ZIP_CRYPTO_PKWARE_HEADERLEN;
}
set_mtime(ctx, st);
st->mtime = ctx->mtime;
st->valid |= ZIP_STAT_MTIME;

return 0;
}
Expand Down Expand Up @@ -229,6 +237,8 @@ trad_pkware_new(const char *password, zip_error_t *error) {
return NULL;
}
ctx->buffer = NULL;
ctx->mtime_set = false;
ctx->mtime = 0;
zip_error_init(&ctx->error);

return ctx;
Expand All @@ -246,3 +256,16 @@ trad_pkware_free(struct trad_pkware *ctx) {
zip_error_fini(&ctx->error);
free(ctx);
}


static void set_mtime(struct trad_pkware* ctx, zip_stat_t* st) {
if (!ctx->mtime_set) {
if (st->valid & ZIP_STAT_MTIME) {
ctx->mtime = st->mtime;
}
else {
time(&ctx->mtime);
}
ctx->mtime_set = true;
}
}

0 comments on commit d148b0e

Please sign in to comment.