###
###  Copyright 2000-2007 University of Illinois Board of Trustees
###  All rights reserved. 
###
###  TCPWrappers.pm - TCPWrappers module for psgconf
###
###  Campus Information Technologies and Educational Services
###  University of Illinois at Urbana-Champaign
###


package PSGConf::Control::TCPWrappers;

use strict;

use PSGConf::Action::GenerateFile::hosts_allow;
use PSGConf::Action::GenerateFile::Literal;
use PSGConf::Data::Boolean;
use PSGConf::Data::List;
use PSGConf::Data::String;
use PSGConf::Data::Table;
use PSGConf::Control::Packages qw(_add_pkgs);


###############################################################################
###  policy methods
###############################################################################
sub _policy_modify_inetd
{
	my ($self, $psgconf) = @_;
	my ($label, $entry, $inetd, $svc, $proto, @args, $tcpd_path);

	return
		if ($psgconf->data_obj('use_xinetd')->equals('true'));

	$tcpd_path = $psgconf->data_obj('tcpd_path')->get();
	$inetd = $psgconf->data_obj('inetd')->get();

	foreach $label (keys %$inetd)
	{
		$entry = $inetd->{$label};
		($svc, $proto) = split(/\//, $label);

		next
			if ($proto ne 'tcp'
			    || $entry->{server} eq 'internal'
			    || exists($entry->{flags}->{NOLIBWRAP}));

		@args = split(/\s+/, $entry->{server_args});
		shift(@args)
			if (exists($entry->{flags}->{NAMEINARGS}));
		unshift(@args, $entry->{server});
		$entry->{server_args} = join(' ', @args);

		$entry->{server} = $tcpd_path;
		$entry->{flags}->{NAMEINARGS} = undef;
	}
}

sub _policy_add_rfc931_token
{
	my ($self, $psgconf) = @_;
	my ($entry);

	return 
		if ( $psgconf->data_obj('tcp_rfc931_enable')->equals('false') );

	foreach $entry (@{$psgconf->data_obj('tcp_wrappers')->get()})
	{
		# If this is the localhost entry, do not
		# bother with rfc931.
		if ( $entry->[1] !~ /localhost/o ) {
			$entry->[3] = $entry->[2];
			$entry->[2] = 'rfc931';
		}
	}
}

sub _policy_expand_hostname_token
{
	my ($self, $psgconf) = @_;
	my ($entry, $hostname);

	$hostname = $psgconf->data_obj('hostname')->get();

	foreach $entry (@{$psgconf->data_obj('tcp_wrappers')->get()})
	{
		### replace "%h" with hostname in host list
		$entry->[1] =~ s/%h/$hostname/;
	}
}


###############################################################################
###  decide() method
###############################################################################

sub decide
{
	my ($self, $psgconf) = @_;

	return
		if ($psgconf->data_obj('tcp_enable')->equals('false')
			|| ! $psgconf->data_obj('tcp_wrappers')->count());

	$psgconf->register_actions(
		PSGConf::Action::GenerateFile::hosts_allow->new(
			'name'		=> '/etc/hosts.allow',
			'description'	=> 'TCP Wrapper configuration file',
			entries		=> $psgconf->data_obj('tcp_wrappers')->get()
		),
		PSGConf::Action::GenerateFile::Literal->new(
			'name'		=> '/etc/hosts.deny',
			'description'	=> 'TCP Wrapper configuration file',
			content		=> ''
		)
	);
}


###############################################################################
###  Constructor
###############################################################################

sub new
{
	my ($class, $psgconf) = @_;
	my ($self);

	$self = {};
	bless($self, $class);

	### So that _add_pkgs knows which directives to look at
	$self->{name} = 'tcp';
	$self->{enable} = $self->{name} . '_enable';
	$self->{packages} = $self->{name} . '_packages';

	$psgconf->register_data(
		tcpd_path		=> PSGConf::Data::String->new(
						'value_abspath' => 1,
						value => '/usr/local/sbin/tcpd'
					),
		tcp_enable		=> PSGConf::Data::Boolean->new(
						value => 'true'
					),
		tcp_rfc931_enable	=> PSGConf::Data::Boolean->new(
						value => 'false'
					),
		tcp_packages		=> PSGConf::Data::List->new(),
		tcp_wrappers		=> PSGConf::Data::Table->new()
	);

	$psgconf->register_policy($self,
		tcpd_expand_hostname_token => '_policy_expand_hostname_token',
		tcpd_modify_inetd	=> '_policy_modify_inetd',
		tcpd_add_rfc931	=> '_policy_add_rfc931_token',
		tcpd_add_packages   => '_add_pkgs'
	);

	return $self;
}


###############################################################################
###  documentation
###############################################################################

1;

__END__

=head1 NAME

PSGConf::Control::TCPWrappers - psgconf control class for TCP wrappers

=head1 SYNOPSIS

In F<psgconf_modules>:

  Control PSGConf::Control::TCPWrappers

=head1 DESCRIPTION

The B<PSGConf::Control::TCPWrappers> module provides a B<psgconf> control
object for configuring TCP wrappers.  It supports the following methods:

=over 4

=item new()

The constructor.  Its parameter is a reference to the B<PSGConf>
object.  It registers the following data objects:

=over 4

=item I<tcp_enable>

A B<PSGConf::Data::Boolean> object that indicates whether C<tcp_wrappers>
should be configured.

=item I<tcp_packages>

A B<PSGConf::Data::List> object that lists all packages to install.

=item I<tcpd_path>

A B<PSGConf::Data::String> object containing the absolute path to the
C<tcpd> binary.  The default is F</usr/local/sbin/tcpd>. 

=item I<tcp_rfc931_enable>

A B<PSGConf::Data::Boolean> object that indicates whether the
F<rfc931> should be used in F</etc/hosts.allow>.

=item I<tcp_wrappers>

A B<PSGConf::Data::Table> object that contains entries for
F</etc/hosts.allow>.  Each row consists of the following fields: a
space-delimited list of daemons, a space-delimited list of hosts, and
one or more options.

=back

The constructor also registers the following policy methods:

=over 4

=item I<tcpd_expand_hostname_token>

For each entry in the I<tcp_wrappers> data object, in the host field,
the token C<%h> will be replaced with the value of the I<hostname>
data object, which is provided by the B<PSGConf::Control::Core> module.

=item I<tcpd_modify_inetd>

If I<use_xinetd> is disabled, then modify the entries in the I<inetd> data
object (provided by the B<PSGConf::Control::inetd> module) to use
C<tcpd>.  Entries will only be modified if they specify the C<tcp>
protocol, do not have the I<server> attribute set to C<internal>, and do
not have the I<NOLIBWRAP> flag set.

=item I<tcpd_add_rfc931>

If I<tcp_rfc931_enable> is set, then add the token I<rfc931> to all entries
to the I<tcp_wrappers> table.

=back

=item decide()

If the I<tcp_wrappers> data object is defined, it registers
a B<PSGConf::Action::GenerateFile::hosts_allow> action
object to create F</etc/hosts.allow>.  Also registers a
B<PSGConf::Action::GenerateFile::Literal> action object to create the
F</etc/hosts.deny> file (which will be an empty file).

=back

=head1 SEE ALSO

L<perl>

hosts_options(5)

L<PSGConf>

L<PSGConf::Action::GenerateFile::hosts_allow>

L<PSGConf::Action::GenerateFile::Literal>

L<PSGConf::Control::Core>

L<PSGConf::Control::inetd>

L<PSGConf::Control::Packages>

L<PSGConf::Data::Boolean>

L<PSGConf::Data::List>

L<PSGConf::Data::String>

L<PSGConf::Data::Table>

L<psgconf-intro>

=cut



syntax highlighted by Code2HTML, v. 0.9.1