From owner-freebsd-bugs Thu Nov 23 14: 0:13 2000 Delivered-To: freebsd-bugs@freebsd.org Received: from freefall.freebsd.org (freefall.FreeBSD.org [216.136.204.21]) by hub.freebsd.org (Postfix) with ESMTP id CCD0437B4CF for ; Thu, 23 Nov 2000 14:00:01 -0800 (PST) Received: (from gnats@localhost) by freefall.freebsd.org (8.9.3/8.9.2) id OAA66069; Thu, 23 Nov 2000 14:00:01 -0800 (PST) (envelope-from gnats@FreeBSD.org) Received: from ringworld.nanolink.com (ringworld.nanolink.com [195.24.48.13]) by hub.freebsd.org (Postfix) with SMTP id 1F43D37B4C5 for ; Thu, 23 Nov 2000 13:58:54 -0800 (PST) Received: (qmail 1380 invoked by uid 1000); 23 Nov 2000 21:58:26 -0000 Message-Id: <20001123215826.1379.qmail@ringworld.nanolink.com> Date: 23 Nov 2000 21:58:26 -0000 From: Peter Pentchev Reply-To: Peter Pentchev To: FreeBSD-gnats-submit@freebsd.org X-Send-Pr-Version: 3.2 Subject: bin/23052: [PATCH] rmuser fails to remove at jobs Sender: owner-freebsd-bugs@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.org >Number: 23052 >Category: bin >Synopsis: [PATCH] rmuser fails to remove at jobs >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Thu Nov 23 14:00:01 PST 2000 >Closed-Date: >Last-Modified: >Originator: Peter Pentchev >Release: FreeBSD 4.2-STABLE i386 >Organization: Orbitel JSCo. >Environment: RELENG_3, RELENG_4, HEAD >Description: The /usr/sbin/rmuser Perl script includes a function for removing the late user's at-scheduled jobs. However, that code has been subtly wrong from the start, and for quite some time now has simply not worked. It scans the /var/at/jobs directory for files belonging to the user being removed, and then passes each filename as an argument to atrm. However, atrm no longer accepts such filenames as arguments - it wants a job ID. Failing to find the "ID" specified, atrm quietly does nothing, leaving the scheduled job to be executed, and not alerting the adminstrator or whoever it is invoking rmuser. Submitted by: Mike Sellenschuetter in a mail to -security; Message-Id: <8625699E.0061FCDC.00@dalnsd40.bankofamerica.com> >How-To-Repeat: [root@ringworld:v4 ~]# pw adduser test [root@ringworld:v4 ~]# echo 'at -f /dev/null now + 1 hour' | su test Job 24 will be executed using /bin/sh [root@ringworld:v4 ~]# atq Date Owner Queue Job# 00:45:00 11/24/00 test c 24 [root@ringworld:v4 ~]# rmuser test Matching password entry: test:*:1007:1007::0:0:User &:/home/test:/bin/sh Is this the entry you wish to remove? y /usr/sbin/rmuser: Informational: Home /home/test is not a directory, so it won't be removed Removing user's at jobs: c0001800f7f5d5 done. Updating password file, updating databases, done. Updating group file: (removing group test -- personal group is empty) done. Removing user's incoming mail file /var/mail/test: done. Removing files belonging to test from /tmp: done. Removing files belonging to test from /var/tmp: done. Removing files belonging to test from /var/tmp/vi.recover: done. [root@ringworld:v4 ~]# atq Date Owner Queue Job# 00:45:00 11/24/00 ??? c 24 [root@ringworld:v4 ~]# >Fix: Although it is trivial to extract the job ID from the filename - in the example given, the job ID was 24, and the filename contained a 00018 hex string - I do not really think this is the way to go. There's no telling when the at job filename format shall be changed again, and it is very easy to miss updating rmuser if/when that should happen. Attached instead are two patches - one against RELENG_4, another against -current - which add two additional subroutines to invoke atq, parse its output, find the jobs belonging to this user, then invoke atrm and kill off the correct job ID's. The patch against RELENG_4 also applies cleanly to RELENG_3. I think this one might well be worth MFC'ing into 3.x. Here's the diff against -current.. Index: rmuser.perl =================================================================== RCS file: /home/ncvs/src/usr.sbin/adduser/rmuser.perl,v retrieving revision 1.11 diff -u -r1.11 rmuser.perl --- rmuser.perl 2000/11/21 05:52:35 1.11 +++ rmuser.perl 2000/11/23 21:27:47 @@ -199,7 +199,7 @@ # Remove the user's at jobs, if any # (probably also needs to be done before password databases are updated) -&remove_at_jobs($login_name, $uid); +&remove_at_jobs($login_name); # # Kill all the user's processes @@ -464,32 +464,75 @@ printf STDERR " done.\n"; } -sub remove_at_jobs { - local($login_name, $uid) = @_; - local($i, $owner, $found); - - $found = 0; - opendir(ATDIR, $atjob_dir) || return; - while ($i = readdir(ATDIR)) { - next if $i eq '.'; - next if $i eq '..'; - next if $i eq '.lockfile'; - $owner = (stat("$atjob_dir/$i"))[4]; # UID - if ($uid == $owner) { - if (!$found) { - print STDERR "Removing user's at jobs:"; - $found = 1; - } - # Use atrm to remove the job - print STDERR " $i"; - system('/usr/bin/atrm', $i); +sub invoke_atq { + local *ATQ; + my($user) = (shift || ""); + my($path_atq) = "/usr/bin/atq"; + my(@at) = (); + my($pid, $line); + + return @at if ($user eq ""); + + if (!defined($pid = open(ATQ, "-|"))) { + die("creating pipe to atq: $!\n"); + } elsif ($pid == 0) { + exec($path_atq, $user); + die("executing $path_atq: $!\n"); + } + + while(defined($_ = )) { + chomp; + if (/^\d\d:\d\d:\d\d\s+\d\d\/\d\d\/\d\d\s+(\S+)\s+\S+\s+(\d+)$/) { + push(@at, $2) if ($1 eq $user); } } - closedir(ATDIR); - if ($found) { - print STDERR " done.\n"; + close ATQ; + return @at; +} + +sub invoke_atrm { + local *ATRM; + my($user) = (shift || ""); + my($path_atrm) = "/usr/bin/atrm"; + my(@jobs) = @_; + my($pid); + my($txt) = ""; + + return "Invalid arguments" if (($user eq "") || ($#jobs == -1)); + + if (!defined($pid = open(ATRM, "-|"))) { + die("creating pipe to atrm: $!\n"); + } elsif ($pid == 0) { + exec($path_atrm, $user, @jobs); + } + + while(defined($_ = )) { + $txt .= $_; } + close ATRM; + return $txt; +} + +sub remove_at_jobs { + my($user) = (shift || ""); + my(@at, $atrm); + + return 1 if ($user eq ""); + + print STDERR "Removing user's at jobs:"; + @at = invoke_atq($user); + return 0 if ($#at == -1); + + print STDERR " @at:"; + $atrm = invoke_atrm($user, @at); + if ($atrm ne "") { + print STDERR " -- $atrm\n"; + return 1; + } + + print STDERR "done.\n"; + return 0; } sub resolvelink { ================================================================== And here's the diff against RELENG_4.. Index: rmuser.perl =================================================================== RCS file: /home/ncvs/src/usr.sbin/adduser/rmuser.perl,v retrieving revision 1.8.2.1 diff -u -r1.8.2.1 rmuser.perl --- rmuser.perl 2000/03/20 13:00:36 1.8.2.1 +++ rmuser.perl 2000/11/23 21:25:50 @@ -202,7 +202,7 @@ # Remove the user's at jobs, if any # (probably also needs to be done before password databases are updated) -&remove_at_jobs($login_name, $uid); +&remove_at_jobs($login_name); # # Kill all the user's processes @@ -495,32 +495,75 @@ printf STDERR " done.\n"; } -sub remove_at_jobs { - local($login_name, $uid) = @_; - local($i, $owner, $found); - - $found = 0; - opendir(ATDIR, $atjob_dir) || return; - while ($i = readdir(ATDIR)) { - next if $i eq '.'; - next if $i eq '..'; - next if $i eq '.lockfile'; - $owner = (stat("$atjob_dir/$i"))[4]; # UID - if ($uid == $owner) { - if (!$found) { - print STDERR "Removing user's at jobs:"; - $found = 1; - } - # Use atrm to remove the job - print STDERR " $i"; - system('/usr/bin/atrm', $i); +sub invoke_atq { + local *ATQ; + my($user) = (shift || ""); + my($path_atq) = "/usr/bin/atq"; + my(@at) = (); + my($pid, $line); + + return @at if ($user eq ""); + + if (!defined($pid = open(ATQ, "-|"))) { + die("creating pipe to atq: $!\n"); + } elsif ($pid == 0) { + exec($path_atq, $user); + die("executing $path_atq: $!\n"); + } + + while(defined($_ = )) { + chomp; + if (/^\d\d:\d\d:\d\d\s+\d\d\/\d\d\/\d\d\s+(\S+)\s+\S+\s+(\d+)$/) { + push(@at, $2) if ($1 eq $user); } } - closedir(ATDIR); - if ($found) { - print STDERR " done.\n"; + close ATQ; + return @at; +} + +sub invoke_atrm { + local *ATRM; + my($user) = (shift || ""); + my($path_atrm) = "/usr/bin/atrm"; + my(@jobs) = @_; + my($pid); + my($txt) = ""; + + return "Invalid arguments" if (($user eq "") || ($#jobs == -1)); + + if (!defined($pid = open(ATRM, "-|"))) { + die("creating pipe to atrm: $!\n"); + } elsif ($pid == 0) { + exec($path_atrm, $user, @jobs); + } + + while(defined($_ = )) { + $txt .= $_; } + close ATRM; + return $txt; +} + +sub remove_at_jobs { + my($user) = (shift || ""); + my(@at, $atrm); + + return 1 if ($user eq ""); + + print STDERR "Removing user's at jobs:"; + @at = invoke_atq($user); + return 0 if ($#at == -1); + + print STDERR " @at:"; + $atrm = invoke_atrm($user, @at); + if ($atrm ne "") { + print STDERR " -- $atrm\n"; + return 1; + } + + print STDERR "done.\n"; + return 0; } sub resolvelink { >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message