[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Status of inetd for etch



On Fri, Aug 11, 2006 at 12:46:44AM +0200, Adam Borowski wrote:
> Now, let's see what depends on *-inetd:
>   Depends:
>     netbase

Hence, everything that wants an inetd can just Depend: on netbase, rather
than specifying it explicitly, so your list is incomplete:

>     lukemftpd
>     wipl-client-java
>     pawserv
>     bitlbee
>     micro-httpd
>     wipl-client-inetd
>     ltsp-server
>     noffle
>   Recommends:
>     atftpd
>   Suggests:
>     micro-proxy
>     education-main-server

The non-broken way to fix this is to have:

	Package: net-common

	Package: openbsd-inetd
	Provides: internet-superserver

	Package: foo
	Depends: net-common, internet-superserver

	Package: netbase
	Priority: extra
	Depends: net-common, internet-superserver

and rebuild packages that currently depend on netbase, to instead depend
on "net-common" or "net-common, internet-superserver" depending on whether
they use an inetd or not. netbase should also ensure "update-inetd" supports
the current syntax, so packages don't break.

The reason that hasn't happened is because people (including myself)
have been hoping to introduce a new update-inetd with a syntax that
doesn't suck at the same time as introducing the internet-superserver
virtual package so that packages only need to be changed once.

It's not really that hard, but no one's bothered finishing it off. My last
attempt's attached. Consider it GPL v2 or later'ed.

Cheers,
aj

#!/usr/bin/perl -w

use strict;

package UpdateInetd;

###########

# service object:
#      service
#      type
#      protocol
#      executable
#      arguments
#      netgroup
#      tcpd
#      group
#      user
#      wait
#      disable

sub service2inetd($) {
	my %serv = %{$_[0]};

	my ($dm, $d, $s, $t, $p, $w, $u, $tcpd, $c, $a) = (
		$serv{"disabled_man"} ? "#" : "",
		join("", map { "#<$_>" } @{$serv{"disabled"}}),
		$serv{"service"},
		$serv{"type"},
		$serv{"protocol"},
		$serv{"wait"},
		$serv{"user"} . 
			(defined $serv{"group"} ? "." . $serv{"group"} : ""),
		defined($serv{"tcpd"}) ? "/usr/sbin/tcpd" : $serv{"command"},
		$serv{"command"},
		$serv{"arguments"},
	);

	$d .= " " if ($d ne "");

	if ($tcpd eq $c) {
		$c =~ s,^.*/,,;
	}

	if ($c eq "internal") {
		return "$dm$d$s\t$t\t$p\t$w\t$u\t$c";
	} else {
		return "$dm$d$s\t$t\t$p\t$w\t$u\t$tcpd\t$c $a";
	}
}

sub inetd2service($) {
	my $line = $_[0];
	
        # a service matches:
	# #                                 ^(#?)                       $1
        # #<disabled-upgrade>#<removed>#    ((#<\S+>)+#?)?              $2
        # mountd/1                          (\S+)           \s+         $4
        # dgram                             (dgram|stream)  \s+         $5
        # rpc/udp                           (\S+)           \s+         $6
        # wait                              (wait|nowait(\.\d+)?)\s+    $7
        # root                              (\S+)           \s+         $9
        # /usr/sbin/rpc.mountd              (\S+)                      $10
        # /usr/sbin/rpc.mountd              (\s+(\S+))?                $12
        #                                   (\s+(\S.*))?               $14

        if ($line =~ m/^(#?)((#<\S+>\s*)+#?\s*)?([^#<\s]\S*)\s+(dgram|stream)\s+(\S+)\s+(wait|nowait(\.\d+)?)\s+(\S+)\s+(\S+)(\s+(\S+))?(\s+(\S.*))?\s*$/) {
		my %results = (
			'disabled_man' => $1 eq "#",
			'disabled' => $2 || "",
			'service' => $4,
			'type' => $5,
			'protocol' => $6,
			'wait' => $7,
			'user' => $9,
			'command' => $10,
			'command2' => $12 || "",
			'arguments' => $14 || "",
			'tcpd' => undef,
			'group' => undef,
		);

		$results{"disabled"} = 
			[ map { $1 if (m/<(.*)>/); } (grep /<.*>/, (split /#+/,
				$results{"disabled"})) ];

		if ($results{"user"} =~ m/^(.*)[:.](.*)$/) {
			$results{"user"} = $1;
			$results{"group"} = $2;
		}
                if ($results{"command"} eq "/usr/sbin/tcpd") {
			$results{"tcpd"} = 1;
			$results{"command"} = $results{"command2"};
                }
		delete $results{"command2"};
                return \%results
	}
	return undef;
}

sub matchserv($$$;$$) {
	my ($serv, $s,$p,$c,$r) = @_;
	return 0 unless 
		($s eq $serv->{"service"}) 
			&& ($p eq $serv->{"protocol"}) 
			&& (!defined $c || $c eq $serv->{"command"});
	if (defined $r) {
		my $k = 0;
		foreach my $d (@{$serv->{disabled}}) {
			$k = 1 if $d eq $r;
		}
		return 0 unless $k;
	} else {
		return 0 if grep /^rm-/, @{$serv->{disabled}};
	}
	return 1;	
}

############

sub scaninetdconf {
	my ($servfn, $ngfn) = @_;
	my $netgroup = undef;

	$ngfn = sub { return $_[1]; } unless defined $ngfn;

	open(INETD_CONF, "</etc/inetd.conf") 
		or die "Couldn't open inetd.conf: $!\n";

	while(my $line = <INETD_CONF>) {
		chomp($line);

		if ($line =~ m/^#:([^\s:]+):\s*(.*)$/) {
			$netgroup = $1;
			$line = &$ngfn($netgroup, $line);
		} elsif (my $x = inetd2service($line)) {
			$line = &$servfn($netgroup, $x, $line);
		}
		print "$line\n" unless ($line eq "");
	}

	close(INETD_CONF);
}
	

############

sub disable($$$$) {
	my ($srv, $prot, $exec, $reason) = @_;
	my $foundit = 0;

	scaninetdconf( sub {
		my ($ng, $x, $l) = @_;
		if (matchserv($x, $srv, $prot, $exec)) {
			$foundit = 1;
			if ($reason eq "") {
				$x->{"disabled_man"} = 1;
			} else {
				push @{$x->{"disabled"}}, $reason;
			}
			$l = service2inetd($x);
		}
		return $l;
	} );

	if (!$foundit) {
		die "Error: service not found\n";
	}
}

sub enable($$$$) {
	my ($srv, $prot, $exec, $r) = @_;
	my $foundit = 0;

	scaninetdconf( sub {
		my ($ng, $x, $l) = @_;
		if (defined $r && matchserv($x, $srv, $prot, $exec, $r)) {
			$x->{"disabled"} = 
				[ grep !/^\Q$r\E$/, @{$x->{"disabled"}} ];
			$l = service2inetd($x);
			$foundit = 1;
		} elsif (!defined $r && matchserv($x, $srv, $prot, $exec)) {
			$x->{"disabled_man"} = 1;
			$l = service2inetd($x);
			$foundit = 1;
		}
		return $l;
	} );

	if (!$foundit) {
		die "Error: service not found\n";
	}
}

sub add($) {
	my ($serv) = @_;

	scaninetdconf( sub {
		my ($ng, $x, $l) = @_; return $l;
	}, sub {
		my ($ng, $l) = @_;
		$l .= "\n" . service2inetd($serv) 
			if ($ng eq $serv->{"netgroup"});
		return $l;
	} );
}

sub delete($) {
	my ($srv, $prot, $exec, $reason) = @_;
	my $foundit = 0;

	scaninetdconf( sub {
		my ($ng, $x, $l) = @_;
		if (matchserv($x, $srv, $prot, $exec, $reason)) {
			$foundit = 1;
			$l = "";
		}
		return $l;
	} );

	if (!$foundit) {
		die "Error: service not found\n";
	}
}

1;
#!/usr/bin/perl -w

use strict;
use Getopt::Long;

unless (eval 'require "./update-inetd-module"') {
	print "No internet superserver installed...\n";
	exit(1);
}

my $oldui = "/usr/sbin/update-inetd.netbase";
$oldui = undef unless -x $oldui;

my $firstword = "";
if ($#ARGV >= 0) {
	$firstword = shift @ARGV;
}

if ($firstword eq "") {
	print "Try --help.\n";
} elsif ($firstword eq "add") {
	# update-inetd add <service> <proto> <executable> <arguments..> 
	#                  [--netgroup=<group>] [--user=<user>[:<group>]] 
	#                  [--wait|--nowait[=<n>]] [--tcpd]
	#                  [--disable[=<reason>]] [--type=stream|dgram]

	my %optctl = ();
	GetOptions (\%optctl, qw(netgroup=s user=s wait nowait:i
		           type=s tcpd disable:s)) or exit(1);
	my ($service, $proto, $exec, @args) = @ARGV;

	if (defined $optctl{"wait"} && defined $optctl{"nowait"}) {
		print STDERR "Can't combine wait and nowait options\n";
		exit(1);
	}
	if (defined $optctl{"wait"}) {
		$optctl{"wait"} = "wait";
	} elsif (defined $optctl{"nowait"}) {
		$optctl{"wait"} = "nowait";
		delete $optctl{"nowait"};
	}

	#foreach my $k (sort keys %optctl) {
	#	print "$k : $optctl{$k}\n";
	#}

	if ($proto eq "tcp") {
		$optctl{"type"} = "stream" unless (defined $optctl{"type"});
		$optctl{"wait"} = "nowait" unless (defined $optctl{"wait"});
	} elsif ($proto eq "udp") {
		$optctl{"type"} = "dgram" unless (defined $optctl{"type"});
		$optctl{"wait"} = "wait" unless (defined $optctl{"wait"});
	}

	my %serv = (
		'service' => $service,
		'protocol' => $proto,
		'command' => $exec,
		'arguments' => join(" ", @args),
		'type' => $optctl{"type"},
		'wait' => $optctl{"wait"},
		'tcpd' => $optctl{"tcpd"},
		'user' => $optctl{"user"},
		'group' => undef,
		'netgroup' => uc($optctl{"netgroup"}) || "OTHER",
		'disabled_man' => 0,
		'disabled' => [],
	);

	if (defined $optctl{"disable"}) {
		$serv{"disabled"} = [ $optctl{"disable"} ];
	}

	if ($serv{"user"} =~ m/^(.*):(.*)$/) {
		$serv{"user"} = $1;
		$serv{"group"} = $2;
	}

	UpdateInetd::add(\%serv);

} elsif ($firstword eq "remove") {

	# update-inetd remove <service> <proto> <executable> <rm-reason>
	# (must already be disabled for reason <rm-reason>
	if (@ARGV != 4) {
		print STDERR "Bad arguments\n";
		exit(1);
	}
	my ($service, $proto, $exec, $reason) = @ARGV;
	if ($reason !~ m/^rm-/) {
		print STDERR "Service must be disable for a rm- reason before removing\n";
		exit (1);
	}
	UpdateInetd::remove($service, $proto, $exec, $reason);
} elsif ($firstword eq "disable") {
	# update-inetd disable <service> <proto> <executable> [<reason>]
	if (@ARGV != 3 && @ARGV != 4) {
		print STDERR "Bad arguments\n";
		exit(1);
	}
	my ($service, $proto, $exec, $reason) = @ARGV;
	$reason = "" unless defined $reason;
	UpdateInetd::disable($service, $proto, $exec, $reason);
} elsif ($firstword eq "enable") {
	# update-inetd enable <service> <proto> <executable> [<reason>]
	if (@ARGV != 3 && @ARGV != 4) {
		print STDERR "Bad arguments\n";
		exit(1);
	}
	my ($service, $proto, $exec, $reason) = @ARGV;
	$reason = "" unless defined $reason;
	UpdateInetd::enable($service, $proto, $exec, $reason);
} elsif ($firstword eq "--help") {
	print "update-inetd -- Copyright (c) 2003 Anthony Towns <ajt\@debian.org>\n";
	print "\n";
	print "update-inetd add <service> <proto> <executable> <arguments..>\n";
	print "                 [--netgroup=<group>] [--user=<user>[:<group>]]\n";
	print "                 [--wait|--nowait[=<n>]] [--tcpd]\n";
	print "                 [--disable[=<reason>]] [--type=stream|dgram]\n";
	print "\n";
	print "update-inetd remove <service> <proto> <executable> <reason>\n";
	print "  (must already be disabled for reason <reason>)\n";
	print "\n";
	print "update-inetd disable <service> <proto> <executable> [<reason>]\n";
	print "\n";
	print "update-inetd enable <service> <proto> <executable> [<reason>]\n";
	print "\n";
} elsif (defined $oldui && $firstword eq "--old-help") {
	exec $oldui, "--help";
	die "Couldn't execute /usr/sbin/update-inetd.netbase";
} elsif (defined $oldui) {
	unshift @ARGV, $firstword unless ($firstword eq "");
	# old style
	exec $oldui, @ARGV;
	die "Couldn't execute /usr/sbin/update-inetd.netbase";
} else {
	print "Unknown argument\n";
	exit(1);
}
#!/usr/bin/perl -w
use strict;

package AJDebianNet;

# Not really a module yet

# okay, so:

# All entries matching a particular (serv,prot,command) should have
# a unique remove-* reason for being disabled, except for at most one entry.
# All entries matching a particular (serv,prot) should be disabled, except
# for at most one.

my $FILE = "/etc/inetd.conf";

open INETDCONF, "<$FILE" or die "Couldn't open $FILE: $!\n";

my $group = "OTHER";
sub read_entry {
	my $line = <INETDCONF>;
	if (!defined $line) {
		close INETDCONF;
		return ();
	}

	chomp($line);
	
	if ($line =~ m/^#:([^\s:]+):\s*(.*)$/) {
		$group = $1;
		return ($line);
	}
	
	# a service matches:
	# ##<disabled-upgrade>#<removed>    ^\s*((#(<\S+>)?\s*)+)?      $1
	# mountd/1                          (\S+)           \s+         $4
	# dgram                             (dgram|stream)  \s+         $5
	# rpc/udp                           (\S+)           \s+         $6
	# wait                              (wait|nowait(\.\d+)?)\s+    $7
	# root                              (\S+)           \s+         $9
	# /usr/sbin/rpc.mountd              (\S+)                      $10
	# /usr/sbin/rpc.mountd              (\s+(\S+))?                $12
	#                                   (\s+(\S.*))?               $14

	if ($line =~ m/^((#(<\S+>)?\s*)+)?([^#\s]\S*)\s+(dgram|stream)\s+(\S+)\s+(wait|nowait(\.\d+)?)\s+(\S+)\s+(\S+)(\s+(\S+))?(\s+(\S.*))?\s*$/) {
		my @hints = ();
		my @result = ($1, $4, $5, $6, $7, $9, $10, $12, $14);
		return ($line) if ($result[6] eq "internal");
		if ($result[6] eq "/usr/sbin/tcpd") {
			push @hints, "tcpd";
			splice @result, 6, 1, ();
		} else {
			splice @result, 7, 1, ();
		}
		return ($line, $group, @result, @hints);
	}

	return ($line); 
}

sub reasoncmp {
	my ($A, $B) = ($a =~ m/^remove-/, $b =~ m/^remove-/);
	if ($A xor $B) {
		return 1 if ($A);
		return -1 if ($B);
	} else {
		return $a cmp $b;
	}
}

sub disablereasons {
	my $disa = shift;
	my %reasons = ();

	while (defined $disa && $disa =~ m/^#(<(\S+)>)?\s*/) {
		$disa = $';
		if (defined $2) {
			$reasons{$2} = 1;
		} else {
			$reasons{""} = 1;
		}
	}
	return sort reasoncmp keys %reasons;
}

my @newinetd = ();
sub printinetd {
	my $line = shift;
	push @newinetd, $line;
	return if ($line =~ m/^\s*$/ || $line =~ m/^\s*#/);
	return if ($line =~ m/^((#(<\S+>)?\s*)+)?([^#\s]\S*)\s+(dgram|stream)\s+(\S+)\s+(wait|nowait(\.\d+)?)\s+(\S+)\s+(\S+)(\s+(\S+))?(\s+(\S.*))?\s*$/);
	die "internal error: tried to write incomprehensible line.\nline was " . scalar(@newinetd) . ": $line\n";
}

sub add {
# add: mustn't be any other enabled (serv,prot),
#      mustn't be any other (serv,prot,command) without a remove-* reason
	my $s = $_[0];
	my $p = $_[1];
	my $c = $_[2];
	my $a = join(" ", @{$_[3]});
	my %optctl = %{$_[4]};

	my @line;
	my $g = $optctl{"netgroup"} || "OTHER";
	my $t = ($p eq "tcp" ? "stream" : "dgram");
	my $w = ($p eq "tcp" ? "nowait" : "wait");;
	if (defined $optctl{"wait"}) {
		$w = "wait";
	} elsif (defined $optctl{"nowait"}) {
		$w = "nowait";
		$w .= "." . $optctl{"nowait"} if ($optctl{"nowait"} > 0);
	}
	my $u = $optctl{"user"} || "root";
	my $tcpd;
	if (grep { m/^tcpd$/ } @{$optctl{"hint"}}) {
		$tcpd = "/usr/sbin/tcpd";
	} else {
		$tcpd = $c;
	}
	my $cnt = 0;
	my $d = "";
	if (defined $optctl{"disable"}) {
		if ($optctl{"disable"} eq "") {
			$d = "#";
		} else {
			$d = "#<" . $optctl{"disable"} . ">";
		}
	}
	while (@line = read_entry) {
		my ($line,$group,$disa,$serv,$type,$prot,$wait,
			$user,$arg0,$args,@hints) = @line;

		if (@line == 1) { printinetd("$line"); next; }

		my @reasons = disablereasons($disa);
		if ($serv eq $s && $prot eq $p && @reasons == 0) {
			die "Service already active!\n";
		}
		if ($serv eq $s && $prot eq $p && $arg0 eq $c) {
			my @remove = grep {m/^remove-/} @reasons;
			if (@remove == 0) {
				die "Duplicate service/command!\n";
			}
		}

		if (defined $g && $group eq $g) {
			printinetd("$d$s\t$t\t$p\t$w\t$u\t$tcpd\t$c $a");
			$g = undef;
		}
		printinetd("$line");
	}
	if (defined $g) {
		printinetd("#:$g:");
		printinetd("$d$s\t$t\t$p\t$w\troot\t$c\t$c $a");
	}

	foreach my $l (@newinetd) {
		print "$l\n";
	}
}

sub remove {
# remove: must be an entry (serv,prot,command,reason)
	my ($s,$p,$c,$r) = @_;
	my @line;
	my $cnt = 0;
	while (@line = read_entry) {
		my ($line,$group,$disa,$serv,$type,$prot,$wait,
			$user,$arg0,$args,@hints) = @line;

		if (@line == 1) {
			printinetd($line);
			next;
		}

		if ($serv eq $s && $prot eq $p && $arg0 eq $c) {
			my %reasons = map {($_,1)} disablereasons($disa);
			my @remove = grep {m/^remove-/} keys %reasons;
			if (!@remove || $remove[0] ne $r) {
				printinetd($line);
			} elsif ($cnt > 0) {
				die "Multiple services of that description!!";
			} else {
				# nothing -- remove that line
				$cnt++;
			}
		} else {
			printinetd($line);
		}
	}
	die "Didn't remove anything!" if ($cnt == 0);

	foreach my $l (@newinetd) {
		print "$l\n";
	}
}


sub enable {
# enable: "must" be an entry (serv,prot,command,reason)
#         mustn't be an enabled (serv,prot)
#         if remove-*, mustn't be an non-remove-* (serv,prot,command)

	my ($s,$p,$c,$r) = @_;
	my @line;
	my $cnt = 0;
	my $suchaservice = 0;
	my $alreadyenabled = 0;
	while (@line = read_entry) {
		my ($line,$group,$disa,$serv,$type,$prot,$wait,
			$user,$arg0,$args,@hints) = @line;

		if (@line == 1) {
			printinetd($line);
			next;
		}

		if ($serv eq $s && $prot eq $p) {
			my %reasons = map {($_,1)} disablereasons($disa);
			my @remove = grep {m/^remove-/} keys %reasons;

			if (keys %reasons == 0) {
				$alreadyenabled |= 1;
			}

			if ($arg0 eq $c) {
				$suchaservice = 1;
				if (@remove && $r ne $remove[0]) {
					;
				} elsif ($cnt > 0) {
					die "Multiple services of that description!!";
				} elsif (!defined $reasons{$r}) {
					warn "Not disabled for that reason!!";
					$cnt++;
				} else {
					my $x = $line;
					if ($r eq "") {
						$x =~ s/^(\s*(#<[^>]*>\s*)*)#\s*([^<\s])/$1$3/;
					} else {
						$x =~ s/#<$r>\s*//;
					}
					if ($x !~ m/^\s*#/) {
						$alreadyenabled |= 2;
					}
					printinetd($x);
					$cnt++;
					next;
				}
			}
		}
		printinetd($line);
	}
	die "Service already enabled!" if ($alreadyenabled == 3);
	die "No such service!" if ($suchaservice == 0);
	die "No service removed for that reason!"
		if ($cnt == 0 && $r =~ m/^remove-/);
	warn "Didn't enable anything!" if ($cnt == 0); 

	foreach my $l (@newinetd) {
		print "$l\n";
	}
}

sub disable {
# disable: must be an entry (serv,prot,commaand) not disabled for a remove-*
#          if remove-*, mustn't be an exact match (serv,prot,command,reason)
	my @line;
	my ($s,$p,$c,$r) = @_;
	my $cnt = 0;
	while (@line = read_entry) {
		my ($line,$group,$disa,$serv,$type,$prot,$wait,
			$user,$arg0,$args,@hints) = @line;

		if (@line == 1) {
			printinetd($line);
			next;
		}

		if ($serv eq $s && $prot eq $p && $arg0 eq $c) {
			my %reasons = map {($_,1)} disablereasons($disa);
			my @remove = grep {m/^remove-/} keys %reasons;
			if (@remove && $r eq $remove[0]) {
				die "Already removed!!";
			} elsif (@remove) {
				printinetd($line);
			} elsif ($cnt > 0) {
				die "Multiple services of that description!!";
			} elsif (defined $reasons{$r}) {
				die "Already disabled for that reason!!";
			} elsif ($r eq "") {
				printinetd("#$line");
				$cnt++;
			} else {
				printinetd("#<$r>$line");
				$cnt++;
			}
		} else {
			printinetd($line);
		}
	}
	die "Didn't disable anything!" if ($cnt == 0);

	foreach my $l (@newinetd) {
		print "$l\n";
	}
}

sub dump {
	my @line;
	while (@line = read_entry) {
		next if (@line == 1);

		my ($line,$group,$disa,$serv,$type,$prot,$wait,
			$user,$arg0,$args,@hints) = @line;

		print "update-inetd add $serv $prot $arg0";
		print " --netgroup=\"$group\"" if defined $group;
		print " --user=$user";
		if ($type eq "dgram") {
			print " --nowait" if $wait eq "nowait";
			print " --wait" if $wait eq "wait";
			print " --wait=$1" if $wait =~ m/wait.(\d+)/;
		}
		push @hints, "$type";
		print " --hint=" . join(",", @hints) if (@hints);
		print " -- $args" if defined $args;
		print "\n";
		foreach my $reason (disablereasons $disa) {
			print "update-inetd disable $serv $prot $arg0";
			print " --reason=$reason" if $reason ne "";
			print "\n";
		}
	}

	foreach my $l (@newinetd) {
		print "$l\n";
	}
}

1

Attachment: signature.asc
Description: Digital signature


Reply to: