Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 3 additions & 21 deletions src/htsbauth.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Please visit our Website: http://www.httrack.com
/* specific definitions */
#include "htsglobal.h"
#include "htslib.h"
#include "htslines.h"
#include "htscore.h"
#include "htspsl.h"
#include "htsdate.h"
Expand Down Expand Up @@ -1099,25 +1100,6 @@ int cookie_load_from(httrackp *opt, t_cookie *cookie, const char *fpath,
return -1;
}

/* Open name for writing, creating it if needed, and return NULL on failure.
The file is owner-only on Unix because it holds session cookies. */
static FILE *cookie_create(const char *name) {
char catbuff[CATBUFF_SIZE];
#ifdef _WIN32
return FOPEN(fconv(catbuff, sizeof(catbuff), name), "wb");
#else
const int fd = open(fconv(catbuff, sizeof(catbuff), name),
O_WRONLY | O_CREAT | O_TRUNC, HTS_PROTECT_FILE);
FILE *fp = fd != -1 ? fdopen(fd, "wb") : NULL;

if (fd != -1 && fp == NULL)
close(fd); /* fdopen failed: don't leak the descriptor */
if (fp != NULL) /* O_CREAT's mode skips pre-existing jars: tighten those */
(void) fchmod(fd, HTS_PROTECT_FILE);
return fp;
#endif
}

