From: Marc Espie Subject: Re: roadmap for more privsep in pkgland To: ports@openbsd.org Cc: bentley@openbsd.org Date: Fri, 16 Aug 2024 12:15:05 +0200 Here's the basic pkg_add change, very lightly tested for now. Not that many lines, considering :) Index: pkg_create.1 =================================================================== RCS file: /build/data/openbsd/cvs/src/usr.sbin/pkg_add/pkg_create.1,v diff -u -p -r1.131 pkg_create.1 --- pkg_create.1 5 Jul 2023 01:21:51 -0000 1.131 +++ pkg_create.1 16 Aug 2024 10:13:43 -0000 @@ -434,13 +434,19 @@ If does not begin with an @, same as .Dl name/ .Pp -.It Cm @define-tag Ar tag mode params +.It Cm @define-tag Oo owner Ns = Ns Ar o Oc Oo group Ns = Ns Ar g Oc Ar tag mode params Define a tag of name .Ar tag . Tags define actions to be performed at specific time during .Xr pkg_add 1 and -.Xr pkg_delete 1 . +.Xr pkg_delete 1 , +after changing identity to owner +.Ar o +and/or +group +.Ar g +if specified. A given tag may be defined several times with additional properties. Currently, the following modes are defined: .Bl -tag -width abc -compact @@ -498,11 +504,15 @@ only rebuilds the local texmf directory so if both tags are seen, only the global command will be run. .El .Pp -.It Cm @exec Ar command +.It Cm @exec Oo owner Ns = Ns Ar o Oc Oo group Ns = Ns Ar g Oc Ar command Execute .Ar command during -.Xr pkg_add 1 . +.Xr pkg_add 1 , +after optionally changing identity to user +.Ar o +and/or group +.Ar g . Note that .Cm @exec commands are executed relative to their location in the packing-list, @@ -562,36 +572,51 @@ in the example case, .Pa emacs . .El .Pp -.It Cm @exec-always Ar command +.It Cm @exec-always Oo owner Ns = Ns Ar o Oc Oo group Ns = Ns Ar g Oc Ar command Synonym of .Cm @exec . .Pp -.It Cm @exec-add Ar command +.It Cm @exec-add Oo owner Ns = Ns Ar o Oc Oo group Ns = Ns Ar g Oc Ar command Similar to .Cm @exec , except it only gets executed during new installations, and not during updates. .Pp -.It Cm @exec-update Ar command +.It Cm @exec-update Oo owner Ns = Ns Ar o Oc Oo group Ns = Ns Ar g Oc Ar command Similar to .Cm @exec , except it only gets executed during updates, and not during new installations. .Pp -.It Cm @extra Ar filename +.It Cm @extra Oo owner Ns = Ns Ar o Oc Oo group Ns = Ns Ar g Oc Oo always Oc Ar filename Declare extra file .Ar filename to be deleted at deinstall time, if user sets the .Fl c -option. +option or if the optional parameter +.Ar always +is used. Those files are extra configuration files that are normally not deleted. +Allows file ownership to be declared as well. .Ar filename can be an absolute path. If .Ar filename ends with a slash, it is a directory. .Pp -.It Cm @extraunexec Ar command +.It Cm @extraglob Oo owner Ns = Ns Ar o Oc Oo group Ns = Ns Ar g Oc Oo always Oc Ar glob +Declare extra files matching the shell globbing pattern +.Ar glob +to be deleted at deinstall time, if user sets the +.Fl c +option or if the optional parameter +.Ar always +is used. +Allows file ownership to be declared as well. +If +.Ar glob +ends with a slash, it is a directory, which will be wiped recursively. +.It Cm @extraunexec Oo owner Ns = Ns Ar o Oc Oo group Ns = Ns Ar g Oc Ar command Extra .Ar command to execute when removing extra files. @@ -862,7 +887,7 @@ Describe the file as a .Ox static library. .Pp -.It Cm @unexec Ar command +.It Cm @unexec Oo owner Ns = Ns Ar o Oc Oo group Ns = Ns Ar g Oc Ar command Execute .Ar command during @@ -892,17 +917,17 @@ definition must be accessible through th is amenable to the same substitutions as .Cm @exec . .Pp -.It Cm @unexec-always Ar command +.It Cm @unexec-always Oo owner Ns = Ns Ar o Oc Oo group Ns = Ns Ar g Oc Ar command Synonym of .Cm @unexec . .Pp -.It Cm @unexec-delete Ar command +.It Cm @unexec-delete Oo owner Ns = Ns Ar o Oc Oo group Ns = Ns Ar g Oc Ar command Similar to .Cm @unexec , except it only gets executed during true deletions and not while removing an old package during updates. .Pp -.It Cm @unexec-update Ar command +.It Cm @unexec-update Oo owner Ns = Ns Ar o Oc Oo group Ns = Ns Ar g Oc Ar command Similar to .Cm @unexec , except it only gets executed while removing an old package during updates, Index: OpenBSD/Add.pm =================================================================== RCS file: /build/data/openbsd/cvs/src/usr.sbin/pkg_add/OpenBSD/Add.pm,v diff -u -p -r1.196 Add.pm --- OpenBSD/Add.pm 11 Oct 2023 13:54:43 -0000 1.196 +++ OpenBSD/Add.pm 16 Aug 2024 10:04:50 -0000 @@ -257,8 +257,6 @@ sub tag_user_packages(@p) package OpenBSD::PackingElement; use OpenBSD::Error; -# used by newuser/newgroup to deal with options. -my ($uidcache, $gidcache); # $self->prepare_for_addition($state, $pkgname, $set) sub prepare_for_addition($, $, $, $) @@ -297,19 +295,7 @@ sub copy_info($, $, $) sub set_modes($self, $state, $name) { if (defined $self->{owner} || defined $self->{group}) { - require OpenBSD::IdCache; - - if (!defined $uidcache) { - $uidcache = OpenBSD::UidCache->new; - $gidcache = OpenBSD::GidCache->new; - } - my ($uid, $gid) = (-1, -1); - if (defined $self->{owner}) { - $uid = $uidcache->lookup($self->{owner}, $uid); - } - if (defined $self->{group}) { - $gid = $gidcache->lookup($self->{group}, $gid); - } + my ($uid, $gid) = $self->find_ids; chown $uid, $gid, $name; } if (defined $self->{mode}) { @@ -922,6 +908,42 @@ sub find_extractible($self, $state, $wan { $state->{current_set}{known_displays}{$self->{d}->key} = 1; $self->SUPER::find_extractible($state, $wanted, $tied); +} + +package OpenBSD::PackingElement::ExtraGlob; +sub chown($self, $uid, $gid) +{ + chown $uid, $gid, glob $self->fullname; +} + +sub install($self, $state) +{ + my ($uid, $gid) = $self->find_ids; + if ($uid != -1 || $gid != -1) { + $self->chown($uid, $gid); + } +} + +package OpenBSD::PackingElement::ExtraGlobdir; +sub chown($self, $uid, $gid) +{ + require File::Find; + File::Find::find( + sub { + chown $uid, $gid, $_; + }, glob $self->fullname); +} + +package OpenBSD::PackingElement::Extra; +# Forwarder +sub install +{ + &OpenBSD::PackingElement::ExtraGlob::install; +} + +sub chown($self, $uid, $gid) +{ + chown $uid, $gid, $self->fullname; } 1; Index: OpenBSD/Delete.pm =================================================================== RCS file: /build/data/openbsd/cvs/src/usr.sbin/pkg_add/OpenBSD/Delete.pm,v diff -u -p -r1.169 Delete.pm --- OpenBSD/Delete.pm 11 Oct 2023 13:54:43 -0000 1.169 +++ OpenBSD/Delete.pm 16 Aug 2024 09:20:13 -0000 @@ -342,6 +342,32 @@ sub should_run($self, $state) return $state->replacing; } +package OpenBSD::PackingElement::ExtraGlob; +sub unlink($self) +{ + unlink(glob($self->fullname)); +} + +sub delete($self, $state) +{ + if ($self->{always} || $state->{extra}) { + $self->unlink; + } else { + my @l = glob($self->fullname); + if (@l > 0 && -e $l[0]) { + $state->log("You should also remove #1", + $self->fullname); + } + } +} + +package OpenBSD::PackingElement::ExtraGlobdir; +sub unlink($self) +{ + require File::Path; + File::Path::remove_tree(glob($self->fullname), {safe => 1}); +} + package OpenBSD::PackingElement::DefineTag::Atend; sub delete($self, $state) { Index: OpenBSD/PackingElement.pm =================================================================== RCS file: /build/data/openbsd/cvs/src/usr.sbin/pkg_add/OpenBSD/PackingElement.pm,v diff -u -p -r1.291 PackingElement.pm --- OpenBSD/PackingElement.pm 30 Apr 2024 14:26:50 -0000 1.291 +++ OpenBSD/PackingElement.pm 16 Aug 2024 10:03:24 -0000 @@ -181,6 +181,76 @@ sub finish($class, $state) } } +sub new_owned_object($class, $param) +{ + my $o = bless {}, $class; + my $again; + do { + $again = 0; + if ($param =~ s/^owner\=(\S+)\s+//) { + $o->{owner} = $1; + $again = 1; + } + if ($param =~ s/^group\=(\S+)\s+//) { + $o->{group} = $1; + $again = 1; + } + if ($param =~ s/^always\s+//) { + $o->{always} = 1; + } + } while ($again); + $o->{name} = $param; + return $o; +} + +sub stringize_owned_object($self) +{ + my @l = ($self->name); + if (defined $self->{always}) { + unshift(@l, 'always'); + } + if (defined $self->{group}) { + unshift(@l, "group=$self->{group}"); + } + if (defined $self->{owner}) { + unshift(@l, "owner=$self->{owner}"); + } + return join(' ', @l); +} + +my ($uidcache, $gidcache); + +sub find_ids($self) +{ + require OpenBSD::IdCache; + + if (!defined $uidcache) { + $uidcache = OpenBSD::UidCache->new; + $gidcache = OpenBSD::GidCache->new; + } + my ($uid, $gid) = (-1, -1); + if (defined $self->{owner}) { + $uid = $uidcache->lookup($self->{owner}, $uid); + } + if (defined $self->{group}) { + $gid = $gidcache->lookup($self->{group}, $gid); + } + return ($uid, $gid); +} + +sub change_id($self) +{ + my ($uid, $gid) = $self->find_ids; + if ($gid != -1) { + $( = $gid; + $) = "$gid $gid"; + } + if ($uid != -1) { + $< = $uid; + $> = $uid; + } +} + # Basic class hierarchy # various stuff that's only linked to objects before/after them @@ -1304,6 +1374,11 @@ use File::Basename; use OpenBSD::Error; our @ISA=qw(OpenBSD::PackingElement::Action); +sub new($class, $arg) +{ + return $class->new_owned_object($arg); +} + sub command($self) { return $self->name; @@ -1340,7 +1415,15 @@ sub run($self, $state, $v = $self->{expa { $state->ldconfig->ensure; $state->say("#1 #2", $self->keyword, $v) if $state->verbose >= 2; - $state->log->system(OpenBSD::Paths->sh, '-c', $v) unless $state->{not}; + $state->log->system(sub { $self->change_id; }, + OpenBSD::Paths->sh, '-c', $v) + unless $state->{not}; +} + +# Forwarder +sub stringize +{ + &OpenBSD::PackingElement::stringize_owned_object; } # so tags are going to get triggered by packages we depend on. @@ -1407,17 +1490,18 @@ my $subclass = { sub new($class, $args) { - my ($tag, $mode, $params) = split(/\s+/, $args, 3); - $cache->{$args} //= bless { - name => $tag, - mode => $mode, - params => $params, - }, $class; + my $o = $class->new_owned_objet($args); + my ($tag, $mode, $params) = split(/\s+/, $o->{name}, 3); + $o->{name} = $tag; + $o->{mode} = $mode; + $o->{params} = $params; + $cache->{$args} //= $o; } sub stringize($self) { - return join(' ', $self->name, $self->{mode}, $self->{params}); + return join(' ', $self->stringize_owned_object, + $self->{mode}, $self->{params}); } sub add_object($self, $plist) @@ -1722,6 +1806,17 @@ sub destate($self, $state) $self->compute_fullname($state); } +sub new($class, $args) +{ + return $class->new_owned_object($args); +} + +# Forwarder +sub stringize +{ + &OpenBSD::PackingElement::stringize_owned_object; +} + sub dirclass($) { "OpenBSD::PackingElement::Extradir" } package OpenBSD::PackingElement::Extradir; @@ -1734,11 +1829,37 @@ sub destate # forwarder } package OpenBSD::PackingElement::ExtraGlob; -our @ISA=qw(OpenBSD::PackingElement::FileObject); +our @ISA=qw(OpenBSD::PackingElement::Object); + +sub new($class, $args) +{ + return $class->new_owned_object($args); +} + +# Forwarder +sub destate +{ + &OpenBSD::PackingElement::FileObject::destate; +} + +# Forwarder +sub stringize +{ + &OpenBSD::PackingElement::stringize_owned_object; +} + +sub dirclass($) +{ + 'OpenBSD::PackingElement::ExtraGlobdir' +} sub keyword($) { 'extraglob' } sub absolute_okay($) { 1 } + __PACKAGE__->register_with_factory; + +package OpenBSD::PackingElement::ExtraGlobdir; +our @ISA=qw(OpenBSD::PackingElement::ExtraGlob); package OpenBSD::PackingElement::SpecialFile; our @ISA=qw(OpenBSD::PackingElement::Unique);