Skip to content

Commit

Permalink
Output file access
Browse files Browse the repository at this point in the history
- Fix #279: Add new conf options to control output file access:
  - `output_user`: set output file user ownership
  - `output_group`: set output file group ownership
  - `output_mod`: set output file mode bits
  • Loading branch information
jelu committed Mar 6, 2023
1 parent 50acf9c commit da06317
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 7 deletions.
46 changes: 46 additions & 0 deletions src/config_hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ extern int threads_flag;
uint64_t minfree_bytes = 0;
int output_format_xml = 0;
int output_format_json = 0;
uid_t output_uid = -1;
gid_t output_gid = -1;
mode_t output_mod = 0664;
#define MAX_HASH_SIZE 512
static hashtbl* dataset_hash = NULL;
uint64_t statistics_interval = 60; /* default interval in seconds*/
Expand Down Expand Up @@ -708,3 +711,46 @@ int load_tld_list(const char* file)

return 1;
}

int set_output_user(const char* user)
{
struct passwd* pw = getpwnam(user);
if (!pw) {
dsyslogf(LOG_ERR, "user %s does not exist", user);
return 0;
}
output_uid = pw->pw_uid;

dsyslogf(LOG_INFO, "using user %s[%d] for output file", user, output_uid);

return 1;
}

int set_output_group(const char* group)
{
struct group* gr = getgrnam(group);
if (!gr) {
dsyslogf(LOG_ERR, "group %s does not exist", group);
return 0;
}
output_gid = gr->gr_gid;

dsyslogf(LOG_INFO, "using group %s[%d] for output file", group, output_gid);

return 1;
}

int set_output_mod(const char* mod)
{
unsigned long int m = strtoul(mod, NULL, 8);
if (m == ULONG_MAX) {
char errbuf[512];
dsyslogf(LOG_ERR, "invalid file mode, strtoul: %s", dsc_strerror(errno, errbuf, sizeof(errbuf)));
return 0;
}
output_mod = m;

dsyslogf(LOG_INFO, "using file mode %o for output file", output_mod);

return 1;
}
3 changes: 3 additions & 0 deletions src/config_hooks.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,5 +81,8 @@ int set_response_time_max_sec_mode(const char* s);
int set_response_time_bucket_size(const char* s);
int load_knowntlds(const char* file);
int load_tld_list(const char* file);
int set_output_user(const char* user);
int set_output_group(const char* group);
int set_output_mod(const char* mod);

#endif /* __dsc_config_hooks_h */
14 changes: 9 additions & 5 deletions src/daemon.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ extern md_array_printer xml_printer;
extern md_array_printer json_printer;
extern int output_format_xml;
extern int output_format_json;
extern uid_t output_uid;
extern gid_t output_gid;
extern mode_t output_mod;
extern int dump_reports_on_exit;
extern uint64_t statistics_interval;
extern int no_wait_interval;
Expand Down Expand Up @@ -290,11 +293,12 @@ dump_report(md_array_printer* printer)

fputs(printer->end_file, fp);

/*
* XXX need chmod because files are written as root, but may be processed
* by a non-priv user
*/
fchmod(fd, 0664);
if (fchown(fd, output_uid, output_gid)) {
dsyslogf(LOG_ERR, "%s: unable to fchown(): %s", tname, dsc_strerror(errno, errbuf, sizeof(errbuf)));
}
if (fchmod(fd, output_mod)) {
dsyslogf(LOG_ERR, "%s: unable to fchmod(): %s", tname, dsc_strerror(errno, errbuf, sizeof(errbuf)));
}
fclose(fp);
dfprintf(0, "renaming to %s", fname);

Expand Down
16 changes: 16 additions & 0 deletions src/dsc.conf.5.in
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,19 @@ any number of times.
Default output format is XML, see section DATA FORMATS and FILE NAMING
CONVENTIONS.
.TP
\fBoutput_user\fR USER ;
Specify which user should own the output file, default to the user running
.IR dsc .
.TP
\fBoutput_group\fR GROUP ;
Specify which group should own the output file, default to the group of the
user running
.IR dsc .
.TP
\fBoutput_mod\fR FILE_MODE_BITS ;
Specify the file mode bits (in octal) for the output file permissions,
default to 0664.
.TP
\fBdump_reports_on_exit\fR ;
Dump any remaining report before exiting.

Expand Down Expand Up @@ -965,6 +978,9 @@ dataset direction_vs_ipproto ip Direction:ip_direction IPProto:ip_proto any;
#no_wait_interval;
output_format XML;
#output_format JSON;
#output_user root;
#output_group root;
#output_mod 0664;

#geoip_v4_dat "/usr/share/GeoIP/GeoIP.dat" STANDARD MEMORY_CACHE MMAP_CACHE;
#geoip_v6_dat "/usr/share/GeoIP/GeoIPv6.dat";
Expand Down
9 changes: 9 additions & 0 deletions src/dsc.conf.sample.in
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,15 @@ dataset direction_vs_ipproto ip Direction:ip_direction IPProto:ip_proto any;
#output_format XML;
#output_format JSON;