/* Flush fp to the disk and close it. Did every step succeed? */
static hts_boolean cookie_close_synced(FILE *fp) {
// a crash after the rename must not leave an empty file behind it
Expand All @@ -1139,7 +1121,7 @@ int cookie_save_fault_selftest = 0;
success. */
static int cookie_write(t_cookie *cookie, const char *name) {
char BIGSTK line[8192];
FILE *fp = cookie_create(name);
FILE *fp = hts_fopen_private(name, "wb");

if (fp) {
const char *a = cookie->data;
Expand Down Expand Up @@ -1189,7 +1171,7 @@ static hts_boolean cookie_copy(const char *src, const char *dst) {
const int fault = cookie_save_fault_selftest;
char buf[8192];
FILE *const in = FOPEN(src, "rb");
FILE *const out = in != NULL ? cookie_create(dst) : NULL;
FILE *const out = in != NULL ? hts_fopen_private(dst, "wb") : NULL;
hts_boolean ok = out != NULL;
size_t n;

Expand Down
19 changes: 14 additions & 5 deletions src/htscache.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Please visit our Website: http://www.httrack.com
#include "htsio.h"
#include "htsbasenet.h"
#include "htsmd5.h"
#include "htslines.h"
#include <limits.h>
#include <time.h>

Expand Down Expand Up @@ -1470,7 +1471,14 @@ void cache_init(cache_back * cache, httrackp * opt) {
StringBuff(opt->path_log), "hts-cache/"));

{
/* Create ZIP file cache */
/* owner-only before an entry names a URL: zip's "wb" keeps the mode */
FILE *const zfp = hts_fopen_private(
fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
StringBuff(opt->path_log), "hts-cache/new.zip"),
"wb");

if (zfp != NULL)
fclose(zfp);
cache->zipOutput = (void *) hts_zipOpen_utf8(
fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
StringBuff(opt->path_log), "hts-cache/new.zip"),
Expand Down Expand Up @@ -1514,10 +1522,11 @@ void cache_init(cache_back * cache, httrackp * opt) {
fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
StringBuff(opt->path_log), "hts-cache/old.txt"));
// ouvrir
cache->txt =
FOPEN(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
StringBuff(opt->path_log), "hts-cache/new.txt"),
"wb");
/* owner-only: it lists URLs with their passwords */
cache->txt = hts_fopen_private(
fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
StringBuff(opt->path_log), "hts-cache/new.txt"),
"wb");
if (cache->txt) {
fprintf(cache->txt,
"date\tsize'/'remotesize\tflags(request:Update,Range state:File response:Modified,Chunked,gZipped)\t");
Expand Down
33 changes: 20 additions & 13 deletions src/htscoremain.c
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ HTSEXT_API int hts_main(int argc, char **argv) {
written at all. */
static hts_boolean write_progress_lock(httrackp *opt, const char *path,
const char *t, int argc, char **argv) {
FILE *fp = FOPEN(path, "wb");
FILE *fp = hts_fopen_private(path, "wb"); /* it echoes argv */
int i;

if (fp == NULL)
Expand Down Expand Up @@ -2946,13 +2946,16 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
/* Check FS directory structure created */
structcheck_utf8(StringBuff(opt->path_log));

opt->log = FOPEN(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
StringBuff(opt->path_log), "hts-log.txt"),
"w");
if (httrack_logmode == 2)
opt->errlog = FOPEN(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
StringBuff(opt->path_log), "hts-err.txt"),
/* owner-only: the log echoes the command line and URLs with passwords */
opt->log =
hts_fopen_private(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
StringBuff(opt->path_log), "hts-log.txt"),
"w");
if (httrack_logmode == 2)
opt->errlog =
hts_fopen_private(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
StringBuff(opt->path_log), "hts-err.txt"),
"w");
else
opt->errlog = opt->log;
if (opt->log == NULL) {
Expand Down Expand Up @@ -2984,9 +2987,11 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
// -%H may run before path_log exists, so create it first.
if (_DEBUG_HEAD) {
structcheck_utf8(StringBuff(opt->path_log));
ioinfo = FOPEN(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
StringBuff(opt->path_log), "hts-ioinfo.txt"),
"wb");
/* owner-only: it records request headers, Authorization included */
ioinfo = hts_fopen_private(
fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
StringBuff(opt->path_log), "hts-ioinfo.txt"),
"wb");
if (ioinfo == NULL)
hts_log_print(opt, LOG_WARNING | LOG_ERRNO,
"unable to create header debug file %s",
Expand Down Expand Up @@ -3063,9 +3068,11 @@ static int hts_main_internal(int argc, char **argv, httrackp * opt) {
(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt), StringBuff(opt->path_log), "hts-cache"),
HTS_PROTECT_FOLDER);
#endif
fp = FOPEN(fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
StringBuff(opt->path_log), "hts-cache/doit.log"),
"wb");
/* owner-only: the command line may carry credentials */
fp = hts_fopen_private(
fconcat(OPT_GET_BUFF(opt), OPT_GET_BUFF_SIZE(opt),
StringBuff(opt->path_log), "hts-cache/doit.log"),
"wb");
if (fp) {
String line = STRING_EMPTY;

Expand Down
35 changes: 33 additions & 2 deletions src/htslines.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,46 @@

/* ------------------------------------------------------------ */
/* File: htslines.c */
/* line readers for config files, shared by the engine */
/* and htsserver */
/* line readers for config files and an owner-only file */
/* opener, shared by the engine and htsserver */
/* Author: Xavier Roche */
/* ------------------------------------------------------------ */

#include "htslines.h"
#include "htslib.h"

#include <errno.h>
#include <string.h>
#ifndef _WIN32
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#endif

FILE *hts_fopen_private(const char *name, const char *mode) {
char catbuff[CATBUFF_SIZE];

/* O_TRUNC below would silently turn an append into a rewrite */
if (strcmp(mode, "w") != 0 && strcmp(mode, "wb") != 0) {
errno = EINVAL;
return NULL;
}
#ifdef _WIN32
return FOPEN(fconv(catbuff, sizeof(catbuff), name), mode);
#else
{
const int fd = open(fconv(catbuff, sizeof(catbuff), name),
Comment thread
xroche marked this conversation as resolved.
Dismissed
O_WRONLY | O_CREAT | O_TRUNC, HTS_PROTECT_FILE);
FILE *fp = fd != -1 ? fdopen(fd, mode) : NULL;

if (fd != -1 && fp == NULL)
close(fd); /* fdopen failed: don't leak the descriptor */
if (fp != NULL) /* O_CREAT's mode skips pre-existing files: tighten those */
(void) fchmod(fd, HTS_PROTECT_FILE);
return fp;
}
#endif
}

/* Is c one of the bytes flags drop? */
static hts_boolean line_drops(int c, int flags) {
Expand Down
8 changes: 6 additions & 2 deletions src/htslines.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ Please visit our Website: http://www.httrack.com

/* ------------------------------------------------------------ */
/* File: htslines.h */
/* line readers for config files, shared by the engine */
/* and htsserver */
/* line readers for config files and an owner-only file */
/* opener, shared by the engine and htsserver */
/* Author: Xavier Roche */
/* ------------------------------------------------------------ */

Expand All @@ -41,6 +41,10 @@ Please visit our Website: http://www.httrack.com
#include <stddef.h>
#include <stdio.h>

/* Open UTF-8 path name for writing ("w" or "wb" only), owner-only on Unix,
truncating it; NULL on failure. Links are followed, as fopen() does. */
FILE *hts_fopen_private(const char *name, const char *mode);

/* Flags for the readers below, which always drop CR. */
#define HTS_LINE_DROP_TAB 1 /* TAB */
#define HTS_LINE_DROP_NUL 2 /* NUL */
Expand Down
75 changes: 75 additions & 0 deletions src/htslines_selftest.c
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,78 @@ static int st_linediff(httrackp *opt, int argc, char **argv) {
return k.failures == 0 ? 0 : 1;
}

/* hts_fopen_private() under umask 022: fstat() right after the open, before any
write, so a file made private only once written fails too. Arg: a directory.
*/
static int st_fopen_private(httrackp *opt, int argc, char **argv) {
char path[HTS_URLMAXSIZE * 2];
char data[8];
int failures = 0;
FILE *fp;
size_t i;
static const char *const refused[] = {"a", "ab", "r", "r+", "w+", "wb+"};

(void) opt;
if (argc < 1) {
printf("usage: -#test=fopen-private <dir>\n");
return 1;
}
snprintf(path, sizeof(path), "%s/kept", argv[0]);
fp = FOPEN(path, "wb");
if (fp == NULL || fputs("kept", fp) == EOF || fclose(fp) != 0) {
printf("fopen-private: cannot write %s\n", path);
return 1;
}
for (i = 0; i < sizeof(refused) / sizeof(refused[0]); i++) {
errno = 0;
fp = hts_fopen_private(path, refused[i]);
if (fp != NULL || errno != EINVAL) {
printf("fopen-private: mode \"%s\" was not refused\n", refused[i]);
failures++;
if (fp != NULL)
fclose(fp);
}
}
fp = FOPEN(path, "rb");
if (fp == NULL || fread(data, 1, sizeof(data), fp) != 4 ||
memcmp(data, "kept", 4) != 0) {
printf("fopen-private: a refused mode changed the file\n");
failures++;
}
if (fp != NULL)
fclose(fp);
#ifndef _WIN32
{
const mode_t old = umask(022);
static const char *const names[] = {"fresh", "kept"};

/* "kept" exists at 0644 from older runs: it must be tightened and emptied
*/
snprintf(path, sizeof(path), "%s/kept", argv[0]);
(void) chmod(path, 0644);
for (i = 0; i < sizeof(names) / sizeof(names[0]); i++) {
struct stat st;

snprintf(path, sizeof(path), "%s/%s", argv[0], names[i]);
fp = hts_fopen_private(path, i == 0 ? "w" : "wb");
if (fp == NULL || fstat(fileno(fp), &st) != 0) {
printf("fopen-private: cannot open %s\n", names[i]);
failures++;
} else if ((st.st_mode & 0777) != 0600 || st.st_size != 0) {
printf("fopen-private: %s is mode %03o size %d before any write\n",
names[i], (unsigned) (st.st_mode & 0777), (int) st.st_size);
failures++;
}
if (fp != NULL)
fclose(fp);
}
(void) umask(old);
}
#endif
printf("fopen-private: %s\n", failures == 0 ? "OK" : "FAIL");
return failures == 0 ? 0 : 1;
}

/* ------------------------------------------------------------ */
/* Registry: this module's tests, in the order -#test lists them. */
/* ------------------------------------------------------------ */
Expand All @@ -410,5 +482,8 @@ const struct selftest_entry selftests_lines[] = {
"config-file line reader: [line] per read, ! when cut", st_readline},
{"linediff", "", "line readers against the legacy ones they replaced",
st_linediff},
{"fopen-private", "<dir>",
"owner-only opener: 0600 before the first write, append refused",
st_fopen_private},
{NULL, NULL, NULL, NULL},
};
3 changes: 2 additions & 1 deletion src/htsserver.c
Original file line number Diff line number Diff line change
Expand Up @@ -1936,7 +1936,8 @@ int smallserver(T_SOC soc, char *url, char *method, char *data, char *path) {

StringCopy(website, StringBuff(fspath));
StringCat(tmpbuff, "winprofile.ini");
fp = fopen(StringBuff(tmpbuff), "wb");
/* owner-only: the profile may hold proxy credentials */
fp = hts_fopen_private(StringBuff(tmpbuff), "wb");
if (fp != NULL) {
int count;

Expand Down
Loading
Loading