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 <[EMAIL 
PROTECTED]>\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 ([EMAIL PROTECTED] || $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 via email to