1#	$OpenBSD: RSyslogd.pm,v 1.7 2019/09/10 22:35:07 bluhm Exp $
2
3# Copyright (c) 2010-2014 Alexander Bluhm <bluhm@openbsd.org>
4#
5# Permission to use, copy, modify, and distribute this software for any
6# purpose with or without fee is hereby granted, provided that the above
7# copyright notice and this permission notice appear in all copies.
8#
9# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
17use strict;
18use warnings;
19
20package RSyslogd;
21use parent 'Proc';
22use Carp;
23use Cwd;
24
25sub new {
26	my $class = shift;
27	my %args = @_;
28	$args{logfile} ||= "rsyslogd.log";
29	$args{up} ||= "calling (select|poll)";
30	$args{down} ||= "Clean shutdown completed";
31	$args{func} = sub { Carp::confess "$class func may not be called" };
32	$args{conffile} ||= "rsyslogd.conf";
33	$args{pidfile} ||= "rsyslogd.pid";
34	$args{outfile} ||= "rsyslogd.out";
35	my $self = Proc::new($class, %args);
36
37	_make_abspath(\$self->{$_}) foreach (qw(conffile pidfile outfile));
38
39	my ($listendomain, $listenproto, $listenaddr, $listenport);
40	if (defined($self->{listendomain})) {
41		$listendomain = $self->{listendomain}
42		    or croak "$class listen domain not given";
43		$listenproto = $self->{listenproto}
44		    or croak "$class listen protocol not given";
45		$listenaddr = $self->{listenaddr}
46		    or croak "$class listen address not given";
47		$listenport = $self->{listenport}
48		    or croak "$class listen port not given";
49	}
50	my ($connectdomain, $connectproto, $connectaddr, $connectport);
51	if (defined($self->{connectdomain})) {
52		$connectdomain = $self->{connectdomain}
53		    or croak "$class connect domain not given";
54		$connectproto = $self->{connectproto}
55		    or croak "$class connect protocol not given";
56		$connectaddr = $self->{connectaddr}
57		    or croak "$class connect address not given";
58		$connectport = $self->{connectport}
59		    or croak "$class connect port not given";
60	}
61
62	open(my $fh, '>', $self->{conffile})
63	    or die ref($self), " create conf file $self->{conffile} failed: $!";
64	if ($listendomain && $listenproto eq "udp") {
65		print $fh "\$ModLoad imudp\n";
66		print $fh "\$UDPServerRun $listenport\n";
67	}
68	if ($listendomain && $listenproto eq "tcp") {
69		print $fh "\$ModLoad imtcp\n";
70		print $fh "\$InputTCPServerRun $listenport\n";
71	}
72	if ($listendomain && $listenproto eq "tls") {
73		print $fh "\$DefaultNetstreamDriver gtls\n";
74		my %cert = (
75		    CA   => "ca.crt",
76		    Cert => "server.crt",
77		    Key  => "server.key",
78		);
79		while(my ($k, $v) = each %cert) {
80			_make_abspath(\$v);
81			print $fh "\$DefaultNetstreamDriver${k}File $v\n";
82		}
83		print $fh "\$ModLoad imtcp\n";
84		print $fh "\$InputTCPServerStreamDriverMode 1\n";
85		print $fh "\$InputTCPServerStreamDriverAuthMode anon\n";
86		print $fh "\$InputTCPServerRun $listenport\n";
87	}
88	if ($connectdomain && $connectproto eq "udp") {
89		print $fh "*.*\t\@$connectaddr:$connectport\n";
90	}
91	if ($connectdomain && $connectproto eq "tcp") {
92		print $fh "*.*\t\@\@$connectaddr:$connectport\n";
93	}
94	if ($connectdomain && $connectproto eq "tls") {
95		print $fh "\$DefaultNetstreamDriver gtls\n";
96		my %cert = (
97		    CA   => "127.0.0.1.crt",
98		);
99		while(my ($k, $v) = each %cert) {
100			_make_abspath(\$v);
101			print $fh "\$DefaultNetstreamDriver${k}File $v\n";
102		}
103		print $fh "\$ActionSendStreamDriverAuthMode x509/name\n";
104		print $fh "\$ActionSendStreamDriverPermittedPeer 127.0.0.1\n";
105		print $fh "\$ActionSendStreamDriverMode 1\n";
106		print $fh "*.*\t\@\@$connectaddr:$connectport\n";
107	}
108	print $fh "*.*\t$self->{outfile}\n";
109	print $fh $self->{conf} if $self->{conf};
110	close $fh;
111
112	unlink($self->{outfile});
113	return $self;
114}
115
116sub child {
117	my $self = shift;
118	my @sudo = $ENV{SUDO} ? $ENV{SUDO} : "env";
119
120	my @pkill = (@sudo, "pkill", "-KILL", "-x", "rsyslogd");
121	my @pgrep = ("pgrep", "-x", "rsyslogd");
122	system(@pkill) && $? != 256
123	    and die ref($self), " system '@pkill' failed: $?";
124	while ($? == 0) {
125		print STDERR "rsyslogd still running\n";
126		system(@pgrep) && $? != 256
127		    and die ref($self), " system '@pgrep' failed: $?";
128	}
129	print STDERR "rsyslogd not running\n";
130
131	my @cmd = ("rsyslogd", "-dn", "-f", $self->{conffile},
132	    "-i", $self->{pidfile});
133	print STDERR "execute: @cmd\n";
134	exec @cmd;
135	die ref($self), " exec '@cmd' failed: $!";
136}
137
138sub _make_abspath {
139	my $file = ref($_[0]) ? ${$_[0]} : $_[0];
140	if (substr($file, 0, 1) ne "/") {
141		$file = getcwd(). "/". $file;
142		${$_[0]} = $file if ref($_[0]);
143	}
144	return $file;
145}
146
147sub down {
148	my $self = shift;
149
150	$self->kill();
151	return Proc::down($self);
152}
153
1541;
155