--- toast 2004/09/05 22:03:00 1.342
+++ toast 2004/09/18 21:33:36 1.343
@@ -258,6 +258,7 @@
"armdir" => superuser ? "/usr/local" : "armed",
"altarmdirs" => "",
"username" => "toast",
+ "fallbackuid" => 23,
"postarmprog" => superuser ? "/sbin/ldconfig" : "",
"editprog" => "",
"defaultcmd" => "help",
@@ -1310,26 +1311,57 @@
##############################################################################
-sub getuidgid()
+BEGIN
{
- my($username) = username;
- my($name, $passwd, $uid, $gid) = getpwnam($username);
- error("getpwnam $username: $!") unless defined($name);
- return ($uid, $gid);
-}
+ my($uid, $gid, $usertext);
-sub dropprivs()
-{
- return unless superuser;
- my($username) = username;
- explain("running as user $username");
- my($uid, $gid) = getuidgid;
- $uid || error("refusing to run as root");
- $( = $gid;
- $) = "$gid $gid";
- ($<, $>) = ($uid, $uid);
- $> == $< || error("real and effective UIDs do not match");
- $> == $uid || error("uid is not set correctly");
+ sub initnonroot()
+ {
+ error unless superuser;
+ return if $uid;
+ $usertext = username;
+ my($name);
+ ($name, undef, $uid, $gid) = getpwnam($usertext);
+ return if defined($name);
+ my($tryuid) = fallbackuid;
+ error("no such user: $usertext") unless $tryuid;
+ explain("no such user: $usertext");
+ for(1..65535)
+ {
+ if(!defined(getpwuid($tryuid)))
+ {
+ explain("falling back on uid $tryuid, gid $tryuid");
+ ($uid, $gid, $usertext) = ($tryuid, $tryuid, $tryuid);
+ return;
+ }
+ ++$uid;
+ $uid = 1 if $uid == 65536;
+ }
+ error("can't find unused uid");
+ }
+
+ sub chownnonroot(@)
+ {
+ my(@files) = @_;
+ return true unless superuser;
+ initnonroot;
+ $uid || error;
+ announce("chown", $usertext, @files);
+ chown($uid, $gid, @files) || error("chown $uid:$gid @files: $!");
+ }
+
+ sub dropprivs()
+ {
+ return true unless superuser;
+ initnonroot;
+ explain("running as user $usertext");
+ $uid || error("refusing to run as root");
+ $( = $gid;
+ $) = "$gid $gid";
+ ($<, $>) = ($uid, $uid);
+ $> == $< || error("real and effective UIDs do not match");
+ $> == $uid || error("uid is not set correctly");
+ }
}
##############################################################################
@@ -3573,12 +3605,7 @@
error("mkdir $builddir: $errmsg") if $errmsg && !-d($builddir);
}
announce("mkdir", $builddir);
- if(superuser)
- {
- my($uid, $gid) = getuidgid;
- announce("chown", username, $builddir);
- chown($uid, $gid, $builddir) || error("chown $uid:$gid $builddir: $!");
- }
+ chownnonroot($builddir);
local(*CHILD);
my($pid);
@@ -4225,13 +4252,7 @@
my($patchfile) = path($editdir, $patchfilename);
md($editdir, $olddir, $newdir);
- if(superuser)
- {
- my($uid, $gid) = getuidgid;
- announce("chown", username, $olddir, $newdir);
- chown($uid, $gid, $olddir, $newdir) ||
- error("chown $uid:$gid $olddir $newdir: $!");
- }
+ chownnonroot($olddir, $newdir);
local(*PATCH);
safeopen(*PATCH, ">", $patchfile);
@@ -6100,6 +6121,14 @@
Note that any additional groups (such as those in C</etc/groups>) will
be ignored, as will I<USER>'s password, home directory, shell, and so on.
Default: C<toast>.
+
+=item B<--fallbackuid=>I<UID>
+
+If B<toast> is invoked as root and needs to do something as a non-root
+user, it normally runs as the user given by the B<username> option.
+However, if no such user exists, B<toast> will search for an unused
+UID to use instead, starting at I<UID>. Use 0 to disable this feature.
+Default: C<23>.
=item B<--postarmprog=>I<PROG>