# output file access
#
# Following options controls the user, group and file mode bits for the
# output file.
#
#output_user root;
#output_group root;
#output_mod 0664;

# dump_reports_on_exit
#
# Dump any remaining report before exiting.
Expand Down
54 changes: 54 additions & 0 deletions src/parse_conf.c
Original file line number Diff line number Diff line change
Expand Up @@ -952,6 +952,51 @@ int parse_conf_tld_list(const conf_token_t* tokens)
return ret == 1 ? 0 : 1;
}

int parse_conf_output_user(const conf_token_t* tokens)
{
char* user = strndup(tokens[1].token, tokens[1].length);
int ret;

if (!user) {
errno = ENOMEM;
return -1;
}

ret = set_output_user(user);
free(user);
return ret == 1 ? 0 : 1;
}

int parse_conf_output_group(const conf_token_t* tokens)
{
char* group = strndup(tokens[1].token, tokens[1].length);
int ret;

if (!group) {
errno = ENOMEM;
return -1;
}

ret = set_output_group(group);
free(group);
return ret == 1 ? 0 : 1;
}

int parse_conf_output_mod(const conf_token_t* tokens)
{
char* mod = strndup(tokens[1].token, tokens[1].length);
int ret;

if (!mod) {
errno = ENOMEM;
return -1;
}

ret = set_output_mod(mod);
free(mod);
return ret == 1 ? 0 : 1;
}

static conf_token_syntax_t _syntax[] = {
{ "interface",
parse_conf_interface,
Expand Down Expand Up @@ -1076,6 +1121,15 @@ static conf_token_syntax_t _syntax[] = {
{ "tld_list",
parse_conf_tld_list,
{ TOKEN_STRING, TOKEN_END } },
{ "output_user",
parse_conf_output_user,
{ TOKEN_STRING, TOKEN_END } },
{ "output_group",
parse_conf_output_group,
{ TOKEN_STRING, TOKEN_END } },
{ "output_mod",
parse_conf_output_mod,
{ TOKEN_NUMBER, TOKEN_END } },

{ 0, 0, { TOKEN_END } }
};
Expand Down
7 changes: 5 additions & 2 deletions src/test/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ CLEANFILES = test*.log test*.trs \
test12.out \
1458044657.tld_list.dist \
tld_list.dat \
dotdoh.dnstap.dist 1643283234.dscdata.xml
dotdoh.dnstap.dist 1643283234.dscdata.xml \
test13.conf

EXTRA_DIST =

TESTS = test1.sh test2.sh test3.sh test4.sh test6.sh test7.sh test8.sh \
test9.sh test10.sh test11.sh test12.sh test_dnstap_unixsock.sh \
test_dnstap_tcp.sh test_pslconv.sh test_encrypted.sh
test_dnstap_tcp.sh test_pslconv.sh test_encrypted.sh test13.sh

if USE_DNSTAP
TESTS += test5.sh
Expand Down Expand Up @@ -76,6 +77,8 @@ test_encrypted.sh: dotdoh.dnstap.dist
dotdoh.dnstap.dist: dotdoh.dnstap
ln -s "$(srcdir)/dotdoh.dnstap" dotdoh.dnstap.dist

test13.sh: 1458044657.pcap.dist 1458044657.tld_list.dist

EXTRA_DIST += $(TESTS) \
1458044657.conf 1458044657.pcap 1458044657.json_gold 1458044657.xml_gold \
pid.conf pid.pcap \
Expand Down
23 changes: 23 additions & 0 deletions src/test/test13.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/sh -xe

rm -f 1458044657.dscdata.json 1458044657.dscdata.xml

rm -f test13.conf
cp "$srcdir/1458044657.conf" test13.conf
echo "output_user `id -nu`;" >>test13.conf
echo "output_group `id -ng`;" >>test13.conf
echo "output_mod 0644;" >>test13.conf

../dsc test13.conf

test -f 1458044657.dscdata.json || sleep 1
test -f 1458044657.dscdata.json || sleep 2
test -f 1458044657.dscdata.json || sleep 3
test -f 1458044657.dscdata.json
test "`stat -c "%a" 1458044657.dscdata.json`" = "644" || test "`perl -e 'printf("%o\n", (stat("1458044657.dscdata.json"))[2])'`" = "100644"

test -f 1458044657.dscdata.xml || sleep 1
test -f 1458044657.dscdata.xml || sleep 2
test -f 1458044657.dscdata.xml || sleep 3
test -f 1458044657.dscdata.xml
test "`stat -c "%a" 1458044657.dscdata.xml`" = "644" || test "`perl -e 'printf("%o\n", (stat("1458044657.dscdata.xml"))[2])'`" = "100644"

0 comments on commit da06317

Please sign in to comment.