File Coverage

bin/sshss
Criterion Covered Total %
statement 60 69 86.9
branch 19 20 95.0
condition 4 9 44.4
subroutine 13 14 92.8
pod n/a
total 96 112 85.7


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2              
3 5     5   3479 use 5.006;
  5         11  
4 5     5   19 use strict;
  5         6  
  5         77  
5 5     5   17 use warnings;
  5         6  
  5         192  
6              
7             our $VERSION = '0.006';
8              
9             package App::SSH::SwitchShell;
10              
11 5     5   21 use Cwd;
  5         6  
  5         266  
12 5     5   1561 use English qw(-no_match_vars);
  5         3911  
  5         22  
13 5     5   1466 use File::Spec;
  5         6  
  5         2993  
14              
15             sub _exec (&@);
16              
17             if ( !caller ) {
18             main();
19             exit 1;
20             }
21              
22             sub main {
23 7     7   24922 configure_home();
24 7         21 my $shell = configure_shell();
25              
26             # Get the last component of the shell name.
27 7         62 my $shell0 = ( File::Spec->splitpath($shell) )[2];
28              
29             # If we have no command, execute the shell. In this case, the shell
30             # name to be passed in argv[0] is preceded by '-' to indicate that
31             # this is a login shell.
32              
33 7 100       15 if ( !exists $ENV{SSH_ORIGINAL_COMMAND} ) {
34              
35             # Launch a login shell
36 6     6   35 _exec { $shell } "-$shell0";
  6         38007  
37             }
38             else {
39             # Execute the command using the user's shell. This uses the -c
40             # option to execute the command.
41 1     1   14 _exec { $shell } $shell0, '-c', $ENV{SSH_ORIGINAL_COMMAND};
  1         6301  
42             }
43              
44 7         42 return;
45             }
46              
47             # We have to run exec from a small wrapper function to be able to test this
48             # script
49             # https://stackoverflow.com/questions/44597021/how-do-you-test-exec-used-with-indirect-object-syntax
50             sub _exec (&@) {
51 0     0   0 my ( $file, @argv ) = @_;
52 0         0 $file = $file->();
53              
54             {
55 0         0 exec {$file} @argv;
  0         0  
  0         0  
56             }
57              
58 0         0 print {*STDERR} "$ERRNO: $file\n";
  0         0  
59 0         0 exit 1;
60             }
61              
62             # Update the HOME env variable and change to the new home directory if we
63             # are configured for a shared account. Otherwise do nothung because SSH
64             # already ensures that HOME is configured correctly and we are chdir'd
65             # into it.
66             sub configure_home {
67 14     14   55788 my $myhome = get_abs_script_basedir();
68              
69 14         155 my @dirs = File::Spec->splitdir($myhome);
70 14 100       47 return if $dirs[-1] ne '.ssh';
71 13         31 pop @dirs;
72 13         133 $myhome = File::Spec->catdir(@dirs);
73              
74 13 100 33     395 if ( exists $ENV{HOME} && defined $ENV{HOME} && -d $ENV{HOME} ) {
      66        
75 8         54 my $home = File::Spec->canonpath( $ENV{HOME} );
76              
77 8         495 my $home_rp = Cwd::realpath($home);
78 8         475 my $myhome_rp = Cwd::realpath($myhome);
79 8 100       93 return if $home_rp eq $myhome_rp;
80             }
81              
82 11         44 $ENV{HOME} = $myhome;
83              
84 11 100       136 if ( !chdir $myhome ) {
85 2         16 print {*STDERR} "Could not chdir to home '$myhome': $ERRNO";
  2         92  
86             }
87              
88 11         51 return;
89             }
90              
91             sub get_abs_script_basedir {
92 1     1   2623 my $basedir = File::Spec->rel2abs(__FILE__);
93 1         37 $basedir = ( File::Spec->splitpath($basedir) )[1];
94 1         31 $basedir = File::Spec->canonpath($basedir);
95              
96 1         21 return $basedir;
97             }
98              
99             sub configure_shell {
100 14     14   37859 my $shell = get_shell();
101              
102             # Make sure SHELL points to the correct shell, either the shell
103             # specified as argument, the shell from the password file, or /bin/sh
104 14         71 $ENV{SHELL} = $shell;
105              
106 14         31 return $shell;
107             }
108              
109             sub get_shell {
110              
111             # The shell can be specified as argument
112 14 100   14   32 if (@ARGV) {
113 13         21 my $shell = shift @ARGV;
114              
115 13 100       291 if ( !File::Spec->file_name_is_absolute($shell) ) {
    100          
116 2         6 print {*STDERR} "Shell '$shell' is not an absolute path\n";
  2         104  
117             }
118             elsif ( !-e $shell ) {
119 1         12 print {*STDERR} "Shell '$shell' does not exist\n";
  1         31  
120             }
121             else {
122 10 100       168 return $shell if -x $shell;
123              
124 2         4 print {*STDERR} "Shell '$shell' is not executable\n";
  2         54  
125             }
126             }
127              
128             # Get the shell from the password data. An empty shell field is
129             # legal, and means /bin/sh.
130              
131 6         46 my $shell = ( getpwuid $EUID )[8];
132 6 50 33     79 return $shell if defined $shell && $shell ne q{};
133 0           return '/bin/sh';
134             }
135              
136             1;
137              
138             __END__