Package: netbase Version: 4.19 Severity: critical Tags: patch Justification: causes serious data loss
When I upgrade ipopd an unrelated (custom-made) entry in my inetd.conf
is being deleted. The entry is
pop3 stream tcp nowait nobody /usr/sbin/tcpd /usr/sbin/stunnel -c -r
mail.argon.org:995
and it gets deleted when ipopd.postrm runs
update-inetd --remove pop3s
due to a bug in DebianNet. In tracing this down I found and fixed these
problems in DebianNet.pm:
- add_service(), remove_service(), and scan_entries() weren't properly
anchoring the service search, so they could all match where they
shouldn't have.
- There's no need to set the umask before doing a chmod() because
chmod() isn't affected by the umask. Additionally, leaving the
process with a 0 umask is not safe. I fixed this by removing the
umask() call. (A better fix would be to locally set a umask
before calling open() and not do the chmod() at all, but I wanted
to keep my changes minimal.)
- The module causes some use of initialized value warnings.
Here's a demonstration of all these problems, and my fix for them.
After that is the patch. I'll also attach these files so you can get
at them without having to cut/paste them out of the main part of this
message.
-------------------------------------------------------------------------------
$ cat do-test
#!/usr/bin/perl -w
use strict;
use DebianNet ();
print "using $INC{'DebianNet.pm'}\n";
$DebianNet::inetdcf = "test.conf";
$DebianNet::verbose = 1;
my $base = "stream tcp nowait nobody file cmd";
# There's no need for DebianNet to set the umask because it doesn't affect
# chmod. (Really it should be setting umask() before the open() instead
# of doing the chmod(), but I wanted to keep my changes minimal.)
umask 0777;
print "various uninit warnings\n";
DebianNet::add_service "warn-add $base";
DebianNet::enable_service "warn-enable";
DebianNet::disable_service "warn-disable";
DebianNet::remove_service "warn-rm";
print "scan_entries() doesn't properly anchor search\n";
DebianNet::disable_service "test-scan";
print "add_service() doesn't properly anchor search\n";
DebianNet::add_service("test-add $base", "TEST");
print "remove_service() doesn't properly anchor search\n";
DebianNet::remove_service("arg");
$ cat test.conf.orig
#:TEST:
#<off># warn-enable stream tcp nowait nobody file cmd
warn-disable stream tcp nowait nobody file cmd
warn-rm stream tcp nowait nobody file cmd
# This shouldn't be seen by add_service() because the #<off># isn't at
# the start of the line.
# x #<off># test-add stream tcp nowait nobody file cmd
# This shouldn't be removed by remove_service("arg").
test-rm stream tcp nowait nobody file cmd arg
# These shouldn't be found by scan_entries('test-scan').
test-scan-1 stream tcp nowait nobody file cmd arg
test-scan-2 stream tcp nowait nobody file cmd arg
$ cp test.conf.orig test.conf; \
perl do-test; \
diff -u test.conf.orig test.conf
using /usr/share/perl5/DebianNet.pm
various uninit warnings
Use of uninitialized value in scalar chomp at /usr/share/perl5/DebianNet.pm
line 25.
Processing service `warn-add' ... added
Use of uninitialized value in regexp compilation at
/usr/share/perl5/DebianNet.pm line 199, <ICREAD> line 3.
Processing service `warn-enable' ... enabled
Use of uninitialized value in regexp compilation at
/usr/share/perl5/DebianNet.pm line 236, <ICREAD> line 4.
Use of uninitialized value in regexp compilation at
/usr/share/perl5/DebianNet.pm line 174, <ICREAD> line 4.
Processing service `warn-disable' ... disabled
Use of uninitialized value in regexp compilation at
/usr/share/perl5/DebianNet.pm line 236, <ICREAD> line 5.
Removing line: `warn-rm stream tcp nowait nobody file cmd'
scan_entries() doesn't properly anchor search
Use of uninitialized value in regexp compilation at
/usr/share/perl5/DebianNet.pm line 236, <ICREAD> line 17.
Use of uninitialized value in regexp compilation at
/usr/share/perl5/DebianNet.pm line 236, <ICREAD> line 18.
WARNING!!!!!! test.conf contains multiple entries for
the `test-scan' service. You're about to disable these entries.
Do you want to continue? [n]
Ok, I'll stop ...
add_service() doesn't properly anchor search
remove_service() doesn't properly anchor search
Removing line: `# This shouldn't be removed by remove_service("arg").'
Removing line: `test-rm stream tcp nowait nobody file cmd arg'
Removing line: `test-scan-1 stream tcp nowait nobody file cmd arg'
Removing line: `test-scan-2 stream tcp nowait nobody file cmd arg'
--- test.conf.orig 2005-02-24 12:21:19.000000000 -0500
+++ test.conf 2005-02-24 12:39:51.000000000 -0500
@@ -1,19 +1,15 @@
#:TEST:
-#<off># warn-enable stream tcp nowait nobody file cmd
-warn-disable stream tcp nowait nobody file cmd
-warn-rm stream tcp nowait nobody file cmd
+warn-enable stream tcp nowait nobody file cmd
+#<off># warn-disable stream tcp nowait nobody file cmd
# This shouldn't be seen by add_service() because the #<off># isn't at
# the start of the line.
# x #<off># test-add stream tcp nowait nobody file cmd
-# This shouldn't be removed by remove_service("arg").
-test-rm stream tcp nowait nobody file cmd arg
# These shouldn't be found by scan_entries('test-scan').
-test-scan-1 stream tcp nowait nobody file cmd arg
-test-scan-2 stream tcp nowait nobody file cmd arg
+warn-add stream tcp nowait nobody file cmd
$ cp test.conf.orig test.conf; \
perl -I. do-test; \
diff -u test.conf.orig test.conf
using DebianNet.pm
various uninit warnings
Processing service `warn-add' ... added
Processing service `warn-enable' ... enabled
Processing service `warn-disable' ... disabled
Removing line: `warn-rm stream tcp nowait nobody file cmd'
scan_entries() doesn't properly anchor search
add_service() doesn't properly anchor search
Processing service `test-add' ... added
remove_service() doesn't properly anchor search
--- test.conf.orig 2005-02-24 12:21:19.000000000 -0500
+++ test.conf 2005-02-24 12:39:57.000000000 -0500
@@ -1,8 +1,8 @@
#:TEST:
+test-add stream tcp nowait nobody file cmd
-#<off># warn-enable stream tcp nowait nobody file cmd
-warn-disable stream tcp nowait nobody file cmd
-warn-rm stream tcp nowait nobody file cmd
+warn-enable stream tcp nowait nobody file cmd
+#<off># warn-disable stream tcp nowait nobody file cmd
# This shouldn't be seen by add_service() because the #<off># isn't at
# the start of the line.
@@ -17,3 +17,4 @@
test-scan-1 stream tcp nowait nobody file cmd arg
test-scan-2 stream tcp nowait nobody file cmd arg
+warn-add stream tcp nowait nobody file cmd
$ _
-------------------------------------------------------------------------------
--- /usr/share/perl5/DebianNet.pm 2004-10-31 11:29:34.000000000 -0500
+++ DebianNet.pm 2005-02-24 12:16:13.000000000 -0500
@@ -22,8 +22,12 @@
local($newentry, $group) = @_;
local($service, $searchentry, @inetd, $inetdconf, $found, $success);
unless (defined($newentry)) { return(-1) };
- chomp($newentry); chomp($group);
- $group = "OTHER" unless (defined($group));
+ chomp($newentry);
+ if (defined $group) {
+ chomp $group;
+ } else {
+ $group = "OTHER";
+ }
$group =~ tr/a-z/A-Z/;
$newentry =~ s/\\t/\t/g;
($service = $newentry) =~ s/(\W*\w+)\s+.*/$1/;
@@ -41,7 +45,7 @@
if (open(INETDCONF,"$inetdcf")) {
@inetd=<INETDCONF>;
close(INETDCONF);
- if (grep(m/$sep$sservice\s+/,@inetd)) {
+ if (grep(m/^$sep$sservice\s+/,@inetd)) {
&enable_service($sservice);
} else {
if (grep(m/^$sservice\s+/,@inetd)) {
@@ -84,7 +88,7 @@
rename("$inetdcf.new","$inetdcf") ||
die "Error installing new $inetdcf: $!\n";
- umask(000); chmod(0644, "$inetdcf");
+ chmod(0644, "$inetdcf");
&wakeup_inetd;
}
@@ -131,7 +135,7 @@
open(ICREAD, "$inetdcf");
RLOOP: while(<ICREAD>) {
chomp;
- unless (/$service\b/) {
+ unless (/^$service\s+/) {
print ICWRITE "$_\n";
} else {
&printv("Removing line: \`$_'\n");
@@ -142,7 +146,7 @@
rename("$inetdcf.new", "$inetdcf") ||
die "Error installing new $inetdcf: $!\n";
- umask(000); chmod(0644, "$inetdcf");
+ chmod(0644, "$inetdcf");
&wakeup_inetd;
return(1);
@@ -151,6 +155,7 @@
sub disable_service {
my($service, $pattern) = @_;
unless (defined($service)) { return(-1) };
+ unless (defined($pattern)) { $pattern = ''; }
chomp($service);
if ((&scan_entries("$service", $pattern) > 1) and (not defined($multi))) {
@@ -182,7 +187,7 @@
rename("$inetdcf.new","$inetdcf") ||
die "Error installing new $inetdcf: $!\n";
- umask(000); chmod(0644, "$inetdcf");
+ chmod(0644, "$inetdcf");
&wakeup_inetd;
return(1);
@@ -191,6 +196,7 @@
sub enable_service {
my($service, $pattern) = @_;
unless (defined($service)) { return(-1) };
+ unless (defined($pattern)) { $pattern = ''; }
chomp($service);
open(ICWRITE, ">$inetdcf.new") || die "Error creating new $inetdcf: $!\n";
open(ICREAD, "$inetdcf");
@@ -207,7 +213,7 @@
rename("$inetdcf.new","$inetdcf") ||
die "Error installing new $inetdcf: $!\n";
- umask(000); chmod(0644, "$inetdcf");
+ chmod(0644, "$inetdcf");
&wakeup_inetd;
return(1);
@@ -229,11 +235,12 @@
sub scan_entries {
my ($service, $pattern) = @_;
+ unless (defined($pattern)) { $pattern = ''; }
my $counter = 0;
open(ICREAD, "$inetdcf");
SLOOP: while (<ICREAD>) {
- $counter++ if (/^$service\b/ and /$pattern/);
+ $counter++ if (/^$service\s+/ and /$pattern/);
}
close(ICREAD);
return($counter);
-------------------------------------------------------------------------------
-- System Information:
Debian Release: 3.1
APT prefers testing
APT policy: (900, 'testing'), (700, 'unstable')
Architecture: i386 (i686)
Kernel: Linux 2.6.8-jones.1
Locale: LANG=en_US, LC_CTYPE=en_US (charmap=ISO-8859-1)
Versions of packages netbase depends on:
ii debconf 1.4.30.11 Debian configuration management sy
ii ifupdown 0.6.4-4.10 High level tools to configure netw
ii netkit-inetd 0.10-10 The Internet Superserver
ii netkit-ping [ping] 0.10-10 The ping utility from netkit
ii tcpd 7.6.dbs-6 Wietse Venema's TCP wrapper utilit
-- debconf information excluded
--
Roderick Schertler
[EMAIL PROTECTED]
--- /usr/share/perl5/DebianNet.pm 2004-10-31 11:29:34.000000000 -0500
+++ DebianNet.pm 2005-02-24 12:16:13.000000000 -0500
@@ -22,8 +22,12 @@
local($newentry, $group) = @_;
local($service, $searchentry, @inetd, $inetdconf, $found, $success);
unless (defined($newentry)) { return(-1) };
- chomp($newentry); chomp($group);
- $group = "OTHER" unless (defined($group));
+ chomp($newentry);
+ if (defined $group) {
+ chomp $group;
+ } else {
+ $group = "OTHER";
+ }
$group =~ tr/a-z/A-Z/;
$newentry =~ s/\\t/\t/g;
($service = $newentry) =~ s/(\W*\w+)\s+.*/$1/;
@@ -41,7 +45,7 @@
if (open(INETDCONF,"$inetdcf")) {
@inetd=<INETDCONF>;
close(INETDCONF);
- if (grep(m/$sep$sservice\s+/,@inetd)) {
+ if (grep(m/^$sep$sservice\s+/,@inetd)) {
&enable_service($sservice);
} else {
if (grep(m/^$sservice\s+/,@inetd)) {
@@ -84,7 +88,7 @@
rename("$inetdcf.new","$inetdcf") ||
die "Error installing new $inetdcf: $!\n";
- umask(000); chmod(0644, "$inetdcf");
+ chmod(0644, "$inetdcf");
&wakeup_inetd;
}
@@ -131,7 +135,7 @@
open(ICREAD, "$inetdcf");
RLOOP: while(<ICREAD>) {
chomp;
- unless (/$service\b/) {
+ unless (/^$service\s+/) {
print ICWRITE "$_\n";
} else {
&printv("Removing line: \`$_'\n");
@@ -142,7 +146,7 @@
rename("$inetdcf.new", "$inetdcf") ||
die "Error installing new $inetdcf: $!\n";
- umask(000); chmod(0644, "$inetdcf");
+ chmod(0644, "$inetdcf");
&wakeup_inetd;
return(1);
@@ -151,6 +155,7 @@
sub disable_service {
my($service, $pattern) = @_;
unless (defined($service)) { return(-1) };
+ unless (defined($pattern)) { $pattern = ''; }
chomp($service);
if ((&scan_entries("$service", $pattern) > 1) and (not defined($multi))) {
@@ -182,7 +187,7 @@
rename("$inetdcf.new","$inetdcf") ||
die "Error installing new $inetdcf: $!\n";
- umask(000); chmod(0644, "$inetdcf");
+ chmod(0644, "$inetdcf");
&wakeup_inetd;
return(1);
@@ -191,6 +196,7 @@
sub enable_service {
my($service, $pattern) = @_;
unless (defined($service)) { return(-1) };
+ unless (defined($pattern)) { $pattern = ''; }
chomp($service);
open(ICWRITE, ">$inetdcf.new") || die "Error creating new $inetdcf: $!\n";
open(ICREAD, "$inetdcf");
@@ -207,7 +213,7 @@
rename("$inetdcf.new","$inetdcf") ||
die "Error installing new $inetdcf: $!\n";
- umask(000); chmod(0644, "$inetdcf");
+ chmod(0644, "$inetdcf");
&wakeup_inetd;
return(1);
@@ -229,11 +235,12 @@
sub scan_entries {
my ($service, $pattern) = @_;
+ unless (defined($pattern)) { $pattern = ''; }
my $counter = 0;
open(ICREAD, "$inetdcf");
SLOOP: while (<ICREAD>) {
- $counter++ if (/^$service\b/ and /$pattern/);
+ $counter++ if (/^$service\s+/ and /$pattern/);
}
close(ICREAD);
return($counter);
do-test
Description: Perl program
#:TEST:
#<off># warn-enable stream tcp nowait nobody file cmd
warn-disable stream tcp nowait nobody file cmd
warn-rm stream tcp nowait nobody file cmd
# This shouldn't be seen by add_service() because the #<off># isn't at
# the start of the line.
# x #<off># test-add stream tcp nowait nobody file cmd
# This shouldn't be removed by remove_service("arg").
test-rm stream tcp nowait nobody file cmd arg
# These shouldn't be found by scan_entries('test-scan').
test-scan-1 stream tcp nowait nobody file cmd arg
test-scan-2 stream tcp nowait nobody file cmd arg
# DebianNet.pm: a perl module to add entries to the /etc/inetd.conf file
#
# Copyright (C) 1995, 1996 Peter Tobias <[EMAIL PROTECTED]>
# Ian Jackson <[EMAIL PROTECTED]>
#
#
# DebianNet::add_service($newentry, $group);
# DebianNet::disable_service($service, $pattern);
# DebianNet::enable_service($service, $pattern);
# DebianNet::remove_service($entry);
#
package DebianNet;
require 5.000;
$inetdcf="/etc/inetd.conf";
$sep = "#<off># ";
$version = "1.11";
sub add_service {
local($newentry, $group) = @_;
local($service, $searchentry, @inetd, $inetdconf, $found, $success);
unless (defined($newentry)) { return(-1) };
chomp($newentry);
if (defined $group) {
chomp $group;
} else {
$group = "OTHER";
}
$group =~ tr/a-z/A-Z/;
$newentry =~ s/\\t/\t/g;
($service = $newentry) =~ s/(\W*\w+)\s+.*/$1/;
($sservice = $service) =~ s/^#([A-Za-z].*)/$1/;
($searchentry = $newentry) =~ s/^$sep//;
$searchentry =~ s/^#([A-Za-z].*)/$1/;
# strip parameter from entry (e.g. -s /tftpboot)
# example: service dgram udp wait root /tcpd /prg -s
/tftpboot";
$searchentry =~ s/^(\w\S+\W+\w+\W+\w\S+\W+\w\S+\W+\w\S+\W+\S+\W+\S+).*/$1/;
$searchentry =~ s/[ \t]+/ /g;
$searchentry =~ s/ /\\s+/g;
$searchentry =~ [EMAIL PROTECTED]/\S+\\s\+/[EMAIL PROTECTED]@g;
if (open(INETDCONF,"$inetdcf")) {
@inetd=<INETDCONF>;
close(INETDCONF);
if (grep(m/^$sep$sservice\s+/,@inetd)) {
&enable_service($sservice);
} else {
if (grep(m/^$sservice\s+/,@inetd)) {
if (grep(m/^$sservice\s+/,@inetd) > 1) {
&inetde("There are several entries for $sservice in
$inetdcf\n");
} elsif (!grep(m:^#?.*$searchentry.*:, @inetd)) {
print"\nTrying to add the following entry:\n\n
$newentry\n\n";
&inetde("There is already an entry for $sservice in
$inetdcf,
but I don't recognise it. Here is what it looks like:\n
".join(' ',grep(m/^$sservice\s+/,@inetd)));
}
} elsif (grep(m/^#\s*$sservice\s+/, @inetd) >= 1 or
(($service =~ s/^#//) and grep(m/^$service\s+/, @inetd)>=1)) {
&printv("Processing service \`$service' ... not changed\n");
} else {
&printv("Processing service \`$sservice' ... added\n");
$inetdconf=1;
}
}
if ($inetdconf) {
open(ICWRITE, ">$inetdcf.new") || die "Error creating new $inetdcf:
$!\n";
open(ICREAD, "$inetdcf");
while(<ICREAD>) {
chomp;
if (/^#:$group:/) {
$found = 1;
};
if ($found and !(/[a-zA-Z#]/)) {
print (ICWRITE "$newentry\n") || die "Error writing new
$inetdcf: $!\n";
$found = 0;
$success = 1;
}
print ICWRITE "$_\n";
}
close(ICREAD);
unless ($success) {
print (ICWRITE "$newentry\n") || die "Error writing new
$inetdcf: $!\n";
}
close(ICWRITE) || die "Error closing new inetd.conf: $!\n";
rename("$inetdcf.new","$inetdcf") ||
die "Error installing new $inetdcf: $!\n";
chmod(0644, "$inetdcf");
&wakeup_inetd;
}
}
sub inetde {
my($response);
do {
print @_,
"\nDo you want to ignore this potential problem and continue, or would
you rather not do so now ? Continue? (n/y) ";
$!=0; defined($response=<STDIN>) || die "netconfig: EOF/error on
stdin: $!\n";
} while ($response !~ m/^\s*[yn]?\s*$/i);
return(1) if($response =~ m/y/i);
exit(1);
}
return(1);
}
sub remove_service {
my($service) = @_;
unless(defined($service)) { return(-1) };
chomp($service);
if($service eq "") {
print "DebianNet::remove_service called with empty argument\n";
return(-1);
}
if ((&scan_entries("$service") > 1) and (not defined($multi))) {
print "\nWARNING!!!!!! $inetdcf contains multiple entries for \n";
print "the \`$service' service. You're about to remove these
entries.\n";
print "Do you want to continue? [n] ";
if (<STDIN> =~ /^[^y]/i) {
print "\nOk, I'll stop ...\n";
return(1);
} else {
if ($want_continue == 0) {
print "\nOk, I'll continue ...\n";
}
}
}
open(ICWRITE, ">$inetdcf.new") || die "Error creating $inetdcf.new";
open(ICREAD, "$inetdcf");
RLOOP: while(<ICREAD>) {
chomp;
unless (/^$service\s+/) {
print ICWRITE "$_\n";
} else {
&printv("Removing line: \`$_'\n");
}
}
close(ICREAD);
close(ICWRITE);
rename("$inetdcf.new", "$inetdcf") ||
die "Error installing new $inetdcf: $!\n";
chmod(0644, "$inetdcf");
&wakeup_inetd;
return(1);
}
sub disable_service {
my($service, $pattern) = @_;
unless (defined($service)) { return(-1) };
unless (defined($pattern)) { $pattern = ''; }
chomp($service);
if ((&scan_entries("$service", $pattern) > 1) and (not defined($multi))) {
print "\nWARNING!!!!!! $inetdcf contains multiple entries for \n";
print "the \`$service' service. You're about to disable these
entries.\n";
print "Do you want to continue? [n] ";
if (<STDIN> =~ /^[^y]/i) {
print "\nOk, I'll stop ...\n";
return(1);
} else {
if ($want_continue == 0) {
print "\nOk, I'll continue ...\n";
}
}
}
open(ICWRITE, ">$inetdcf.new") || die "Error creating new $inetdcf: $!\n";
open(ICREAD, "$inetdcf");
DLOOP: while(<ICREAD>) {
chomp;
if (/^$service\s+\w+\s+/ and /$pattern/) {
&printv("Processing service \`$service' ... disabled\n");
$_ =~ s/^(.+)$/$sep$1/;
}
print ICWRITE "$_\n";
}
close(ICREAD);
close(ICWRITE) || die "Error closing new inetd.conf: $!\n";
rename("$inetdcf.new","$inetdcf") ||
die "Error installing new $inetdcf: $!\n";
chmod(0644, "$inetdcf");
&wakeup_inetd;
return(1);
}
sub enable_service {
my($service, $pattern) = @_;
unless (defined($service)) { return(-1) };
unless (defined($pattern)) { $pattern = ''; }
chomp($service);
open(ICWRITE, ">$inetdcf.new") || die "Error creating new $inetdcf: $!\n";
open(ICREAD, "$inetdcf");
while(<ICREAD>) {
chomp;
if (/^$sep$service\s+\w+\s+/ and /$pattern/) {
&printv("Processing service \`$service' ... enabled\n");
$_ =~ s/^$sep//;
}
print ICWRITE "$_\n";
}
close(ICREAD);
close(ICWRITE) || die "Error closing new inetd.conf: $!\n";
rename("$inetdcf.new","$inetdcf") ||
die "Error installing new $inetdcf: $!\n";
chmod(0644, "$inetdcf");
&wakeup_inetd;
return(1);
}
sub wakeup_inetd {
my($pid);
if (open(P,"/var/run/inetd.pid")) {
$pid=<P>;
if (open(C,sprintf("/proc/%d/stat",$pid))) {
$_=<C>;
if (m/^\d+ \(inetd\)/) { kill(1,$pid); }
close(C);
}
close(P);
}
return(1);
}
sub scan_entries {
my ($service, $pattern) = @_;
unless (defined($pattern)) { $pattern = ''; }
my $counter = 0;
open(ICREAD, "$inetdcf");
SLOOP: while (<ICREAD>) {
$counter++ if (/^$service\s+/ and /$pattern/);
}
close(ICREAD);
return($counter);
}
sub printv {
print @_ if (defined($verbose));
}
1;

