File Coverage

blib/lib/Net/SSH/Perl/Config.pm
Criterion Covered Total %
statement 68 92 73.9
branch 27 60 45.0
condition 9 21 42.8
subroutine 17 18 94.4
pod 5 5 100.0
total 126 196 64.2


line stmt bran cond sub pod time code
1             # $Id: Config.pm,v 1.22 2008/10/02 20:46:17 turnstep Exp $
2              
3             package Net::SSH::Perl::Config;
4 4     4   35 use strict;
  4         11  
  4         225  
5 4     4   26 use warnings;
  4         10  
  4         185  
6              
7 4     4   28 use Net::SSH::Perl::Constants qw( :protocol :kex );
  4         23  
  4         33  
8 4     4   66 use vars qw( %DIRECTIVES $AUTOLOAD );
  4         12  
  4         357  
9 4     4   30 use Carp qw( croak );
  4         9  
  4         9007  
10              
11             %DIRECTIVES = (
12             BindAddress => [ \&_set_str, 'bind_address' ],
13             Host => [ \&_host ],
14             BatchMode => [ \&_batch_mode ],
15             ChallengeResponseAuthentication => [ \&_set_yesno, 'auth_ch_res' ],
16             CheckHostIP => [ \&_set_yesno, 'check_host_ip' ],
17             Cipher => [ \&_cipher ],
18             Ciphers => [ \&_set_str, 'ciphers', KEX_DEFAULT_ENCRYPT, KEX_ALL_ENCRYPT ],
19             Compression => [ \&_set_yesno, 'compression' ],
20             CompressionLevel => [ \&_set_str, 'compression_level' ],
21             DSAAuthentication => [ \&_set_yesno, 'auth_dsa' ],
22             FingerprintHash => [ \&_set_str, 'fingerprint_hash' ],
23             GlobalKnownHostsFile => [ \&_set_str, 'global_known_hosts' ],
24             HashKnownHosts => [ \&_set_yesno, 'hash_known_hosts' ],
25             HostKeyAlgorithms => [ \&_set_str, 'host_key_algorithms', KEX_DEFAULT_PK_ALG, KEX_ALL_PK_ALG ],
26             HostName => [ \&_set_str, 'hostname' ],
27             IdentityFile => [ \&_identity_file ],
28             KexAlgorithms => [ \&_set_str, 'kex_algorithms', KEX_DEFAULT_KEX, KEX_ALL_KEX ],
29             MACs => [ \&_set_str, 'macs', KEX_DEFAULT_MAC, KEX_ALL_MAC ],
30             NumberOfPasswordPrompts => [ \&_set_str, 'number_of_password_prompts' ],
31             PasswordAuthentication => [ \&_set_yesno, 'auth_password' ],
32             PasswordPromptHost => [ \&_set_yesno, 'password_prompt_host' ],
33             PasswordPromptLogin => [ \&_set_yesno, 'password_prompt_login' ],
34             Port => [ \&_set_str, 'port' ],
35             Protocol => [ \&_protocol ],
36             RhostsAuthentication => [ \&_set_yesno, 'auth_rhosts' ],
37             RhostsRSAAuthentication => [ \&_set_yesno, 'auth_rhosts_rsa' ],
38             RSAAuthentication => [ \&_set_yesno, 'auth_rsa' ],
39             StrictHostKeyChecking => [ \&_set_str, 'strict_host_key_checking' ],
40             UpdateHostKeys => [ \&_set_str, 'update_host_keys' ],
41             UsePrivilegedPort => [ \&_set_yesno, 'privileged' ],
42             User => [ \&_set_str, 'user' ],
43             UserKnownHostsFile => [ \&_set_str, 'user_known_hosts' ],
44             );
45              
46             sub new {
47 7     7 1 6885 my $class = shift;
48 7         24 my $host = shift;
49 7         56 bless { host => $host, o => { @_ } }, $class;
50             }
51              
52 49     49 1 1102 sub get { $_[0]->{o}{ $_[1] } }
53              
54             sub set {
55 22     22 1 67 my($cfg, $key) = @_;
56 22 50       95 $cfg->{o}{$key} = $_[2] if @_ == 3;
57 22         76 $cfg->{o}{$key};
58             }
59              
60             sub read_config {
61 11     11 1 2186 my($cfg, $conf_file) = @_;
62              
63 11         61 local $cfg->{_state} = { host => $cfg->{host}, host_matched => 1 };
64              
65 11         53 local($_, $/);
66 11         33 $/ = "\n";
67 11 100       485 open my $fh, '<', $conf_file or return;
68 6         115 while (<$fh>) {
69 54 100 66     383 next if !/\S/ || /^#/;
70 48         311 my($key, $args) = $_ =~ /^\s*(\S+)\s+(.+)$/;
71 48 50 33     238 next unless $key && $args;
72 48 100 100     231 next unless $cfg->{_state}{host_matched} || $key eq "Host";
73              
74 34 50       119 my $code = $DIRECTIVES{$key}[0] or next;
75 34         98 $code->($cfg, $key, $args);
76             }
77 6 50       107 close $fh or warn qq{Could not close "$conf_file": $!\n};
78             }
79              
80             sub merge_directive {
81 6     6 1 3718 my($cfg, $line) = @_;
82 6         51 my($key, $args) = $line =~ /^\s*(\S+)\s+(.+)$/;
83 6 50 33     38 return unless $key && $args;
84              
85 6 50       36 my $code = $DIRECTIVES{$key}[0] or return;
86 6         25 $code->($cfg, $key, $args);
87             }
88              
89             sub _host {
90 12     12   35 my($cfg, $key, $host) = @_;
91 12         38 (my $hostre = $host) =~ s/\*/.*/g;
92 12         32 $hostre =~ s/\?/./g;
93 12 100 66     284 if ($host eq '*' || $cfg->{_state}{host} =~ /^$hostre$/) {
94 6         49 $cfg->{_state}{host_matched} = 1;
95             }
96             else {
97 6         42 $cfg->{_state}{host_matched} = 0;
98             }
99             }
100              
101             sub _batch_mode {
102 2     2   7 my($cfg, $key, $batch) = @_;
103 2 50       10 return if exists $cfg->{o}{interactive};
104 2 50       90 $cfg->{o}{interactive} = $batch eq "yes" ? 0 : 1;
105             }
106              
107             sub _identity_file {
108 10     10   29 my($cfg, $key, $id_file) = @_;
109             $cfg->{identity_files} = []
110 10 100       50 unless ref $cfg->{o}{identity_files} eq "ARRAY";
111 10         31 $id_file =~ s!~!$ENV{HOME}!;
112 10         26 push @{ $cfg->{o}{identity_files} }, $id_file;
  10         65  
113             }
114              
115             sub _protocol {
116 0     0   0 my($cfg, $key, $p_list) = @_;
117 0 0       0 return if exists $cfg->{o}{protocol};
118 0         0 for my $p (split /\s*,\s*/, $p_list) {
119 0 0 0     0 croak "Invalid protocol: must be 1 or 2"
120             unless $p == 1 || $p == 2;
121 0         0 $cfg->{o}{protocol} |= $p;
122 0 0 0     0 if ($p == PROTOCOL_SSH1 && !($cfg->{o}{protocol} & PROTOCOL_SSH2)) {
123 0         0 $cfg->{o}{protocol} |= PROTOCOL_SSH1_PREFERRED;
124             }
125             }
126             }
127              
128             sub _set_str {
129 13     13   40 my($cfg, $key, $value) = @_;
130 13 100       59 return if exists $cfg->{o}{ $DIRECTIVES{$key}[1] };
131 10 50       120 if ($value =~ s/^-//) {
    50          
132 0         0 my @list;
133 0         0 $value =~ s/\*/\.\*/g;
134 0 0       0 my $defaults = $DIRECTIVES{$key}[2] or return;
135 0         0 foreach (split(',', $defaults)) {
136 0 0       0 next if /^$value$/;
137 0         0 push @list, $_;
138             }
139 0         0 $value = join(',',@list);
140             }
141             elsif ($value =~ s/^\+//) {
142 0         0 my @list;
143 0         0 $value =~ s/\*/\.\*/g;
144 0 0       0 my $all = $DIRECTIVES{$key}[3] or return;
145 0         0 foreach (split(',', $all)) {
146 0 0       0 push @list, $_ if /^$value$/;
147             }
148 0         0 $value = join(',', $DIRECTIVES{$key}[2], @list);
149             }
150 10         73 $cfg->{o}{ $DIRECTIVES{$key}[1] } = $value;
151             }
152              
153             {
154             my %cipher_map = (
155             idea => 'IDEA',
156             none => 'None',
157             des => 'DES',
158             '3des' => 'DES3',
159             arcfour => 'RC4',
160             blowfish => 'Blowfish',
161             );
162              
163             sub _cipher {
164 1     1   4 my($cfg, $key, $value) = @_;
165 1 50       6 return if exists $cfg->{o}{cipher};
166 1         8 $cfg->{o}{cipher} = $cipher_map{$value};
167             }
168             }
169              
170             sub _set_yesno {
171 2     2   7 my($cfg, $key, $yesno) = @_;
172 2 50       14 return if exists $cfg->{o}{ $DIRECTIVES{$key}[1] };
173 2 50       13 if ($yesno eq "yes") {
    50          
174 0         0 $cfg->{o}{ $DIRECTIVES{$key}[1] } = 1;
175             }
176             elsif ($yesno eq "no") {
177 2         12 $cfg->{o}{ $DIRECTIVES{$key}[1] } = 0;
178             }
179             else {
180 0         0 warn "Configuration setting for '$key' must be 'yes' or 'no'";
181             }
182             }
183              
184             sub AUTOLOAD {
185 7     7   2842 my $cfg = shift;
186 7         120 (my $variable = $AUTOLOAD) =~ s/.*:://;
187 7 50       130 return if $variable eq 'DESTROY';
188              
189             croak "No such configuration option $variable"
190 0 0         unless exists $cfg->{o}{$variable};
191              
192 0 0         return @_ ? $cfg->set($variable, @_) : $cfg->get($variable);
193             }
194              
195             1;
196             __END__