--- 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>