Shell.pm 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. # ex:ts=8 sw=4:
  2. # $OpenBSD: Shell.pm,v 1.17 2015/07/21 05:10:12 naddy Exp $
  3. #
  4. # Copyright (c) 2010-2014 Marc Espie <espie@openbsd.org>
  5. #
  6. # Permission to use, copy, modify, and distribute this software for any
  7. # purpose with or without fee is hereby granted, provided that the above
  8. # copyright notice and this permission notice appear in all copies.
  9. #
  10. # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  11. # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12. # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  13. # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14. # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15. # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16. # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17. use strict;
  18. use warnings;
  19. # the shell package is used to exec commands.
  20. # note that we're dealing with exec, so we can modify the object/context
  21. # itself with abandon
  22. package DPB::Shell::Abstract;
  23. sub new
  24. {
  25. my ($class, $host) = @_;
  26. $host //= {}; # this makes it possible to build "localhost" shells
  27. bless {as_root => 0, prop => $host->{prop}}, $class;
  28. }
  29. sub prop
  30. {
  31. my $self = shift;
  32. return $self->{prop};
  33. }
  34. sub stringize_master_pid
  35. {
  36. return "";
  37. }
  38. sub chdir
  39. {
  40. my ($self, $dir) = @_;
  41. $self->{dir} = $dir;
  42. return $self;
  43. }
  44. sub env
  45. {
  46. my ($self, %h) = @_;
  47. while (my ($k, $v) = each %h) {
  48. $self->{env}{$k} = $v;
  49. }
  50. return $self;
  51. }
  52. sub as_root
  53. {
  54. my ($self, $val) = @_;
  55. # XXX calling as_root without parms is equivalent to saying "1"
  56. if (@_ == 1) {
  57. $val = 1;
  58. }
  59. $self->{as_root} = $val;
  60. return $self;
  61. }
  62. sub run_as
  63. {
  64. my ($self, $user) = @_;
  65. $self->{user} = $user;
  66. return $self;
  67. }
  68. sub nochroot
  69. {
  70. my $self = shift;
  71. $self->{nochroot} = 1;
  72. return $self;
  73. }
  74. package DPB::Shell::Local;
  75. our @ISA = qw(DPB::Shell::Abstract);
  76. sub is_alive
  77. {
  78. return 1;
  79. }
  80. sub chdir
  81. {
  82. my ($self, $dir) = @_;
  83. CORE::chdir($dir) or DPB::Util->die_bang("Can't chdir to $dir");
  84. return $self;
  85. }
  86. sub env
  87. {
  88. my ($self, %h) = @_;
  89. while (my ($k, $v) = each %h) {
  90. $ENV{$k} = $v;
  91. }
  92. return $self;
  93. }
  94. sub exec
  95. {
  96. my ($self, @argv) = @_;
  97. if ($self->{as_root}) {
  98. unshift(@argv, OpenBSD::Paths->doas);
  99. }
  100. if (-t STDIN) {
  101. close(STDIN);
  102. open STDIN, '</dev/null';
  103. }
  104. exec {$argv[0]} @argv;
  105. }
  106. package DPB::Shell::Chroot;
  107. our @ISA = qw(DPB::Shell::Abstract);
  108. sub exec
  109. {
  110. my ($self, @argv) = @_;
  111. my $chroot = $self->prop->{chroot};
  112. if ($self->{nochroot}) {
  113. undef $chroot;
  114. }
  115. if ($self->prop->{iamroot}) {
  116. $chroot //= '/';
  117. }
  118. unshift @argv, 'exec' unless $self->{as_root} && !$chroot;
  119. if ($self->{env}) {
  120. while (my ($k, $v) = each %{$self->{env}}) {
  121. $v //= '';
  122. unshift @argv, "$k=\'$v\'";
  123. }
  124. }
  125. if ($self->{as_root} && !$chroot) {
  126. unshift(@argv, 'exec', OpenBSD::Paths->doas,
  127. OpenBSD::Paths->env);
  128. }
  129. my $cmd = join(' ', @argv);
  130. if ($self->{dir}) {
  131. $cmd = "cd $self->{dir} && $cmd";
  132. }
  133. if (defined $self->prop->{umask}) {
  134. my $umask = $self->prop->{umask};
  135. $cmd = "umask $umask && $cmd";
  136. }
  137. $self->{user} //= $self->prop->{build_user};
  138. if ($chroot) {
  139. my @cmd2 = ("chroot");
  140. if (!$self->prop->{iamroot}) {
  141. unshift(@cmd2, OpenBSD::Paths->doas);
  142. }
  143. if (!$self->{as_root} && defined $self->{user}) {
  144. push(@cmd2, "-u", $self->{user}->user);
  145. }
  146. $self->_run(@cmd2, $chroot, "/bin/sh", "-c",
  147. $self->quote($cmd));
  148. } else {
  149. $self->_run($cmd);
  150. }
  151. }
  152. package DPB::Shell::Local::Chroot;
  153. our @ISA = qw(DPB::Shell::Chroot);
  154. sub _run
  155. {
  156. my ($self, @argv) = @_;
  157. if (-t STDIN) {
  158. close(STDIN);
  159. open STDIN, '</dev/null';
  160. }
  161. exec {$argv[0]} @argv;
  162. }
  163. sub quote
  164. {
  165. my ($self, $cmd) = @_;
  166. return $cmd;
  167. }
  168. sub is_alive
  169. {
  170. return 1;
  171. }
  172. sub nochroot
  173. {
  174. my $self = shift;
  175. bless $self, 'DPB::Shell::Local';
  176. }
  177. package DPB::Shell::Local::Root;
  178. our @ISA = qw(DPB::Shell::Local::Chroot);
  179. use POSIX;
  180. sub exec
  181. {
  182. my ($self, @argv) = @_;
  183. $> = 0;
  184. $) = 0;
  185. $self->SUPER::exec(@argv);
  186. }
  187. sub nochroot
  188. {
  189. my $self = shift;
  190. $self->{nochroot} = 1;
  191. return $self;
  192. }
  193. 1;