pax_global_header 0000666 0000000 0000000 00000000064 13153765720 0014523 g ustar 00root root 0000000 0000000 52 comment=4790748f9fad1aafda500d68747bc21a465f262c
net-ssh-4.2.0/ 0000775 0000000 0000000 00000000000 13153765720 0013107 5 ustar 00root root 0000000 0000000 net-ssh-4.2.0/.gitignore 0000664 0000000 0000000 00000000071 13153765720 0015075 0 ustar 00root root 0000000 0000000 /Gemfile.lock
doc
ri
pkg
*.swp
test/integration/.vagrant
net-ssh-4.2.0/.rubocop.yml 0000664 0000000 0000000 00000000111 13153765720 0015352 0 ustar 00root root 0000000 0000000 inherit_from: .rubocop_todo.yml
AllCops:
Exclude:
- 'tryout/**/*'
net-ssh-4.2.0/.rubocop_todo.yml 0000664 0000000 0000000 00000100711 13153765720 0016406 0 ustar 00root root 0000000 0000000 # This configuration was generated by
# `rubocop --auto-gen-config`
# on 2016-12-11 13:27:14 +0100 using RuboCop version 0.46.0.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
# Offense count: 4
# Configuration parameters: AllowSafeAssignment.
Lint/AssignmentInCondition:
Exclude:
- 'lib/net/ssh/connection/channel.rb'
- 'lib/net/ssh/connection/session.rb'
- 'lib/net/ssh/proxy/command.rb'
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: AlignWith, SupportedStyles.
# SupportedStyles: either, start_of_block, start_of_line
Lint/BlockAlignment:
Exclude:
- 'test/integration/test_proxy.rb'
# Offense count: 1
# Cop supports --auto-correct.
Lint/DeprecatedClassMethods:
Exclude:
- 'Rakefile'
# Offense count: 1
Lint/EmptyWhen:
Exclude:
- 'lib/net/ssh/config.rb'
# Offense count: 223
# Cop supports --auto-correct.
# Configuration parameters: AlignWith, SupportedStyles, AutoCorrect.
# SupportedStyles: keyword, variable, start_of_line
Lint/EndAlignment:
Enabled: false
# Offense count: 8
Lint/HandleExceptions:
Exclude:
- 'lib/net/ssh/authentication/session.rb'
- 'lib/net/ssh/known_hosts.rb'
- 'lib/net/ssh/transport/openssl.rb'
- 'test/integration/common.rb'
- 'test/integration/test_forward.rb'
- 'test/start/test_connection.rb'
- 'test/start/test_transport.rb'
# Offense count: 72
Lint/ImplicitStringConcatenation:
Exclude:
- 'lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb'
- 'lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb'
# Offense count: 1
Lint/LiteralInCondition:
Exclude:
- 'lib/net/ssh/authentication/pageant.rb'
# Offense count: 2
Lint/Loop:
Exclude:
- 'lib/net/ssh/authentication/methods/password.rb'
- 'lib/net/ssh/key_factory.rb'
# Offense count: 1
Lint/NextWithoutAccumulator:
Exclude:
- 'lib/net/ssh/connection/session.rb'
# Offense count: 1
Lint/NonLocalExitFromIterator:
Exclude:
- 'lib/net/ssh/known_hosts.rb'
# Offense count: 4
Lint/RescueException:
Exclude:
- 'lib/net/ssh/authentication/key_manager.rb'
- 'lib/net/ssh/service/forward.rb'
- 'lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb'
# Offense count: 2
Lint/ShadowedException:
Exclude:
- 'lib/net/ssh/authentication/key_manager.rb'
# Offense count: 1
Lint/UnderscorePrefixedVariableName:
Exclude:
- 'lib/net/ssh/test/local_packet.rb'
# Offense count: 52
# Cop supports --auto-correct.
# Configuration parameters: IgnoreEmptyBlocks, AllowUnusedKeywordArguments.
Lint/UnusedBlockArgument:
Exclude:
- 'lib/net/ssh/connection/keepalive.rb'
- 'lib/net/ssh/connection/session.rb'
- 'lib/net/ssh/service/forward.rb'
- 'test/authentication/methods/test_password.rb'
- 'test/authentication/test_agent.rb'
- 'test/common.rb'
- 'test/connection/test_channel.rb'
- 'test/connection/test_session.rb'
- 'test/transport/test_algorithms.rb'
- 'test/transport/test_hmac.rb'
# Offense count: 50
# Cop supports --auto-correct.
# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods.
Lint/UnusedMethodArgument:
Enabled: false
# Offense count: 3
# Configuration parameters: ContextCreatingMethods.
Lint/UselessAccessModifier:
Exclude:
- 'lib/net/ssh/buffered_io.rb'
- 'lib/net/ssh/connection/channel.rb'
- 'lib/net/ssh/transport/session.rb'
# Offense count: 10
Lint/UselessAssignment:
Exclude:
- 'lib/net/ssh/proxy/socks4.rb'
- 'lib/net/ssh/proxy/socks5.rb'
- 'test/integration/common.rb'
- 'test/integration/test_forward.rb'
# Offense count: 196
Metrics/AbcSize:
Max: 76
# Offense count: 14
# Configuration parameters: CountComments.
Metrics/BlockLength:
Max: 88
# Offense count: 1
Metrics/BlockNesting:
Max: 4
# Offense count: 27
# Configuration parameters: CountComments.
Metrics/ClassLength:
Max: 548
# Offense count: 34
Metrics/CyclomaticComplexity:
Max: 39
# Offense count: 1341
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
# URISchemes: http, https
Metrics/LineLength:
Max: 934
# Offense count: 164
# Configuration parameters: CountComments.
Metrics/MethodLength:
Max: 93
# Offense count: 1
# Configuration parameters: CountComments.
Metrics/ModuleLength:
Max: 142
# Offense count: 1
# Configuration parameters: CountKeywordArgs.
Metrics/ParameterLists:
Max: 6
# Offense count: 27
Metrics/PerceivedComplexity:
Max: 23
# Offense count: 3
# Cop supports --auto-correct.
Performance/RangeInclude:
Exclude:
- 'lib/net/ssh/transport/algorithms.rb'
# Offense count: 3
# Cop supports --auto-correct.
Performance/RedundantBlockCall:
Exclude:
- 'lib/net/ssh/connection/session.rb'
- 'test/connection/test_channel.rb'
# Offense count: 6
# Cop supports --auto-correct.
Performance/RedundantMatch:
Exclude:
- 'lib/net/ssh/key_factory.rb'
- 'lib/net/ssh/transport/server_version.rb'
# Offense count: 13
Style/AccessorMethodName:
Exclude:
- 'lib/net/ssh/authentication/methods/password.rb'
- 'lib/net/ssh/authentication/pageant.rb'
- 'lib/net/ssh/connection/session.rb'
- 'lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb'
- 'lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb'
- 'lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb'
- 'lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb'
# Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: prefer_alias, prefer_alias_method
Style/Alias:
Exclude:
- 'lib/net/ssh/connection/session.rb'
- 'lib/net/ssh/service/forward.rb'
# Offense count: 1
# Cop supports --auto-correct.
Style/AlignArray:
Exclude:
- 'lib/net/ssh/proxy/socks5.rb'
# Offense count: 25
# Cop supports --auto-correct.
# Configuration parameters: EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle, SupportedLastArgumentHashStyles.
# SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit
Style/AlignHash:
Exclude:
- 'lib/net/ssh/transport/algorithms.rb'
- 'test/connection/test_channel.rb'
- 'test/integration/test_id_rsa_keys.rb'
- 'test/transport/kex/test_diffie_hellman_group1_sha1.rb'
- 'test/transport/kex/test_ecdh_sha2_nistp256.rb'
- 'test/transport/test_algorithms.rb'
- 'test/transport/test_cipher_factory.rb'
- 'test/transport/test_state.rb'
# Offense count: 72
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
# SupportedStyles: with_first_parameter, with_fixed_indentation
Style/AlignParameters:
Enabled: false
# Offense count: 33
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: always, conditionals
Style/AndOr:
Exclude:
- 'lib/net/ssh/authentication/key_manager.rb'
- 'lib/net/ssh/buffer.rb'
- 'lib/net/ssh/buffered_io.rb'
- 'lib/net/ssh/config.rb'
- 'lib/net/ssh/connection/channel.rb'
- 'lib/net/ssh/connection/session.rb'
- 'lib/net/ssh/key_factory.rb'
- 'lib/net/ssh/service/forward.rb'
- 'lib/net/ssh/test/channel.rb'
- 'lib/net/ssh/test/script.rb'
- 'lib/net/ssh/transport/cipher_factory.rb'
- 'lib/net/ssh/transport/hmac.rb'
- 'lib/net/ssh/transport/key_expander.rb'
- 'lib/net/ssh/transport/packet_stream.rb'
- 'test/common.rb'
# Offense count: 2
Style/AsciiComments:
Exclude:
- 'lib/net/ssh/authentication/pageant.rb'
- 'lib/net/ssh/buffered_io.rb'
# Offense count: 11
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, ProceduralMethods, FunctionalMethods, IgnoredMethods.
# SupportedStyles: line_count_based, semantic, braces_for_chaining
# ProceduralMethods: benchmark, bm, bmbm, create, each_with_object, measure, new, realtime, tap, with_object
# FunctionalMethods: let, let!, subject, watch
# IgnoredMethods: lambda, proc, it
Style/BlockDelimiters:
Exclude:
- 'Rakefile'
- 'lib/net/ssh/authentication/key_manager.rb'
- 'lib/net/ssh/config.rb'
- 'lib/net/ssh/connection/keepalive.rb'
- 'lib/net/ssh/proxy/command.rb'
- 'lib/net/ssh/transport/ctr.rb'
- 'test/test_buffer.rb'
- 'test/verifiers/test_secure.rb'
# Offense count: 8
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: braces, no_braces, context_dependent
Style/BracesAroundHashParameters:
Exclude:
- 'lib/net/ssh/config.rb'
- 'test/integration/test_ed25519_pkeys.rb'
- 'test/integration/test_id_rsa_keys.rb'
- 'test/transport/test_hmac.rb'
- 'test/transport/test_session.rb'
- 'test_kerberos_client2.rb'
# Offense count: 2
Style/CaseEquality:
Exclude:
- 'lib/net/ssh/buffer.rb'
- 'lib/net/ssh/connection/session.rb'
# Offense count: 42
# Cop supports --auto-correct.
# Configuration parameters: IndentWhenRelativeTo, SupportedStyles, IndentOneStep, IndentationWidth.
# SupportedStyles: case, end
Style/CaseIndentation:
Exclude:
- 'lib/net/ssh.rb'
- 'lib/net/ssh/authentication/methods/hostbased.rb'
- 'lib/net/ssh/authentication/methods/none.rb'
- 'lib/net/ssh/authentication/methods/password.rb'
- 'lib/net/ssh/authentication/methods/publickey.rb'
- 'lib/net/ssh/buffer.rb'
- 'lib/net/ssh/config.rb'
- 'lib/net/ssh/test/local_packet.rb'
- 'lib/net/ssh/test/packet.rb'
# Offense count: 1
# Cop supports --auto-correct.
Style/CharacterLiteral:
Exclude:
- 'test/test_buffer.rb'
# Offense count: 12
Style/ClassAndModuleCamelCase:
Exclude:
- 'lib/net/ssh/transport/hmac/md5_96.rb'
- 'lib/net/ssh/transport/hmac/sha1_96.rb'
- 'lib/net/ssh/transport/hmac/sha2_256.rb'
- 'lib/net/ssh/transport/hmac/sha2_256_96.rb'
- 'lib/net/ssh/transport/hmac/sha2_512.rb'
- 'lib/net/ssh/transport/hmac/sha2_512_96.rb'
- 'test/transport/hmac/test_md5_96.rb'
- 'test/transport/hmac/test_sha1_96.rb'
- 'test/transport/hmac/test_sha2_256.rb'
- 'test/transport/hmac/test_sha2_256_96.rb'
- 'test/transport/hmac/test_sha2_512.rb'
- 'test/transport/hmac/test_sha2_512_96.rb'
# Offense count: 16
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: nested, compact
Style/ClassAndModuleChildren:
Enabled: false
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: is_a?, kind_of?
Style/ClassCheck:
Exclude:
- 'test/authentication/test_key_manager.rb'
# Offense count: 7
Style/ClassVars:
Exclude:
- 'lib/net/ssh/config.rb'
- 'lib/net/ssh/packet.rb'
- 'test/authentication/methods/test_hostbased.rb'
- 'test/authentication/methods/test_publickey.rb'
# Offense count: 1
# Cop supports --auto-correct.
Style/ColonMethodCall:
Exclude:
- 'lib/net/ssh/authentication/ed25519.rb'
# Offense count: 4
# Cop supports --auto-correct.
# Configuration parameters: Keywords.
# Keywords: TODO, FIXME, OPTIMIZE, HACK, REVIEW
Style/CommentAnnotation:
Exclude:
- 'lib/net/ssh/authentication/ed25519.rb'
- 'lib/net/ssh/authentication/session.rb'
- 'lib/net/ssh/buffer.rb'
- 'lib/net/ssh/config.rb'
# Offense count: 2
# Cop supports --auto-correct.
Style/CommentIndentation:
Exclude:
- 'test/integration/test_forward.rb'
- 'test/transport/test_server_version.rb'
# Offense count: 4
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, SingleLineConditionsOnly.
# SupportedStyles: assign_to_condition, assign_inside_condition
Style/ConditionalAssignment:
Exclude:
- 'lib/net/ssh/transport/ctr.rb'
- 'lib/net/ssh/transport/state.rb'
- 'test/test_key_factory.rb'
- 'lib/net/ssh/config.rb'
- 'lib/net/ssh/known_hosts.rb'
- 'lib/net/ssh/proxy/socks5.rb'
- 'lib/net/ssh/test/script.rb'
# Offense count: 5
Style/ConstantName:
Exclude:
- 'lib/net/ssh/authentication/pageant.rb'
- 'lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb'
- 'lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb'
- 'lib/net/ssh/transport/openssl.rb'
# Offense count: 1
# Cop supports --auto-correct.
Style/DefWithParentheses:
Exclude:
- 'test/integration/test_forward.rb'
# Offense count: 16
Style/Documentation:
Exclude:
- 'spec/**/*'
- 'test/**/*'
- 'lib/net/ssh/authentication/ed25519.rb'
- 'lib/net/ssh/connection/keepalive.rb'
- 'lib/net/ssh/connection/session.rb'
- 'lib/net/ssh/ruby_compat.rb'
- 'lib/net/ssh/test/extensions.rb'
- 'lib/net/ssh/transport/hmac/sha2_256_96.rb'
- 'lib/net/ssh/transport/hmac/sha2_512.rb'
- 'lib/net/ssh/transport/hmac/sha2_512_96.rb'
- 'lib/net/ssh/transport/kex.rb'
- 'lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb'
- 'lib/net/ssh/transport/key_expander.rb'
- 'lib/net/ssh/transport/openssl.rb'
# Offense count: 6
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: leading, trailing
Style/DotPosition:
Exclude:
- 'test/transport/test_algorithms.rb'
# Offense count: 3
# Cop supports --auto-correct.
Style/EachWithObject:
Exclude:
- 'lib/net/ssh/config.rb'
- 'lib/net/ssh/connection/session.rb'
- 'lib/net/ssh/service/forward.rb'
# Offense count: 1
# Cop supports --auto-correct.
Style/ElseAlignment:
Exclude:
- 'lib/net/ssh/packet.rb'
# Offense count: 12
# Cop supports --auto-correct.
# Configuration parameters: AllowAdjacentOneLineDefs.
Style/EmptyLineBetweenDefs:
Exclude:
- 'lib/net/ssh/buffered_io.rb'
- 'lib/net/ssh/ruby_compat.rb'
- 'lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb'
- 'lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb'
- 'test/test_buffer.rb'
- 'test/test_key_factory.rb'
# Offense count: 16
# Cop supports --auto-correct.
Style/EmptyLines:
Exclude:
- 'Rakefile'
- 'lib/net/ssh/buffered_io.rb'
- 'lib/net/ssh/connection/session.rb'
- 'lib/net/ssh/known_hosts.rb'
- 'lib/net/ssh/transport/cipher_factory.rb'
- 'lib/net/ssh/transport/packet_stream.rb'
- 'lib/net/ssh/transport/session.rb'
- 'test/authentication/methods/test_keyboard_interactive.rb'
- 'test/authentication/methods/test_password.rb'
- 'test/integration/test_ed25519_pkeys.rb'
- 'test/integration/test_id_rsa_keys.rb'
- 'test/test_config.rb'
- 'test/test_known_hosts.rb'
- 'test/transport/test_cipher_factory.rb'
# Offense count: 39
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: empty_lines, empty_lines_except_namespace, empty_lines_special, no_empty_lines
Style/EmptyLinesAroundClassBody:
Enabled: false
# Offense count: 4
# Cop supports --auto-correct.
Style/EmptyLinesAroundMethodBody:
Exclude:
- 'lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb'
- 'lib/net/ssh/transport/openssl.rb'
- 'test/transport/hmac/test_sha2_256.rb'
- 'test/transport/hmac/test_sha2_512.rb'
# Offense count: 209
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: empty_lines, empty_lines_except_namespace, empty_lines_special, no_empty_lines
Style/EmptyLinesAroundModuleBody:
Enabled: false
# Offense count: 2
# Cop supports --auto-correct.
Style/EmptyLiteral:
Exclude:
- 'lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb'
- 'lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb'
# Offense count: 1
# Cop supports --auto-correct.
Style/EvenOdd:
Exclude:
- 'lib/net/ssh/buffer.rb'
# Offense count: 17
# Cop supports --auto-correct.
# Configuration parameters: AllowForAlignment, ForceEqualSignAlignment.
Style/ExtraSpacing:
Exclude:
- 'Rakefile'
- 'lib/net/ssh/authentication/methods/password.rb'
- 'lib/net/ssh/authentication/pageant.rb'
- 'lib/net/ssh/proxy/socks5.rb'
- 'lib/net/ssh/transport/hmac/sha2_256_96.rb'
- 'lib/net/ssh/transport/hmac/sha2_512_96.rb'
- 'test/authentication/test_key_manager.rb'
- 'test/integration/test_forward.rb'
- 'test/test_config.rb'
- 'test/test_key_factory.rb'
- 'test/transport/test_packet_stream.rb'
# Offense count: 2
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: format, sprintf, percent
Style/FormatString:
Exclude:
- 'lib/net/ssh/authentication/pageant.rb'
- 'lib/net/ssh/loggable.rb'
# Offense count: 35
# Configuration parameters: MinBodyLength.
Style/GuardClause:
Enabled: false
# Offense count: 1
Style/IfInsideElse:
Exclude:
- 'lib/net/ssh/connection/session.rb'
# Offense count: 9
# Cop supports --auto-correct.
# Configuration parameters: MaxLineLength.
Style/IfUnlessModifier:
Exclude:
- 'lib/net/ssh.rb'
- 'lib/net/ssh/authentication/pageant.rb'
- 'lib/net/ssh/proxy/command.rb'
- 'lib/net/ssh/service/forward.rb'
- 'lib/net/ssh/transport/ctr.rb'
- 'lib/net/ssh/transport/key_expander.rb'
- 'test/integration/test_proxy.rb'
- 'test/test_key_factory.rb'
# Offense count: 4
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
# SupportedStyles: special_inside_parentheses, consistent, align_brackets
Style/IndentArray:
Exclude:
- 'lib/net/ssh/transport/openssl.rb'
# Offense count: 4
# Cop supports --auto-correct.
# Configuration parameters: IndentationWidth.
Style/IndentAssignment:
Exclude:
- 'test/transport/kex/test_diffie_hellman_group1_sha1.rb'
- 'test/transport/kex/test_ecdh_sha2_nistp256.rb'
- 'test/transport/kex/test_ecdh_sha2_nistp384.rb'
- 'test/transport/kex/test_ecdh_sha2_nistp521.rb'
# Offense count: 227
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: normal, rails
Style/IndentationConsistency:
Enabled: false
# Offense count: 96
# Cop supports --auto-correct.
# Configuration parameters: Width.
Style/IndentationWidth:
Enabled: false
# Offense count: 1
# Cop supports --auto-correct.
Style/InfiniteLoop:
Exclude:
- 'lib/net/ssh/authentication/pageant.rb'
# Offense count: 17
# Cop supports --auto-correct.
Style/LeadingCommentSpace:
Exclude:
- 'test/integration/test_ed25519_pkeys.rb'
- 'test/integration/test_forward.rb'
- 'test/integration/test_id_rsa_keys.rb'
- 'test/integration/test_proxy.rb'
# Offense count: 27
# Cop supports --auto-correct.
Style/LineEndConcatenation:
Exclude:
- 'lib/net/ssh/authentication/pageant.rb'
- 'lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb'
- 'lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb'
- 'lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb'
- 'lib/net/ssh/verifiers/secure.rb'
# Offense count: 12
# Cop supports --auto-correct.
Style/MethodCallWithoutArgsParentheses:
Exclude:
- 'test/authentication/test_key_manager.rb'
- 'test/connection/test_session.rb'
- 'test/integration/test_forward.rb'
- 'test/start/test_user_nil.rb'
# Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: require_parentheses, require_no_parentheses, require_no_parentheses_except_multiline
Style/MethodDefParentheses:
Exclude:
- 'test/common.rb'
- 'test/integration/common.rb'
# Offense count: 1
Style/MethodMissing:
Exclude:
- 'lib/net/ssh/connection/session.rb'
# Offense count: 24
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: snake_case, camelCase
Style/MethodName:
Exclude:
- 'lib/net/ssh/authentication/ed25519_loader.rb'
- 'test/authentication/test_agent.rb'
- 'test/authentication/test_session.rb'
- 'test/common.rb'
- 'test/connection/test_channel.rb'
- 'test/test_config.rb'
- 'test/test_key_factory.rb'
# Offense count: 3
# Cop supports --auto-correct.
Style/MultilineIfThen:
Exclude:
- 'lib/net/ssh/buffered_io.rb'
- 'lib/net/ssh/service/forward.rb'
# Offense count: 23
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
# SupportedStyles: aligned, indented
Style/MultilineOperationIndentation:
Exclude:
- 'lib/net/ssh/authentication/pageant.rb'
- 'lib/net/ssh/known_hosts.rb'
- 'lib/net/ssh/proxy/https.rb'
- 'lib/net/ssh/transport/algorithms.rb'
- 'lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb'
- 'lib/net/ssh/transport/state.rb'
- 'lib/net/ssh/verifiers/secure.rb'
- 'test/authentication/methods/test_hostbased.rb'
- 'test/authentication/methods/test_publickey.rb'
# Offense count: 40
# Cop supports --auto-correct.
Style/MutableConstant:
Enabled: false
# Offense count: 13
# Cop supports --auto-correct.
Style/NegatedIf:
Exclude:
- 'lib/net/ssh.rb'
- 'lib/net/ssh/authentication/key_manager.rb'
- 'lib/net/ssh/service/forward.rb'
- 'lib/net/ssh/transport/algorithms.rb'
- 'lib/net/ssh/transport/hmac/abstract.rb'
- 'lib/net/ssh/transport/session.rb'
- 'lib/net/ssh/transport/state.rb'
- 'test/test_key_factory.rb'
- 'test/transport/test_state.rb'
# Offense count: 1
# Cop supports --auto-correct.
Style/NegatedWhile:
Exclude:
- 'lib/net/ssh/config.rb'
# Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles.
# SupportedStyles: skip_modifier_ifs, always
Style/Next:
Exclude:
- 'lib/net/ssh/authentication/key_manager.rb'
- 'lib/net/ssh/transport/algorithms.rb'
# Offense count: 2
# Cop supports --auto-correct.
Style/NilComparison:
Exclude:
- 'lib/net/ssh/proxy/command.rb'
- 'lib/net/ssh/transport/openssl.rb'
# Offense count: 3
# Cop supports --auto-correct.
Style/Not:
Exclude:
- 'lib/net/ssh/connection/channel.rb'
# Offense count: 7
# Cop supports --auto-correct.
Style/NumericLiterals:
MinDigits: 310
# Offense count: 11
# Cop supports --auto-correct.
# Configuration parameters: AutoCorrect, EnforcedStyle, SupportedStyles.
# SupportedStyles: predicate, comparison
Style/NumericPredicate:
Exclude:
- 'spec/**/*'
- 'lib/net/ssh/authentication/methods/password.rb'
- 'lib/net/ssh/authentication/pageant.rb'
- 'lib/net/ssh/buffer.rb'
- 'lib/net/ssh/service/forward.rb'
- 'lib/net/ssh/test/extensions.rb'
- 'lib/net/ssh/transport/key_expander.rb'
- 'test/transport/test_packet_stream.rb'
- 'test_connection_close_shall_close_cannels.rb'
# Offense count: 2
Style/OpMethod:
Exclude:
- 'lib/net/ssh/buffer.rb'
- 'lib/net/ssh/version.rb'
# Offense count: 15
# Cop supports --auto-correct.
Style/ParallelAssignment:
Exclude:
- 'lib/net/ssh/config.rb'
- 'lib/net/ssh/connection/channel.rb'
- 'lib/net/ssh/connection/session.rb'
- 'lib/net/ssh/errors.rb'
- 'lib/net/ssh/test/socket.rb'
- 'lib/net/ssh/version.rb'
- 'test/authentication/test_agent.rb'
- 'test/common.rb'
- 'test/connection/test_channel.rb'
# Offense count: 7
# Cop supports --auto-correct.
# Configuration parameters: AllowSafeAssignment.
Style/ParenthesesAroundCondition:
Exclude:
- 'lib/net/ssh/authentication/ed25519.rb'
- 'lib/net/ssh/service/forward.rb'
- 'lib/net/ssh/transport/cipher_factory.rb'
- 'lib/net/ssh/transport/ctr.rb'
- 'test/integration/test_proxy.rb'
# Offense count: 5
# Cop supports --auto-correct.
# Configuration parameters: PreferredDelimiters.
Style/PercentLiteralDelimiters:
Exclude:
- 'Rakefile'
- 'net-ssh.gemspec'
- 'test/test_config.rb'
# Offense count: 16
# Cop supports --auto-correct.
Style/PerlBackrefs:
Exclude:
- 'lib/net/ssh/buffer.rb'
- 'lib/net/ssh/config.rb'
- 'lib/net/ssh/key_factory.rb'
- 'lib/net/ssh/proxy/command.rb'
- 'lib/net/ssh/proxy/socks5.rb'
- 'lib/net/ssh/transport/openssl.rb'
- 'test/integration/common.rb'
# Offense count: 14
# Cop supports --auto-correct.
Style/Proc:
Exclude:
- 'lib/net/ssh/connection/session.rb'
- 'lib/net/ssh/test/channel.rb'
- 'lib/net/ssh/transport/algorithms.rb'
- 'lib/net/ssh/verifiers/secure.rb'
- 'test/authentication/methods/test_hostbased.rb'
- 'test/authentication/methods/test_publickey.rb'
- 'test/connection/test_channel.rb'
- 'test/connection/test_session.rb'
# Offense count: 7
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: compact, exploded
Style/RaiseArgs:
Exclude:
- 'lib/net/ssh/authentication/ed25519.rb'
# Offense count: 4
# Cop supports --auto-correct.
Style/RedundantBegin:
Exclude:
- 'lib/net/ssh/buffered_io.rb'
- 'lib/net/ssh/verifiers/strict.rb'
- 'test/manual/test_pageant.rb'
# Offense count: 1
# Cop supports --auto-correct.
Style/RedundantParentheses:
Exclude:
- 'support/arcfour_check.rb'
# Offense count: 57
# Cop supports --auto-correct.
# Configuration parameters: AllowMultipleReturnValues.
Style/RedundantReturn:
Enabled: false
# Offense count: 11
# Cop supports --auto-correct.
Style/RedundantSelf:
Exclude:
- 'lib/net/ssh/authentication/ed25519.rb'
- 'lib/net/ssh/connection/channel.rb'
- 'lib/net/ssh/test/extensions.rb'
- 'lib/net/ssh/transport/openssl.rb'
- 'test/authentication/test_ed25519.rb'
# Offense count: 4
# Cop supports --auto-correct.
Style/RescueModifier:
Exclude:
- 'lib/net/ssh/service/forward.rb'
- 'lib/net/ssh/transport/algorithms.rb'
# Offense count: 1
# Cop supports --auto-correct.
Style/SelfAssignment:
Exclude:
- 'lib/net/ssh/config.rb'
# Offense count: 8
# Cop supports --auto-correct.
# Configuration parameters: AllowAsExpressionSeparator.
Style/Semicolon:
Exclude:
- 'lib/net/ssh/buffer.rb'
- 'test/connection/test_channel.rb'
- 'test/connection/test_session.rb'
- 'test/transport/kex/test_ecdh_sha2_nistp256.rb'
# Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: only_raise, only_fail, semantic
Style/SignalException:
Exclude:
- 'lib/net/ssh/config.rb'
- 'lib/net/ssh/connection/channel.rb'
# Offense count: 2
# Cop supports --auto-correct.
# Configuration parameters: AllowIfMethodIsEmpty.
Style/SingleLineMethods:
Exclude:
- 'lib/net/ssh/buffered_io.rb'
# Offense count: 16
# Cop supports --auto-correct.
Style/SpaceAfterColon:
Exclude:
- 'lib/net/ssh/authentication/ed25519.rb'
- 'test/integration/test_ed25519_pkeys.rb'
- 'test/verifiers/test_secure.rb'
# Offense count: 254
# Cop supports --auto-correct.
Style/SpaceAfterComma:
Enabled: false
# Offense count: 132
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: space, no_space
Style/SpaceAroundEqualsInParameterDefault:
Enabled: false
# Offense count: 55
# Cop supports --auto-correct.
# Configuration parameters: AllowForAlignment.
Style/SpaceAroundOperators:
Enabled: false
# Offense count: 6
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: space, no_space
Style/SpaceBeforeBlockBraces:
Exclude:
- 'lib/net/ssh/authentication/session.rb'
- 'support/ssh_tunnel_bug.rb'
- 'test/authentication/test_agent.rb'
- 'test/connection/test_session.rb'
# Offense count: 4
# Cop supports --auto-correct.
Style/SpaceBeforeComma:
Exclude:
- 'test/integration/test_forward.rb'
- 'test/integration/test_proxy.rb'
# Offense count: 3
# Cop supports --auto-correct.
# Configuration parameters: AllowForAlignment.
Style/SpaceBeforeFirstArg:
Exclude:
- 'lib/net/ssh/transport/hmac/sha2_256_96.rb'
- 'lib/net/ssh/transport/hmac/sha2_512_96.rb'
- 'test/authentication/test_key_manager.rb'
# Offense count: 10
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters.
# SupportedStyles: space, no_space
Style/SpaceInsideBlockBraces:
Exclude:
- 'lib/net/ssh/authentication/session.rb'
- 'lib/net/ssh/transport/ctr.rb'
- 'support/ssh_tunnel_bug.rb'
- 'test/authentication/test_agent.rb'
- 'test/authentication/test_key_manager.rb'
- 'test/start/test_user_nil.rb'
# Offense count: 22
# Cop supports --auto-correct.
Style/SpaceInsideBrackets:
Exclude:
- 'Rakefile'
- 'lib/net/ssh/transport/algorithms.rb'
- 'lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb'
- 'test/integration/test_forward.rb'
- 'test/start/test_options.rb'
# Offense count: 69
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces, SupportedStyles.
# SupportedStyles: space, no_space, compact
Style/SpaceInsideHashLiteralBraces:
Enabled: false
# Offense count: 13
# Cop supports --auto-correct.
Style/SpaceInsideParens:
Exclude:
- 'lib/net/ssh/transport/algorithms.rb'
- 'lib/net/ssh/transport/openssl.rb'
# Offense count: 3
# Cop supports --auto-correct.
Style/SpaceInsideRangeLiteral:
Exclude:
- 'lib/net/ssh/authentication/ed25519.rb'
- 'lib/net/ssh/transport/algorithms.rb'
# Offense count: 22
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: use_perl_names, use_english_names
Style/SpecialGlobalVars:
Exclude:
- 'lib/net/ssh/authentication/agent.rb'
- 'lib/net/ssh/connection/session.rb'
- 'support/ssh_tunnel_bug.rb'
- 'test/integration/common.rb'
- 'test/integration/test_forward.rb'
- 'test/manual/test_pageant.rb'
- 'test/test_all.rb'
- 'test_connection_close_shall_close_cannels.rb'
- 'test_kerberos_client2.rb'
# Offense count: 1846
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, ConsistentQuotesInMultiline.
# SupportedStyles: single_quotes, double_quotes
Style/StringLiterals:
Enabled: false
# Offense count: 11
# Cop supports --auto-correct.
# Configuration parameters: IgnoredMethods.
# IgnoredMethods: respond_to, define_method
Style/SymbolProc:
Exclude:
- 'lib/net/ssh/authentication/session.rb'
- 'lib/net/ssh/buffer.rb'
- 'lib/net/ssh/connection/session.rb'
- 'lib/net/ssh/test/extensions.rb'
- 'lib/net/ssh/transport/algorithms.rb'
- 'test/integration/test_forward.rb'
- 'test/test/test_test.rb'
# Offense count: 1
# Cop supports --auto-correct.
Style/Tab:
Exclude:
- 'lib/net/ssh/config.rb'
# Offense count: 39
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: final_newline, final_blank_line
Style/TrailingBlankLines:
Enabled: false
# Offense count: 255
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyleForMultiline, SupportedStyles.
# SupportedStyles: comma, consistent_comma, no_comma
Style/TrailingCommaInLiteral:
Exclude:
- 'lib/net/ssh/key_factory.rb'
- 'lib/net/ssh/transport/cipher_factory.rb'
- 'lib/net/ssh/transport/kex.rb'
- 'lib/net/ssh/transport/openssl.rb'
- 'test/transport/test_packet_stream.rb'
# Offense count: 66
# Cop supports --auto-correct.
Style/TrailingWhitespace:
Enabled: false
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: ExactNameMatch, AllowPredicates, AllowDSLWriters, IgnoreClassMethods, Whitelist.
# Whitelist: to_ary, to_a, to_c, to_enum, to_h, to_hash, to_i, to_int, to_io, to_open, to_path, to_proc, to_r, to_regexp, to_str, to_s, to_sym
Style/TrivialAccessors:
Exclude:
- 'test/transport/kex/test_diffie_hellman_group1_sha1.rb'
# Offense count: 6
# Cop supports --auto-correct.
Style/UnlessElse:
Exclude:
- 'lib/net/ssh/buffer.rb'
- 'lib/net/ssh/transport/ctr.rb'
- 'test/transport/kex/test_ecdh_sha2_nistp256.rb'
- 'test/transport/kex/test_ecdh_sha2_nistp384.rb'
- 'test/transport/kex/test_ecdh_sha2_nistp521.rb'
- 'test/transport/test_server_version.rb'
# Offense count: 4
# Cop supports --auto-correct.
Style/UnneededInterpolation:
Exclude:
- 'lib/net/ssh/proxy/socks5.rb'
- 'lib/net/ssh/transport/session.rb'
- 'test/integration/test_forward.rb'
# Offense count: 4
# Cop supports --auto-correct.
Style/UnneededPercentQ:
Exclude:
- 'net-ssh.gemspec'
- 'test/test_config.rb'
# Offense count: 2
# Cop supports --auto-correct.
Style/WhileUntilDo:
Exclude:
- 'lib/net/ssh/config.rb'
- 'test/integration/common.rb'
# Offense count: 3
# Cop supports --auto-correct.
# Configuration parameters: SupportedStyles, WordRegex.
# SupportedStyles: percent, brackets
Style/WordArray:
EnforcedStyle: percent
MinSize: 3
# Offense count: 7
# Cop supports --auto-correct.
Style/ZeroLengthPredicate:
Exclude:
- 'lib/net/ssh/buffered_io.rb'
- 'lib/net/ssh/connection/channel.rb'
- 'test/integration/test_forward.rb'
- 'test_connection_close_shall_close_cannels.rb'
net-ssh-4.2.0/.travis.yml 0000664 0000000 0000000 00000002622 13153765720 0015222 0 ustar 00root root 0000000 0000000 language: ruby
sudo: true
dist: trusty
addon:
hosts:
gateway.netssh
rvm:
- 2.0
- 2.1
- 2.2
- 2.3.0
- 2.4.0
- jruby-9.1.6.0
- rbx-3.69
- ruby-head
env:
NET_SSH_RUN_INTEGRATION_TESTS=1
matrix:
exclude:
- rvm: rbx-3.69
- rvm: jruby-9.1.6.0
include:
- rvm: rbx-3.69
env: NET_SSH_RUN_INTEGRATION_TESTS=
- rvm: jruby-9.1.6.0
env: JRUBY_OPTS='--client -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1 -Xcext.enabled=false -J-Xss2m -Xcompile.invokedynamic=false' NET_SSH_RUN_INTEGRATION_TESTS=
fast_finish: true
allow_failures:
- rvm: rbx-3.69
- rvm: jruby-9.1.6.0
- rvm: ruby-head
install:
- export JRUBY_OPTS='--client -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1 -Xcext.enabled=false -J-Xss2m -Xcompile.invokedynamic=false'
- sudo pip install ansible
- gem install bundler -v "= 1.13.7"
- bundle _1.13.7_ install
- BUNDLE_GEMFILE=./Gemfile.norbnacl bundle _1.13.7_ install
- sudo ansible-galaxy install rvm_io.ruby
- sudo chown -R travis:travis /home/travis/.ansible
- ansible-playbook ./test/integration/playbook.yml -i "localhost," --become -c local -e 'no_rvm=true' -e 'myuser=travis' -e 'mygroup=travis' -e 'homedir=/home/travis'
script:
- ssh -V
- bundle _1.13.7_ exec rake test
- BUNDLE_GEMFILE=./Gemfile.norbnacl bundle _1.13.7_ exec rake test
- bundle _1.13.7_ exec rake test_test
- bundle _1.13.7_ exec rubocop
net-ssh-4.2.0/CHANGES.txt 0000664 0000000 0000000 00000047764 13153765720 0014742 0 ustar 00root root 0000000 0000000 === 4.2.0.rc2
* Fix double close bug on auth failure (or ruby 2.2 or earlier) [#538]
=== 4.2.0.rc1
* Improved logging with proxy command [Dmitriy Ivliev, #530]
* Close transport on proxy error [adamruzicka, #526]
* Support multiple identity files [Kimura Masayuki, #528]
* Move `none` cipher to end of cipher list [Brian Cain, #525]
* Deprecate `:paranoid` in favor of `:verify_host_key` [Jared Beck, #524]
* Support Multile Include ssh config files [Kasumi Hanazuki, #516]
* Support Relative path in ssh confif files [Akinori MUSHA, #510]
* add direct-streamlocal@openssh.com support in Forward class [Harald Sitter, #502]
=== 4.1.0
=== 4.1.0.rc1
* ProxyJump support [Ryan McGeary, #500]
* Fix agent detection on Windows [Christian Koehler, #495]
=== 4.1.0.beta1
* Fix nil error when libsodium is not there [chapmajs ,#488]
* SSH certificate support for client auth [David Bartley, #485]
=== 4.0.1
=== 4.0.1.rc2
* ENV["HOME"] might be empty so filter non expandable paths [Matt Casper, #351]
=== 4.0.1.rc1
* support of rbnacl 4.0 and better error message [#479]
* support include in config files [Kimura Masayuki, #475]
* fixed issue with ruby 2.2 or older on windows [#472]
=== 4.0.0
=== 4.0.0.rc3
* parse `+` character in config files [Christoph Lupprich, #470, #314]
=== 4.0.0.rc2
* Fixed OpenSSL 2.0/Ruby 2.4.0 warnings [Miklós Fazekas, #468]
* Added ssh-ed25519 to KnownHosts:SUPPORTED_TYPE [detatka-kuzlatka-otevrete, Miklós Fazekas, #459]
* Allow nil for :passhrase and passing in nil option is now a depreaction warning [Miklós Fazekas, #465]
=== 4.0.0.rc1
* Allow :password to be nil for capistrano v2 compatibility [Will Bryant, #357]
* In next_packet if prefer consuming buffer before filling it again if we have enough data [Miklós Fazekas, #454]
=== 4.0.0.beta4
* Added exitstatus method to exec's return [Miklós Fazekas, #452]
* Don't raise from exec if server closes transport just after channel close [Miklós Fazekas, #450]
* Removed java_pageant, as jruby should be using regular pagent impl [Miklós Fazekas, ]
* Use SSH_AUTH_SOCK if possible on windows (cygwin) [Miklós Fazekas, Martin Dürst, #365, #361]
* HTTPS proxy support [Marcus Ilgner, #432]
* Supports ruby 2.4.0.dev new exception type from OpenSSL::PKey.read
=== 4.0.0.beta3
* Fix Net::SSH::Disconnect exceptions when channels are closed cleanly [Miklos Fazekas, #421, #422]
=== 4.0.0.beta2
* Fix raiseUnlessLoaded undefined ERROR issue [Miklos Fazekas, #418]
=== 4.0.0.beta1
* Fix pageant [elconas, #235]
* Relaxed rbnacl,rbnacl-selenium contstraints ang give better errors about them [Miklos Fazekas, #398]
* Fix UTF-8 encoding issues [Ethan J. Brown, #407]
=== 4.0.0.alpha4
* Experimental event loop abstraction [Miklos Fazekas]
* RbNacl dependency is optional [Miklos Fazekas]
* agent_socket_factory option [Alon Goldboim]
* client sends KEXINIT, it doesn't have to wait for server [Miklos Fazekas]
* better error message when option is nil [Kane Morgan]
* prompting can be customized [Miklos Fazekas]
=== 4.0.0.alpha3
* added max_select_wait_time [Eugene Kenny]
=== 4.0.0.alpha2
* when transport closes we're cleaning up channels [Miklos Fazekas]
=== 4.0.0.alpha1
* ed25519 key support [Miklos Fazekas]
* removed camellia [Miklos Fazekas]
=== 3.1.0
=== 3.1.0.rc1
* fix Secure#verify [Jean Boussier]
* use the smallest of don't spend longer time than keepalive if it's configured [Eugene Kenny]
=== 3.1.0.beta3
* forward/on_open_failed should stop listning closed socket otherwise it locks #269 [Miklos Fazekas,Scott McGillivray]
* fix incorrect pattern handling in config files #310 [Miklos Fazekas]
=== 3.1.0.beta2
* trying to execute something on a not yet opend channel throws nicer messag [Miklos Fazekas]
* calling close on a not opened channel marks the channel for close [Miklos Fazekas]
* read keepalive configuration from ssh config files [Miklos Fazekas]
* send client version on hadshake before waiting for server to reduce handshake time [Miklos Fazekas]
* allow custom Net::SSH::KnownHosts implementations [Jean Boussier]
* memoize known host so we only search it once per session [Jean Boussier, Miklos Fazekas]
=== 3.0.2
=== 3.0.2.rc1
* fixed rare WaitWritable error with proxy commands [Miklos Fazkas, Andre Meij]]
* if Net::SSH.start user is nil and config has no entry we default to Etc.getlogin
* Bugfix: CHANNEL_CLOSE was sent before draining ouput buffer #280 [Christopher F. Auston]
=== 3.0.1
=== 3.0.1.rc1
* Breaking change from 2.* series: exec! without block now returns empty string instread of nil if command has no output [https://github.com/net-ssh/net-ssh/pull/273]
* Support remote_user as %r in proxy commands [Dominic Scheirlinck]
* Raise Net::SSH::ConnectionTimeout from connection timeout [Carl Hoerberg]
=== 3.0.0.rc1
* SemVer: Major version change because of dropping of ruby 1.9
=== 2.10.1.rc2
* Win: Use fiddle on ruby 2.1 too [Charlie Savage]
=== 2.10.1.rc1
* Added ruby 2.0 requirement to gemspec [Alex Schultz]
=== 2.10.0
=== 2.10.0-beta2
* Fix :passphrase option with :non_interactive [Jeremy Stanley]
* Use Socket.tcp with connect_timeout instead of Timeout::timeout [Carl Hörberg]
* Support for hostname hashes [Jef Mathiot]
* Ruby 1.9.3 is no longer supported but should moslty work expect for stuff like connect_timeout
=== 2.10.0-beta1
* Fix could not parse PKey error. [Andrey Voronkov]
* Workaround for threading issue in MRI + singleton method declaration [Matt Brictson]
* Configuration change: we no longer append all supported algorithms, this is so you can exclude insecure algorithms. If you want to use the old behaviour specify append_all_supported_algorithms => true [voidus, mfazekas]
* New configuration option: :non_interactive => true in case you prefer an authmethod to fail rather than prompt. [mfazekas]
* Configuration change: password will now ask for password up to the :number_of_password_prompts times. If you want the
2.9.1 behaviour of never asking password please set number_of_password_prompts to 0.
=== 2.9.4-beta1
* Use sysread and syswrite on Windows instead of read_nonblock and write [marc-etienne]
* Windows/peagant: use fiddle on ruby 2.2+/windows [Charlie Savage]
* Check if ssh key is a file [kiela]
=== 2.9.3
=== 2.9.2-rc3
* Remove advertised algorithms that were not working (curve25519-sha256@libssh.org) [mfazekas]
=== 2.9.2-rc2
* number_of_password_prompts is now accepted as ssh option, by setting it 0 net-ssh will not ask for password for password auth as with previous versions [mfazekas]
=== 2.9.2-rc1
* Documentation fixes and refactoring to keepalive [detiber, mfazekas]
=== 2.9.2-beta
* Remove advertised algorithms that were not working (ssh-rsa-cert-* *ed25519 acm*-gcm@openssh.com) [mfazekas]
* Unkown algorithms now ignored instead of failed [mfazekas]
* Configuration change: Asks for password with password auth (up to number_of_password_prompts) [mfazekas]
* Removed warnings [amatsuda]
=== 2.9.1 / 13 May 2014
* Fix for unknown response from agent on Windows with 64-bit PuTTY [chrahunt]
* Support negative patterns in host lookup from the SSH config file [nirvdrum]
=== 2.9.0 / 30 Apr 2014
* New ciphers [chr4]
* Added host keys: ssh-rsa-cert-v01@openssh.com ssh-rsa-cert-v00@openssh.com ssh-ed25519-cert-v01@openssh.com ssh-ed25519
* Added HMACs: hmac-sha2-512-etm@openssh.com hmac-sha2-256-etm@openssh.com umac-128-etm@openssh.com
* Added Kex: aes256-gcm@openssh.com aes128-gcm@openssh.com curve25519-sha256@libssh.org
* Added private key support for id_ed25519
* IdentiesOnly will not disable ssh_agent - fixes #148 and new fix for #137 [mfazekas]
* Ignore errors during ssh agent negotiation [simonswine, jasiek]
* Added an optional "options" argument to test socket open method [jefmathiot]
* Added gem signing (again) with new cert [delano]
=== 2.8.1 / 19 Feb 2014
* Correct location of global known_hosts files [mfischer-zd]
* Fix for password authentication [blackpond, zachlipton, delano]
=== 2.8.0 / 01 Feb 2014
* Handle ssh-rsa and ssh-dss certificate files [bobveznat]
* Correctly interpret /etc/ssh_config Authentication settings based on openssh /etc/ssh_config system defaults [therealjessesanford, liggitt]
* Fixed pageant support for Windows [jarredholman]
* Support %r in ProxyCommand configuration in ssh_config files as defined in OpenSSH [yugui]
* Don't use ssh-agent if :keys_only is true [SFEley]
* Fix the bug in keys with comments [bobtfish]
* Add a failing tests for options in pub keys [bobtfish]
* Assert that the return value from ssh block is returned [carlhoerberg]
* Don't close the connection it's already closed [carlhoerberg]
* Ensure the connection closes even on exception [carlhoerberg]
* Make the authentication error message more useful [deric]
* Fix "ConnectionError" typo in lib/net/ssh/proxy/socks5.rb [mirakui]
* Allow KeyManager to recover from incompatible agents [ecki, delano]
* Fix for "Authentication Method determination can pick up a class from the root namespace" [dave.sieh]
=== 2.7.0 / 11 Sep 2013
* Fix for 'Could not parse PKey: no start line' error on private keys with passphrases (issue #101) [metametaclass]
* Automatically forward environment variables defined in OpenSSH config files [fnordfish]
* Guard against socket.gets being nil in Net::SSH::Proxy::HTTP [krishicks]
* Implemented experimental keepalive feature [noric]
=== 2.6.8 / 6 Jul 2013
* Added support for host wildcard substitution [GabKlein]
* Added a wait to the loop in close to help fix possible blocks [Josh Kalderimis]
* Fixed test file encoding issues with Ruby 2.0 (#87) [voxik]
=== 2.6.7 / 11 Apr 2013
* Decreased default packet size to 32768 as described in RFC 4253 [Olipro]
* Added max_pkt_size and max_win_size options to Net::SSH.start [Olipro]
=== 2.6.6 / 03 Mar 2013
* Fix for ruby 2.0 in windows [jansegre]
=== 2.6.5 / 06 Feb 2013
* Fixed path in gemspec [thanks priteau]
=== 2.6.4 / 06 Feb 2013
* Added license info to gemspec [jordimassaguerpla]
* Added public cert. All gem releases are now signed.
=== 2.6.3 / 10 Jan 2013
* Small doc fix and correct error class for PKey::EC key type [Andreas Wolff]
* Improve test dependencies [Kenichi Kamiya]
=== 2.6.2 / 22 Nov 2012
* Net::SSH.start now returns result of block [mhuffnagle]
* Add stderr handling to Net::SSH::Test [ohrite]
* Fix Invalid key size in JRuby [ohrite]
=== 2.6.1 / 18 Oct 2012
* Remove platform specific jruby dependency from gemspec
* Changed encoding of file to prevent warnings when generating docs [iltempo]
=== 2.6.0 / 19 Sep 2012
* Use OpenSSL::PKey.read to read arbitrary private key. [nagachika]
* Check availability of UNIXSocket and UNIXServer for Windows [Nobuhiro IMAI]
* Bump version to 2.5.3 and depend on newer jruby-pageant version for Java 1.5 compat. [arturaz]
* Implementation of the "none"-authentication method [dubspeed]
* Add class for stricter host key verification [Andy Brody]
=== 2.5.2 / 25 May 2012
* Fix for Net::SSH::KnownHosts::SUPPORTED_TYPE [Marco Sandrini]
=== 2.5.1 / 24 May 2012
* Added missing file to manifest [Marco Sandrini]
=== 2.5.0 / 24 May 2012
* Implement many algorithms [Ryosuke Yamazaki]
* Key Exchange
* diffie-hellman-group14-sha1
* ecdh-sha2-nistp{256,384,521}
* Host Key
* ecdsa-sha2-nistp{256,384,521}
* Authentication
* ecdsa-sha2-nistp{256,384,521}
* HMAC
* hmac-ripemd160
* Cipher:
* aes{128,192,256}-ctr
* camellia{128,192,256}-ctr
* blowfish-ctr
* cast128-ctr
* 3des-ctr
* arcfour (has problems with weak keys, and should be used with caution)
* camellia{128,192,256}-cbc
=== 2.4.0 / 17 May 2012
* Support for JRuby + Pageant + Windows [arturaz]
=== 2.3.0 / 11 Jan 2012
* Support for hmac-sha2 and diffie-hellman-group-exchange-sha256 [Ryosuke Yamazaki]
=== 2.2.2 / 04 Jan 2012
* Fixed: Connection hangs on ServerVersion.new(socket, logger) [muffl0n]
* Avoid dying when unsupported auth mechanisms are defined [pcn]
=== 2.2.1 / 24 Aug 2011
* Do not prompt any passphrases before trying all identities from agent. [musybite]
(see: http://net-ssh.lighthouseapp.com/projects/36253-net-ssh/tickets/30)
=== 2.2.0 / 16 Aug 2011
* Add support for forward a local UNIX domain socket to a remote TCP socket. [Mark Imbriaco]
=== 2.1.4 / 3 Apr 2011
* Add ConnectionTimeout exception class. [Joel Watson]
See: https://github.com/net-ssh/net-ssh-multi/pull/1
=== 2.1.3 / 2 Mar 2011
* Call to transport.closed should be transport.close [Woon Jung]
=== 2.1.2 / 1 Mar 2011
* Fix for Net::SSH Continues to attempt authentication when notified it is not allowed [Eric Hodel]
(see: http://net-ssh.lighthouseapp.com/projects/36253-net-ssh/tickets/26)
* Fix for transport won't be closed if authentication fails [Patrick Marchi]
=== 2.1 / 19 Jan 2011
* Support "IdentitiesOnly" directive (LH-24) [Musy Bite, Edmund Haselwanter]
* Speeding up the Loggable module (LH-23) [robbebob]
=== 2.0.24 / 14 Jan 2011
* Fix for process code to correctly wait until remote_id is set before sending any output, including eof. [Daniel Pittman, Markus Roberts]
* Fix circular require warning in Ruby 1.9.2 [Gavin Brock]
=== 2.0.23 / 03 Jun 2010
* delay CHANNEL_EOF packet until output buffer is empty [Rich Lane]
Previously, calling #eof! after #send_data would result in the CHANNEL_EOF
packet being sent immediately, ahead of the data in the output buffer. Now
buffer becomes empty.
=== 2.0.22 / 20 Apr 2010
* Fix for: "Parsing the config errors out because it coerces the "1" into an integer and then tries to split it on spaces for multiple host checking." (http://net-ssh.lighthouseapp.com/projects/36253/tickets/10) [Lee Marlow]
=== 2.0.21 / 20 Mar 2010
* Fix for "IdentifyFile" in ~/.ssh/config does not work if no "Host" statement is given (http://net-ssh.lighthouseapp.com/projects/36253/tickets/9-identifyfile-in-sshconfig-does-not-work-if-no-host-statement-is-given#ticket-9-5) [xbaldauf, Delano Mandelbaum]
* Fix for client closes a forwarded connection, but the server is reading, net-ssh terminates with IOError socket closed (http://net-ssh.lighthouseapp.com/projects/36253/tickets/7) [Miklós Fazekas]
* Fix for client force closes (RST) a forwarded connection, but server is reading, net-ssh terminates with exception [Miklós Fazekas]
* Fix for server closes the sending side, the on_eof is not handled. [Miklós Fazekas]
* Removed Hanna dependency in Rakefile [Delano Mandelbaum]
=== 2.0.20 / 10 Feb 2010
* Support "ProxyCommand none" directive [Andy Lo-A-Foe]
=== 2.0.19 / 16 Jan 2010
* Support plus sign in sshconfig hostname [Jason Weathered]
=== 2.0.18 / 15 Jan 2010
* Fix related to #recv(1) to #readpartial change in 2.0.16 [Hans de Graaff, Delano Mandelbaum]
=== 2.0.17 / 14 Dec 2009
* Don't load net/ssh/authentication/pageant on Windows with Ruby 1.9 [Travis Reeder, Delano Mandelbaum]
=== 2.0.16 / 28 Nov 2009
* Fix for "multiple hosts are separated by whitespace" [Akinori MUSHA]
* Add support for the ProxyCommand directive [Akinori MUSHA]
* Switched from #recv(1) to #readpartial in lib/net/ssh/transport/server_version.rb, so that closed sockets are recognized [Alex Peuchert]
=== 2.0.15 / 03 Sep 2009
* Scale back IO#select patch so it mutexes only zero-timeout calls [Daniel Azuma, Will Bryant]
=== 2.0.14 / 28 Aug 2009
* Fix for IO#select threading bug in Ruby 1.8 (LH-1) [Daniel Azuma]
* Fix for "uninitialized constant OpenSSL::Digest::MD5" exception in Net::SFTP [DL Redden]
=== 2.0.13 / 17 Aug 2009
* Added fix for hanging in ServerVersion#negotiate! when using SOCKS5 proxy (GH-9) [Gerald Talton]
* Added support for specifying a list of hosts in .ssh/config, with tests (GH-6) [ckoehler, Delano Mandelbaum]
* Added tests for arcfour128/256/512 lengths, encryption, and decryption [Delano Mandelbaum]
* Skip packet stream tests for arcfour128/256/512 [Delano Mandelbaum]
* Fix for OpenSSL cipher key length because it always returns 16, even when 32 byte keys are required, e.g. for arcfour256 and arcfour512 ciphers [Karl Varga]
=== 2.0.12 / 08 Jun 2009
* Applied patch for arcfour128 and arcfour256 support [Denis Bernard]
* Use unbuffered reads when negotiating the protocol version [Steven Hazel]
=== 2.0.11 / 24 Feb 2009
* Add :key_data option for specifying raw private keys in PEM format [Alex Holems, Andrew Babkin]
=== 2.0.10 / 4 Feb 2009
* Added Net::SSH.configuration_for to make it easier to query the SSH configuration file(s) [Jamis Buck]
=== 2.0.9 / 1 Feb 2009
* Specifying non-nil user argument overrides user in .ssh/config [Jamis Buck]
* Ignore requests for non-existent channels (workaround ssh server bug) [Jamis Buck]
* Add terminate! method for hard shutdown scenarios [Jamis Buck]
* Revert to pre-2.0.7 key-loading behavior by default, but load private-key if public-key doesn't exist [Jamis Buck]
* Make sure :passphrase option gets passed to key manager [Bob Cotton]
=== 2.0.8 / 29 December 2008
* Fix private key change from 2.0.7 so that keys are loaded just-in-time, avoiding unecessary prompts from encrypted keys. [Jamis Buck]
=== 2.0.7 / 29 December 2008
* Make key manager use private keys instead of requiring public key to exist [arilerner@mac.com]
* Fix failing tests [arilerner@mac.com]
* Don't include pageant when running under JRuby [Angel N. Sciortino]
=== 2.0.6 / 6 December 2008
* Update the Manifest file so that the gem includes all necessary files [Jamis Buck]
=== 2.0.5 / 6 December 2008
* Make the Pageant interface comply with more of the Socket interface to avoid related errors [Jamis Buck]
* Don't busy-wait on session close for remaining channels to close [Will Bryant]
* Ruby 1.9 compatibility [Jamis Buck]
* Fix Cipher#final to correctly flag a need for a cipher reset [Jamis Buck]
=== 2.0.4 / 27 Aug 2008
* Added Connection::Session#closed? and Transport::Session#closed? [Jamis Buck]
* Numeric host names in .ssh/config are now parsed correct [Yanko Ivanov]
* Make sure the error raised when a public key file is malformed is more informative than a MethodMissing error [Jamis Buck]
* Cipher#reset is now called after Cipher#final, with the last n bytes used as the next initialization vector [Jamis Buck]
=== 2.0.3 / 27 Jun 2008
* Make Net::SSH::Version comparable [Brian Candler]
* Fix errors in port forwarding when a channel could not be opened due to a typo in the exception name [Matthew Todd]
* Use #chomp instead of #strip when cleaning the version string reported by the remote host, so that trailing whitespace is preserved (this is to play nice with servers like Mocana SSH) [Timo Gatsonides]
* Correctly parse ssh_config entries with eq-sign delimiters [Jamis Buck]
* Ignore malformed ssh_config entries [Jamis Buck]
=== 2.0.2 / 29 May 2008
* Make sure the agent client understands both RSA "identities answers" [Jamis Buck]
* Fixed key truncation bug that caused hmacs other than SHA1 to fail with "corrupt hmac" errors [Jamis Buck]
* Fix detection and loading of public keys when the keys don't actually exist [David Dollar]
=== 2.0.1 / 5 May 2008
* Teach Net::SSH about a handful of default key names [Jamis Buck]
=== 2.0.0 / 1 May 2008
* Allow the :verbose argument to accept symbols (:debug, etc.) as well as Logger level constants (Logger::DEBUG, etc.) [Jamis Buck]
=== 2.0 Preview Release 4 (1.99.3) / 19 Apr 2008
* Make sure HOME is set to something sane, even on OS's that don't set it by default [Jamis Buck]
* Add a :passphrase option to specify the passphrase to use with private keys [Francis Sullivan]
* Open a new auth agent connection for every auth-agent channel request [Jamis Buck]
=== 2.0 Preview Release 3 (1.99.2) / 10 Apr 2008
* Session properties [Jamis Buck]
* Make channel open failure work with a callback so that failures can be handled similarly to successes [Jamis Buck]
=== 2.0 Preview Release 2 (1.99.1) / 22 Mar 2008
* Partial support for ~/.ssh/config (and related) SSH configuration files [Daniel J. Berger, Jamis Buck]
* Added Net::SSH::Test to facilitate testing complex SSH state machines [Jamis Buck]
* Reworked Net::SSH::Prompt to use conditionally-selected modules [Jamis Buck, suggested by James Rosen]
* Added Channel#eof? and Channel#eof! [Jamis Buck]
* Fixed bug in strict host key verifier on cache miss [Mike Timm]
=== 2.0 Preview Release 1 (1.99.0) / 21 Aug 2007
* First preview release of Net::SSH v2
net-ssh-4.2.0/Gemfile 0000664 0000000 0000000 00000000616 13153765720 0014405 0 ustar 00root root 0000000 0000000 source 'https://rubygems.org'
# Specify your gem's dependencies in mygem.gemspec
gemspec
if !Gem.win_platform? && RUBY_ENGINE == "ruby"
gem 'byebug', group: [:development, :test]
end
if (Gem::Version.new(RUBY_VERSION) <=> Gem::Version.new("2.2.6")) < 0
gem 'rbnacl', '< 4.0'
end
if ENV["CI"]
gem 'codecov', require: false, group: :test
gem 'simplecov', require: false, group: :test
end
net-ssh-4.2.0/Gemfile.norbnacl 0000664 0000000 0000000 00000000402 13153765720 0016173 0 ustar 00root root 0000000 0000000 source 'https://rubygems.org'
ENV['NET_SSH_NO_RBNACL'] = 'true'
# Specify your gem's dependencies in mygem.gemspec
gemspec
if ENV["CI"] && !Gem.win_platform?
gem 'simplecov', require: false, group: :test
gem 'codecov', require: false, group: :test
end
net-ssh-4.2.0/Gemfile.norbnacl.lock 0000664 0000000 0000000 00000001333 13153765720 0017126 0 ustar 00root root 0000000 0000000 PATH
remote: .
specs:
net-ssh (4.0.0)
GEM
remote: https://rubygems.org/
specs:
ast (2.3.0)
metaclass (0.0.4)
minitest (5.10.1)
mocha (1.2.1)
metaclass (~> 0.0.1)
parser (2.3.3.1)
ast (~> 2.2)
powerpack (0.1.1)
rainbow (2.1.0)
rake (12.0.0)
rubocop (0.46.0)
parser (>= 2.3.1.1, < 3.0)
powerpack (~> 0.1)
rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1)
ruby-progressbar (1.8.1)
unicode-display_width (1.1.2)
PLATFORMS
ruby
x86-mingw32
DEPENDENCIES
bundler (~> 1.11)
minitest (~> 5.10)
mocha (>= 1.2.1)
net-ssh!
rake (~> 12.0)
rubocop (~> 0.46.0)
BUNDLED WITH
1.13.6
net-ssh-4.2.0/ISSUE_TEMPLATE.md 0000664 0000000 0000000 00000001171 13153765720 0015614 0 ustar 00root root 0000000 0000000 ### Expected behavior
Tell us what should happen
### Actual behavior
Tell us what happens instead.
### System configuration
- net-ssh version
- Ruby version
### Example App
Please provide an example script that reproduces the problem. This will save maintainers time so they can spend it fixing your issues instead of trying to build a reproduction case from sparse instructions.
You can use this as stating point:
```ruby
gem 'net-ssh', '= 4.0.0.beta3'
require 'net/ssh'
puts Net::SSH::Version::CURRENT
@host = 'localhost'
@user = ENV['USER']
Net::SSH.start(@host, @user) do |ssh|
puts ssh.exec!('echo "hello"')
end
```
net-ssh-4.2.0/LICENSE.txt 0000664 0000000 0000000 00000002045 13153765720 0014733 0 ustar 00root root 0000000 0000000 Copyright © 2008 Jamis Buck
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the ‘Software’), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
net-ssh-4.2.0/Manifest 0000664 0000000 0000000 00000010631 13153765720 0014601 0 ustar 00root root 0000000 0000000 CHANGELOG.rdoc
Manifest
README.rdoc
Rakefile
Rudyfile
THANKS.rdoc
lib/net/ssh.rb
lib/net/ssh/authentication/agent.rb
lib/net/ssh/authentication/constants.rb
lib/net/ssh/authentication/key_manager.rb
lib/net/ssh/authentication/methods/abstract.rb
lib/net/ssh/authentication/methods/hostbased.rb
lib/net/ssh/authentication/methods/keyboard_interactive.rb
lib/net/ssh/authentication/methods/password.rb
lib/net/ssh/authentication/methods/publickey.rb
lib/net/ssh/authentication/pageant.rb
lib/net/ssh/authentication/session.rb
lib/net/ssh/buffer.rb
lib/net/ssh/buffered_io.rb
lib/net/ssh/config.rb
lib/net/ssh/connection/channel.rb
lib/net/ssh/connection/constants.rb
lib/net/ssh/connection/session.rb
lib/net/ssh/connection/term.rb
lib/net/ssh/errors.rb
lib/net/ssh/key_factory.rb
lib/net/ssh/known_hosts.rb
lib/net/ssh/loggable.rb
lib/net/ssh/packet.rb
lib/net/ssh/prompt.rb
lib/net/ssh/proxy/command.rb
lib/net/ssh/proxy/errors.rb
lib/net/ssh/proxy/http.rb
lib/net/ssh/proxy/socks4.rb
lib/net/ssh/proxy/socks5.rb
lib/net/ssh/ruby_compat.rb
lib/net/ssh/service/forward.rb
lib/net/ssh/test.rb
lib/net/ssh/test/channel.rb
lib/net/ssh/test/extensions.rb
lib/net/ssh/test/kex.rb
lib/net/ssh/test/local_packet.rb
lib/net/ssh/test/packet.rb
lib/net/ssh/test/remote_packet.rb
lib/net/ssh/test/script.rb
lib/net/ssh/test/socket.rb
lib/net/ssh/transport/algorithms.rb
lib/net/ssh/transport/cipher_factory.rb
lib/net/ssh/transport/constants.rb
lib/net/ssh/transport/ctr.rb
lib/net/ssh/transport/hmac.rb
lib/net/ssh/transport/hmac/abstract.rb
lib/net/ssh/transport/hmac/md5.rb
lib/net/ssh/transport/hmac/md5_96.rb
lib/net/ssh/transport/hmac/none.rb
lib/net/ssh/transport/hmac/ripemd160.rb
lib/net/ssh/transport/hmac/sha1.rb
lib/net/ssh/transport/hmac/sha1_96.rb
lib/net/ssh/transport/hmac/sha2_256.rb
lib/net/ssh/transport/hmac/sha2_256_96.rb
lib/net/ssh/transport/hmac/sha2_512.rb
lib/net/ssh/transport/hmac/sha2_512_96.rb
lib/net/ssh/transport/identity_cipher.rb
lib/net/ssh/transport/key_expander.rb
lib/net/ssh/transport/kex.rb
lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb
lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb
lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb
lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb
lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb
lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb
lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb
lib/net/ssh/transport/openssl.rb
lib/net/ssh/transport/packet_stream.rb
lib/net/ssh/transport/server_version.rb
lib/net/ssh/transport/session.rb
lib/net/ssh/transport/state.rb
lib/net/ssh/verifiers/lenient.rb
lib/net/ssh/verifiers/null.rb
lib/net/ssh/verifiers/secure.rb
lib/net/ssh/verifiers/strict.rb
lib/net/ssh/version.rb
net-ssh.gemspec
setup.rb
support/arcfour_check.rb
support/ssh_tunnel_bug.rb
test/authentication/methods/common.rb
test/authentication/methods/test_abstract.rb
test/authentication/methods/test_hostbased.rb
test/authentication/methods/test_keyboard_interactive.rb
test/authentication/methods/test_password.rb
test/authentication/methods/test_publickey.rb
test/authentication/test_agent.rb
test/authentication/test_key_manager.rb
test/authentication/test_session.rb
test/common.rb
test/configs/eqsign
test/configs/exact_match
test/configs/host_plus
test/configs/multihost
test/configs/wild_cards
test/connection/test_channel.rb
test/connection/test_session.rb
test/test_all.rb
test/test_buffer.rb
test/test_buffered_io.rb
test/test_config.rb
test/test_key_factory.rb
test/transport/hmac/test_md5.rb
test/transport/hmac/test_md5_96.rb
test/transport/hmac/test_none.rb
test/transport/hmac/test_ripemd160.rb
test/transport/hmac/test_sha1.rb
test/transport/hmac/test_sha1_96.rb
test/transport/hmac/test_sha2_256.rb
test/transport/hmac/test_sha2_256_96.rb
test/transport/hmac/test_sha2_512.rb
test/transport/hmac/test_sha2_512_96.rb
test/transport/kex/test_diffie_hellman_group1_sha1.rb
test/transport/kex/test_diffie_hellman_group14_sha1.rb
test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb
test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb
test/transport/kex/test_ecdh_sha2_nistp256.rb
test/transport/kex/test_ecdh_sha2_nistp384.rb
test/transport/kex/test_ecdh_sha2_nistp521.rb
test/transport/test_algorithms.rb
test/transport/test_cipher_factory.rb
test/transport/test_hmac.rb
test/transport/test_identity_cipher.rb
test/transport/test_packet_stream.rb
test/transport/test_server_version.rb
test/transport/test_session.rb
test/transport/test_state.rb
net-ssh-4.2.0/README.rdoc 0000664 0000000 0000000 00000015243 13153765720 0014722 0 ustar 00root root 0000000 0000000 {
}[https://badge.fury.io/rb/net-ssh]
{
}[https://gitter.im/net-ssh/net-ssh?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge]
{
}[https://travis-ci.org/net-ssh/net-ssh]
{
}[https://codecov.io/gh/net-ssh/net-ssh]
= Net::SSH 4.x
* Docs: http://net-ssh.github.com/net-ssh
* Issues: https://github.com/net-ssh/net-ssh/issues
* Codes: https://github.com/net-ssh/net-ssh
* Email: net-ssh@solutious.com
As of v2.6.4, all gem releases are signed. See INSTALL.
== DESCRIPTION:
Net::SSH is a pure-Ruby implementation of the SSH2 client protocol. It allows you to write programs that invoke and interact with processes on remote servers, via SSH2.
== FEATURES:
* Execute processes on remote servers and capture their output
* Run multiple processes in parallel over a single SSH connection
* Support for SSH subsystems
* Forward local and remote ports via an SSH connection
== SYNOPSIS:
In a nutshell:
require 'net/ssh'
Net::SSH.start('host', 'user', :password => "password") do |ssh|
# capture all stderr and stdout output from a remote process
output = ssh.exec!("hostname")
puts output
# capture only stdout matching a particular pattern
stdout = ""
ssh.exec!("ls -l /home/jamis") do |channel, stream, data|
stdout << data if stream == :stdout
end
puts stdout
# run multiple processes in parallel to completion
ssh.exec "sed ..."
ssh.exec "awk ..."
ssh.exec "rm -rf ..."
ssh.loop
# open a new channel and configure a minimal set of callbacks, then run
# the event loop until the channel finishes (closes)
channel = ssh.open_channel do |ch|
ch.exec "/usr/local/bin/ruby /path/to/file.rb" do |ch, success|
raise "could not execute command" unless success
# "on_data" is called when the process writes something to stdout
ch.on_data do |c, data|
$stdout.print data
end
# "on_extended_data" is called when the process writes something to stderr
ch.on_extended_data do |c, type, data|
$stderr.print data
end
ch.on_close { puts "done!" }
end
end
channel.wait
# forward connections on local port 1234 to port 80 of www.capify.org
ssh.forward.local(1234, "www.capify.org", 80)
ssh.loop { true }
end
See Net::SSH for more documentation, and links to further information.
== REQUIREMENTS:
The only requirement you might be missing is the OpenSSL bindings for Ruby. These are built by default on most platforms, but you can verify that they're built and installed on your system by running the following command line:
ruby -ropenssl -e 'puts OpenSSL::OPENSSL_VERSION'
If that spits out something like "OpenSSL 0.9.8g 19 Oct 2007", then you're set. If you get an error, then you'll need to see about rebuilding ruby with OpenSSL support, or (if your platform supports it) installing the OpenSSL bindings separately.
Lastly, if you want to run the tests or use any of the Rake tasks, you'll need Mocha and other dependencies listed in Gemfile
== INSTALL:
* gem install net-ssh (might need sudo privileges)
NOTE: If you are running on jruby on windows you need to install jruby-pageant manually (gemspec doesn't allow for platform specific dependencies).
However, in order to be sure the code you're installing hasn't been tampered with, it's recommended that you verify the signature[http://docs.rubygems.org/read/chapter/21]. To do this, you need to add my public key as a trusted certificate (you only need to do this once):
# Add the public key as a trusted certificate
# (You only need to do this once)
$ curl -O https://raw.githubusercontent.com/net-ssh/net-ssh/master/net-ssh-public_cert.pem
$ gem cert --add net-ssh-public_cert.pem
Then, when install the gem, do so with high security:
$ gem install net-ssh -P HighSecurity
If you don't add the public key, you'll see an error like "Couldn't verify data signature". If you're still having trouble let me know and I'll give you a hand.
For ed25519 public key auth support your bundle file should contain ```rbnacl-libsodium```, ```rbnacl```, ```bcrypt_pbkdf``` dependencies.
== RUBY SUPPORT
* Ruby 1.8.x is supported up until the net-ssh 2.5.1 release.
* Ruby 1.9.x is supported up until the net-ssh 2.9.x release.
* Current net-ssh releases require Ruby 2.0 or later.
== RUNNING TESTS
Run the test suite from the net-ssh directory with the following command:
bundle exec rake test
Run a single test file like this:
ruby -Ilib -Itest test/transport/test_server_version.rb
To run integration tests see test/integration/README.txt
=== BUILDING GEM
rake build
=== GEM SIGNING (for maintainers)
If you have the net-ssh private signing key, you will be able to create signed release builds. Make sure the private key path matches the `signing_key` path set in `net-ssh.gemspec` and tell rake to sign the gem by setting the `NET_SSH_BUILDGEM_SIGNED` flag:
NET_SSH_BUILDGEM_SIGNED=true rake build
For time to time, the public certificate associated to the private key needs to be renewed. You can do this with the following command:
gem cert --build netssh@solutious.com --private-key path/2/net-ssh-private_key.pem
mv gem-public_cert.pem net-ssh-public_cert.pem
gem cert --add net-ssh-public_cert.pem
== LICENSE:
(The MIT License)
Copyright (c) 2008 Jamis Buck
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
net-ssh-4.2.0/Rakefile 0000664 0000000 0000000 00000005356 13153765720 0014565 0 ustar 00root root 0000000 0000000 # coding: UTF-8
#
# Also in your terminal environment run:
# $ export LANG=en_US.UTF-8
# $ export LANGUAGE=en_US.UTF-8
# $ export LC_ALL=en_US.UTF-8
require "rubygems"
require "rake"
require "rake/clean"
require "bundler/gem_tasks"
require "rdoc/task"
desc "When releasing make sure NET_SSH_BUILDGEM_SIGNED is set"
task :check_NET_SSH_BUILDGEM_SIGNED do
raise "NET_SSH_BUILDGEM_SIGNED should be set to release" unless ENV['NET_SSH_BUILDGEM_SIGNED']
end
Rake::Task[:release].enhance [:check_NET_SSH_BUILDGEM_SIGNED]
Rake::Task[:release].prerequisites.unshift(:check_NET_SSH_BUILDGEM_SIGNED)
task default: ["build"]
CLEAN.include [ 'pkg', 'rdoc' ]
name = "net-ssh"
require_relative "lib/net/ssh/version"
version = Net::SSH::Version::CURRENT
extra_files = %w[LICENSE.txt THANKS.txt CHANGES.txt]
RDoc::Task.new do |rdoc|
rdoc.rdoc_dir = "rdoc"
rdoc.title = "#{name} #{version}"
rdoc.generator = 'hanna' # gem install hanna-nouveau
rdoc.main = 'README.rdoc'
rdoc.rdoc_files.include("README*")
rdoc.rdoc_files.include("bin/*.rb")
rdoc.rdoc_files.include("lib/**/*.rb")
extra_files.each { |file|
rdoc.rdoc_files.include(file) if File.exists?(file)
}
end
namespace :rdoc do
desc "Update gh-pages branch"
task :publish do
# copy/checkout
rm_rf "/tmp/net-ssh-rdoc"
rm_rf "/tmp/net-ssh-gh-pages"
cp_r "./rdoc", "/tmp/net-ssh-rdoc"
mkdir "/tmp/net-ssh-gh-pages"
Dir.chdir "/tmp/net-ssh-gh-pages" do
sh "git clone --branch gh-pages --single-branch https://github.com/net-ssh/net-ssh"
rm_rf "/tmp/net-ssh-gh-pages/net-ssh/*"
end
# update
sh "cp -rf ./rdoc/* /tmp/net-ssh-gh-pages/net-ssh/"
Dir.chdir "/tmp/net-ssh-gh-pages/net-ssh" do
sh "git add -A ."
sh "git commit -m \"Update docs\""
end
# publish
Dir.chdir "/tmp/net-ssh-gh-pages/net-ssh" do
sh "git push origin gh-pages"
end
end
end
require 'rake/testtask'
Rake::TestTask.new do |t|
t.libs = ["lib", "test"]
t.libs << "test/integration" if ENV['NET_SSH_RUN_INTEGRATION_TESTS']
t.libs << "test/win_integration" if ENV['NET_SSH_RUN_WIN_INTEGRATION_TESTS']
test_files = FileList['test/**/test_*.rb']
test_files -= FileList['test/integration/**/test_*.rb'] unless ENV['NET_SSH_RUN_INTEGRATION_TESTS']
test_files -= FileList['test/win_integration/**/test_*.rb'] unless ENV['NET_SSH_RUN_WIN_INTEGRATION_TESTS']
test_files -= FileList['test/manual/test_*.rb']
test_files -= FileList['test/test_pageant.rb']
test_files -= FileList['test/test/**/test_*.rb']
t.test_files = test_files
end
desc "Run tests of Net::SSH:Test"
Rake::TestTask.new do |t|
t.name = "test_test"
# we need to run test/test separatedly as it hacks io + other modules
t.libs = ["lib", "test"]
test_files = FileList['test/test/**/test_*.rb']
t.test_files = test_files
end
net-ssh-4.2.0/THANKS.txt 0000664 0000000 0000000 00000003436 13153765720 0014646 0 ustar 00root root 0000000 0000000 Net::SSH was originally written by Jamis Buck . It
is currently maintained by Delano Mandelbaum . In
addition, the following individuals are gratefully acknowledged for their
contributions:
GOTOU Yuuzou
* help and code related to OpenSSL
Guillaume Marçais
* support for communicating with the the PuTTY "pageant" process
Daniel Berger
* help getting unit tests in earlier Net::SSH versions to pass in Windows
* initial version of Net::SSH::Config provided inspiration and encouragement
Chris Andrews and Lee Jensen
* support for ssh agent forwarding
Hiroshi Nakamura
* fixed errors with JRuby tests
bobveznat
therealjessesanford
liggitt
jarredholman
yugui
SFEley
bobtfish
carlhoerberg
deric
mirakui
ecki
Dave Sieh
metametaclass
fnordfish
krishicks
noric
GabKlein
Josh Kalderimis
voxik
Olipro
jansegre
priteau
jordimassaguerpla
Kenichi Kamiya
Andreas Wolff
mhuffnagle
ohrite
iltempo
nagachika
Nobuhiro IMAI
arturaz
dubspeed
Andy Brody
Marco Sandrini
Ryosuke Yamazaki
muffl0n
pcn
musybite
Mark Imbriaco
Joel Watson
Woon Jung
Edmund Haselwanter
robbebob
Daniel Pittman
Markus Roberts
Gavin Brock
Rich Lane
Lee Marlow
xbaldauf
Delano Mandelbaum
Miklós Fazekas
Andy Lo-A-Foe
Jason Weathered
Hans de Graaff
Travis Reeder
Akinori MUSHA
Alex Peuchert
Daniel Azuma
Will Bryant
Gerald Talton
ckoehler
Karl Varga
Denis Bernard
Steven Hazel
Alex Holems
Andrew Babkin
Bob Cotton
Yanko Ivanov
Angel N. Sciortino
arilerner@mac.com
David Dollar
Timo Gatsonides
Matthew Todd
Brian Candler
Francis Sullivan
James Rosen
Mike Timm
guns
devrandom
kachick
Pablo Merino
thedarkone
czarneckid
jbarnette
watsonian
Grant Hutchins
Michael Schubert
mtrudel
Aurélien Derouineau
net-ssh-4.2.0/appveyor.yml 0000664 0000000 0000000 00000003514 13153765720 0015502 0 ustar 00root root 0000000 0000000 version: '{build}'
skip_tags: true
environment:
matrix:
- ruby_version: "jruby-9.1.2.0"
- ruby_version: "23"
- ruby_version: "23-x64"
- ruby_version: "22-x64"
matrix:
allow_failures:
- ruby_version: "jruby-9.1.2.0"
#init:
# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
#on_finish:
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
platform:
- x86
install:
- SET PATH=C:\Ruby%ruby_version%\bin;%PATH%
- if "%ruby_version%" == "jruby-9.1.2.0" ( cinst javaruntime -i )
- if "%ruby_version%" == "jruby-9.1.2.0" ( cinst jruby --version 9.1.2.0 -i --allow-empty-checksums )
- if "%ruby_version%" == "jruby-9.1.2.0" ( SET "PATH=C:\jruby-9.1.2.0\bin\;%PATH%" )
- ruby --version
- gem install bundler --no-document -v 1.13.5
- SET BUNDLE_GEMFILE=Gemfile.norbnacl
- bundle _1.13.5_ install --retry=3
- cinst freesshd
- cinst putty --allow-empty-checksums
- ps: |
if ($env:Processor_Architecture -eq "x86")
{
dir 'C:\Program Files\'
dir 'C:\Program Files\freeSSHd'
cp 'test\win_integration\FreeSSHDService.ini' 'C:\Program Files\freeSSHd\FreeSSHDService.ini'
& 'C:\Program Files\freeSSHd\FreeSSHDService.exe'
} else {
dir 'C:\Program Files (x86)\'
dir 'C:\Program Files (x86)\freeSSHd'
cp 'test\win_integration\FreeSSHDService32.ini' 'C:\Program Files (x86)\freeSSHd\FreeSSHDService.ini'
& 'C:\Program Files (x86)\freeSSHd\FreeSSHDService.exe'
}
test_script:
- SET BUNDLE_GEMFILE=Gemfile.norbnacl
- SET NET_SSH_RUN_WIN_INTEGRATION_TESTS=YES
- bundle _1.13.5_ exec rake test
build: off
net-ssh-4.2.0/lib/ 0000775 0000000 0000000 00000000000 13153765720 0013655 5 ustar 00root root 0000000 0000000 net-ssh-4.2.0/lib/net/ 0000775 0000000 0000000 00000000000 13153765720 0014443 5 ustar 00root root 0000000 0000000 net-ssh-4.2.0/lib/net/ssh.rb 0000664 0000000 0000000 00000035450 13153765720 0015574 0 ustar 00root root 0000000 0000000 # Make sure HOME is set, regardless of OS, so that File.expand_path works
# as expected with tilde characters.
ENV['HOME'] ||= ENV['HOMEPATH'] ? "#{ENV['HOMEDRIVE']}#{ENV['HOMEPATH']}" : Dir.pwd
require 'logger'
require 'etc'
require 'net/ssh/config'
require 'net/ssh/errors'
require 'net/ssh/loggable'
require 'net/ssh/transport/session'
require 'net/ssh/authentication/session'
require 'net/ssh/connection/session'
require 'net/ssh/prompt'
module Net
# Net::SSH is a library for interacting, programmatically, with remote
# processes via the SSH2 protocol. Sessions are always initiated via
# Net::SSH.start. From there, a program interacts with the new SSH session
# via the convenience methods on Net::SSH::Connection::Session, by opening
# and interacting with new channels (Net::SSH::Connection:Session#open_channel
# and Net::SSH::Connection::Channel), or by forwarding local and/or
# remote ports through the connection (Net::SSH::Service::Forward).
#
# The SSH protocol is very event-oriented. Requests are sent from the client
# to the server, and are answered asynchronously. This gives great flexibility
# (since clients can have multiple requests pending at a time), but it also
# adds complexity. Net::SSH tries to manage this complexity by providing
# some simpler methods of synchronous communication (see Net::SSH::Connection::Session#exec!).
#
# In general, though, and if you want to do anything more complicated than
# simply executing commands and capturing their output, you'll need to use
# channels (Net::SSH::Connection::Channel) to build state machines that are
# executed while the event loop runs (Net::SSH::Connection::Session#loop).
#
# Net::SSH::Connection::Session and Net::SSH::Connection::Channel have more
# information about this technique.
#
# = "Um, all I want to do is X, just show me how!"
#
# == X == "execute a command and capture the output"
#
# Net::SSH.start("host", "user", password: "password") do |ssh|
# result = ssh.exec!("ls -l")
# puts result
# end
#
# == X == "forward connections on a local port to a remote host"
#
# Net::SSH.start("host", "user", password: "password") do |ssh|
# ssh.forward.local(1234, "www.google.com", 80)
# ssh.loop { true }
# end
#
# == X == "forward connections on a remote port to the local host"
#
# Net::SSH.start("host", "user", password: "password") do |ssh|
# ssh.forward.remote(80, "www.google.com", 1234)
# ssh.loop { true }
# end
module SSH
# This is the set of options that Net::SSH.start recognizes. See
# Net::SSH.start for a description of each option.
VALID_OPTIONS = [
:auth_methods, :bind_address, :compression, :compression_level, :config,
:encryption, :forward_agent, :hmac, :host_key, :remote_user,
:keepalive, :keepalive_interval, :keepalive_maxcount, :kex, :keys, :key_data,
:languages, :logger, :paranoid, :password, :port, :proxy,
:rekey_blocks_limit,:rekey_limit, :rekey_packet_limit, :timeout, :verbose,
:known_hosts, :global_known_hosts_file, :user_known_hosts_file, :host_key_alias,
:host_name, :user, :properties, :passphrase, :keys_only, :max_pkt_size,
:max_win_size, :send_env, :use_agent, :number_of_password_prompts,
:append_all_supported_algorithms, :non_interactive, :password_prompt,
:agent_socket_factory, :minimum_dh_bits, :verify_host_key
]
# The standard means of starting a new SSH connection. When used with a
# block, the connection will be closed when the block terminates, otherwise
# the connection will just be returned. The yielded (or returned) value
# will be an instance of Net::SSH::Connection::Session (q.v.). (See also
# Net::SSH::Connection::Channel and Net::SSH::Service::Forward.)
#
# Net::SSH.start("host", "user") do |ssh|
# ssh.exec! "cp /some/file /another/location"
# hostname = ssh.exec!("hostname")
#
# ssh.open_channel do |ch|
# ch.exec "sudo -p 'sudo password: ' ls" do |ch, success|
# abort "could not execute sudo ls" unless success
#
# ch.on_data do |ch, data|
# print data
# if data =~ /sudo password: /
# ch.send_data("password\n")
# end
# end
# end
# end
#
# ssh.loop
# end
#
# This method accepts the following options (all are optional):
#
# * :auth_methods => an array of authentication methods to try
# * :bind_address => the IP address on the connecting machine to use in
# establishing connection. (:bind_address is discarded if :proxy
# is set.)
# * :compression => the compression algorithm to use, or +true+ to use
# whatever is supported.
# * :compression_level => the compression level to use when sending data
# * :config => set to +true+ to load the default OpenSSH config files
# (~/.ssh/config, /etc/ssh_config), or to +false+ to not load them, or to
# a file-name (or array of file-names) to load those specific configuration
# files. Defaults to +true+.
# * :encryption => the encryption cipher (or ciphers) to use
# * :forward_agent => set to true if you want the SSH agent connection to
# be forwarded
# * :known_hosts => a custom object holding known hosts records.
# It must implement #search_for and add in a similiar manner as KnownHosts.
# * :global_known_hosts_file => the location of the global known hosts
# file. Set to an array if you want to specify multiple global known
# hosts files. Defaults to %w(/etc/ssh/ssh_known_hosts /etc/ssh/ssh_known_hosts2).
# * :hmac => the hmac algorithm (or algorithms) to use
# * :host_key => the host key algorithm (or algorithms) to use
# * :host_key_alias => the host name to use when looking up or adding a
# host to a known_hosts dictionary file
# * :host_name => the real host name or IP to log into. This is used
# instead of the +host+ parameter, and is primarily only useful when
# specified in an SSH configuration file. It lets you specify an
# "alias", similarly to adding an entry in /etc/hosts but without needing
# to modify /etc/hosts.
# * :keepalive => set to +true+ to send a keepalive packet to the SSH server
# when there's no traffic between the SSH server and Net::SSH client for
# the keepalive_interval seconds. Defaults to +false+.
# * :keepalive_interval => the interval seconds for keepalive.
# Defaults to +300+ seconds.
# * :keepalive_maxcount => the maximun number of keepalive packet miss allowed.
# Defaults to 3
# * :kex => the key exchange algorithm (or algorithms) to use
# * :keys => an array of file names of private keys to use for publickey
# and hostbased authentication
# * :key_data => an array of strings, with each element of the array being
# a raw private key in PEM format.
# * :keys_only => set to +true+ to use only private keys from +keys+ and
# +key_data+ parameters, even if ssh-agent offers more identities. This
# option is intended for situations where ssh-agent offers many different
# identites.
# * :logger => the logger instance to use when logging
# * :max_pkt_size => maximum size we tell the other side that is supported per
# packet. Default is 0x8000 (32768 bytes). Increase to 0x10000 (65536 bytes)
# for better performance if your SSH server supports it (most do).
# * :max_win_size => maximum size we tell the other side that is supported for
# the window.
# * :non_interactive => set to true if your app is non interactive and prefers
# authentication failure vs password prompt. Non-interactive applications
# should set it to true to prefer failing a password/etc auth methods vs.
# asking for password.
# * :paranoid => deprecated alias for :verify_host_key
# * :passphrase => the passphrase to use when loading a private key (default
# is +nil+, for no passphrase)
# * :password => the password to use to login
# * :port => the port to use when connecting to the remote host
# * :properties => a hash of key/value pairs to add to the new connection's
# properties (see Net::SSH::Connection::Session#properties)
# * :proxy => a proxy instance (see Proxy) to use when connecting
# * :rekey_blocks_limit => the max number of blocks to process before rekeying
# * :rekey_limit => the max number of bytes to process before rekeying
# * :rekey_packet_limit => the max number of packets to process before rekeying
# * :send_env => an array of local environment variable names to export to the
# remote environment. Names may be given as String or Regexp.
# * :timeout => how long to wait for the initial connection to be made
# * :user => the user name to log in as; this overrides the +user+
# parameter, and is primarily only useful when provided via an SSH
# configuration file.
# * :remote_user => used for substitution into the '%r' part of a ProxyCommand
# * :user_known_hosts_file => the location of the user known hosts file.
# Set to an array to specify multiple user known hosts files.
# Defaults to %w(~/.ssh/known_hosts ~/.ssh/known_hosts2).
# * :use_agent => Set false to disable the use of ssh-agent. Defaults to
# true
# * :verbose => how verbose to be (Logger verbosity constants, Logger::DEBUG
# is very verbose, Logger::FATAL is all but silent). Logger::FATAL is the
# default. The symbols :debug, :info, :warn, :error, and :fatal are also
# supported and are translated to the corresponding Logger constant.
# * :append_all_supported_algorithms => set to +true+ to append all supported
# algorithms by net-ssh. Was the default behaviour until 2.10
# * :number_of_password_prompts => Number of prompts for the password
# authentication method defaults to 3 set to 0 to disable prompt for
# password auth method
# * :password_prompt => a custom prompt object with ask method. See Net::SSH::Prompt
#
# * :agent_socket_factory => enables the user to pass a lambda/block that will serve as the socket factory
# Net::SSH::start(user,host,agent_socket_factory: ->{ UNIXSocket.open('/foo/bar') })
# example: ->{ UNIXSocket.open('/foo/bar')}
# * :verify_host_key => either false, true, :very, or :secure specifying how
# strict host-key verification should be (in increasing order here).
# You can also provide an own Object which responds to +verify+. The argument
# given to +verify+ is a hash consisting of the +:key+, the +:key_blob+,
# the +:fingerprint+ and the +:session+. Returning true accepts the host key,
# returning false declines it and closes the connection.
#
# If +user+ parameter is nil it defaults to USER from ssh_config, or
# local username
def self.start(host, user=nil, options={}, &block)
invalid_options = options.keys - VALID_OPTIONS
if invalid_options.any?
raise ArgumentError, "invalid option(s): #{invalid_options.join(', ')}"
end
assign_defaults(options)
_sanitize_options(options)
options[:user] = user if user
options = configuration_for(host, options.fetch(:config, true)).merge(options)
host = options.fetch(:host_name, host)
if options[:non_interactive]
options[:number_of_password_prompts] = 0
end
_support_deprecated_option_paranoid(options)
if options[:verbose]
options[:logger].level = case options[:verbose]
when Integer then options[:verbose]
when :debug then Logger::DEBUG
when :info then Logger::INFO
when :warn then Logger::WARN
when :error then Logger::ERROR
when :fatal then Logger::FATAL
else raise ArgumentError, "can't convert #{options[:verbose].inspect} to any of the Logger level constants"
end
end
transport = Transport::Session.new(host, options)
auth = Authentication::Session.new(transport, options)
user = options.fetch(:user, user) || Etc.getlogin
if auth.authenticate("ssh-connection", user, options[:password])
connection = Connection::Session.new(transport, options)
if block_given?
begin
yield connection
ensure
connection.close unless connection.closed?
end
else
return connection
end
else
transport.close
raise AuthenticationFailed, "Authentication failed for user #{user}@#{host}"
end
end
# Returns a hash of the configuration options for the given host, as read
# from the SSH configuration file(s). If +use_ssh_config+ is true (the
# default), this will load configuration from both ~/.ssh/config and
# /etc/ssh_config. If +use_ssh_config+ is nil or false, nothing will be
# loaded (and an empty hash returned). Otherwise, +use_ssh_config+ may
# be a file name (or array of file names) of SSH configuration file(s)
# to read.
#
# See Net::SSH::Config for the full description of all supported options.
def self.configuration_for(host, use_ssh_config)
files = case use_ssh_config
when true then Net::SSH::Config.expandable_default_files
when false, nil then return {}
else Array(use_ssh_config)
end
Net::SSH::Config.for(host, files)
end
def self.assign_defaults(options)
if !options[:logger]
options[:logger] = Logger.new(STDERR)
options[:logger].level = Logger::FATAL
end
options[:password_prompt] ||= Prompt.default(options)
[:password, :passphrase].each do |key|
options.delete(key) if options.key?(key) && options[key].nil?
end
end
def self._sanitize_options(options)
invalid_option_values = [nil,[nil]]
unless (options.values & invalid_option_values).empty?
nil_options = options.select { |_k,v| invalid_option_values.include?(v) }.map(&:first)
Kernel.warn "#{caller_locations(2, 1)[0]}: Passing nil, or [nil] to Net::SSH.start is deprecated for keys: #{nil_options.join(', ')}"
end
end
private_class_method :_sanitize_options
def self._support_deprecated_option_paranoid(options)
if options.key?(:paranoid)
Kernel.warn(
":paranoid is deprecated, please use :verify_host_key. Supported " \
"values are exactly the same, only the name of the option has changed."
)
if options.key?(:verify_host_key)
Kernel.warn(
"Both :paranoid and :verify_host_key were specified. " \
":verify_host_key takes precedence, :paranoid will be ignored."
)
else
options[:verify_host_key] = options.delete(:paranoid)
end
end
end
private_class_method :_support_deprecated_option_paranoid
end
end
net-ssh-4.2.0/lib/net/ssh/ 0000775 0000000 0000000 00000000000 13153765720 0015240 5 ustar 00root root 0000000 0000000 net-ssh-4.2.0/lib/net/ssh/authentication/ 0000775 0000000 0000000 00000000000 13153765720 0020257 5 ustar 00root root 0000000 0000000 net-ssh-4.2.0/lib/net/ssh/authentication/agent.rb 0000664 0000000 0000000 00000024503 13153765720 0021706 0 ustar 00root root 0000000 0000000 require 'net/ssh/buffer'
require 'net/ssh/errors'
require 'net/ssh/loggable'
require 'net/ssh/transport/server_version'
require 'socket'
require 'rubygems'
require 'net/ssh/authentication/pageant' if Gem.win_platform? && RUBY_PLATFORM != "java"
module Net; module SSH; module Authentication
# Class for representing agent-specific errors.
class AgentError < Net::SSH::Exception; end
# An exception for indicating that the SSH agent is not available.
class AgentNotAvailable < AgentError; end
# This class implements a simple client for the ssh-agent protocol. It
# does not implement any specific protocol, but instead copies the
# behavior of the ssh-agent functions in the OpenSSH library (3.8).
#
# This means that although it behaves like a SSH1 client, it also has
# some SSH2 functionality (like signing data).
class Agent
include Loggable
# A simple module for extending keys, to allow comments to be specified
# for them.
module Comment
attr_accessor :comment
end
SSH2_AGENT_REQUEST_VERSION = 1
SSH2_AGENT_REQUEST_IDENTITIES = 11
SSH2_AGENT_IDENTITIES_ANSWER = 12
SSH2_AGENT_SIGN_REQUEST = 13
SSH2_AGENT_SIGN_RESPONSE = 14
SSH2_AGENT_ADD_IDENTITY = 17
SSH2_AGENT_REMOVE_IDENTITY = 18
SSH2_AGENT_REMOVE_ALL_IDENTITIES = 19
SSH2_AGENT_ADD_ID_CONSTRAINED = 25
SSH2_AGENT_FAILURE = 30
SSH2_AGENT_VERSION_RESPONSE = 103
SSH_COM_AGENT2_FAILURE = 102
SSH_AGENT_REQUEST_RSA_IDENTITIES = 1
SSH_AGENT_RSA_IDENTITIES_ANSWER1 = 2
SSH_AGENT_RSA_IDENTITIES_ANSWER2 = 5
SSH_AGENT_FAILURE = 5
SSH_AGENT_SUCCESS = 6
SSH_AGENT_CONSTRAIN_LIFETIME = 1
SSH_AGENT_CONSTRAIN_CONFIRM = 2
SSH_AGENT_RSA_SHA2_256 = 0x02
SSH_AGENT_RSA_SHA2_512 = 0x04
# The underlying socket being used to communicate with the SSH agent.
attr_reader :socket
# Instantiates a new agent object, connects to a running SSH agent,
# negotiates the agent protocol version, and returns the agent object.
def self.connect(logger=nil, agent_socket_factory = nil)
agent = new(logger)
agent.connect!(agent_socket_factory)
agent.negotiate!
agent
end
# Creates a new Agent object, using the optional logger instance to
# report status.
def initialize(logger=nil)
self.logger = logger
end
# Connect to the agent process using the socket factory and socket name
# given by the attribute writers. If the agent on the other end of the
# socket reports that it is an SSH2-compatible agent, this will fail
# (it only supports the ssh-agent distributed by OpenSSH).
def connect!(agent_socket_factory = nil)
debug { "connecting to ssh-agent" }
@socket =
if agent_socket_factory
agent_socket_factory.call
elsif ENV['SSH_AUTH_SOCK'] && unix_socket_class
unix_socket_class.open(ENV['SSH_AUTH_SOCK'])
elsif Gem.win_platform? && RUBY_ENGINE != "jruby"
Pageant::Socket.open
else
raise AgentNotAvailable, "Agent not configured"
end
rescue StandardError => e
error { "could not connect to ssh-agent: #{e.message}" }
raise AgentNotAvailable, $!.message
end
# Attempts to negotiate the SSH agent protocol version. Raises an error
# if the version could not be negotiated successfully.
def negotiate!
# determine what type of agent we're communicating with
type, body = send_and_wait(SSH2_AGENT_REQUEST_VERSION, :string, Transport::ServerVersion::PROTO_VERSION)
raise AgentNotAvailable, "SSH2 agents are not yet supported" if type == SSH2_AGENT_VERSION_RESPONSE
if type == SSH2_AGENT_FAILURE
debug { "Unexpected response type==#{type}, this will be ignored" }
elsif type != SSH_AGENT_RSA_IDENTITIES_ANSWER1 && type != SSH_AGENT_RSA_IDENTITIES_ANSWER2
raise AgentNotAvailable, "unknown response from agent: #{type}, #{body.to_s.inspect}"
end
end
# Return an array of all identities (public keys) known to the agent.
# Each key returned is augmented with a +comment+ property which is set
# to the comment returned by the agent for that key.
def identities
type, body = send_and_wait(SSH2_AGENT_REQUEST_IDENTITIES)
raise AgentError, "could not get identity count" if agent_failed(type)
raise AgentError, "bad authentication reply: #{type}" if type != SSH2_AGENT_IDENTITIES_ANSWER
identities = []
body.read_long.times do
key_str = body.read_string
comment_str = body.read_string
begin
key = Buffer.new(key_str).read_key
key.extend(Comment)
key.comment = comment_str
identities.push key
rescue NotImplementedError => e
error { "ignoring unimplemented key:#{e.message} #{comment_str}" }
end
end
return identities
end
# Closes this socket. This agent reference is no longer able to
# query the agent.
def close
@socket.close
end
# Using the agent and the given public key, sign the given data. The
# signature is returned in SSH2 format.
def sign(key, data, flags = 0)
type, reply = send_and_wait(SSH2_AGENT_SIGN_REQUEST, :string, Buffer.from(:key, key), :string, data, :long, flags)
raise AgentError, "agent could not sign data with requested identity" if agent_failed(type)
raise AgentError, "bad authentication response #{type}" if type != SSH2_AGENT_SIGN_RESPONSE
return reply.read_string
end
# Adds the private key with comment to the agent.
# If lifetime is given, the key will automatically be removed after lifetime
# seconds.
# If confirm is true, confirmation will be required for each agent signing
# operation.
def add_identity(priv_key, comment, lifetime: nil, confirm: false)
constraints = Buffer.new
if lifetime
constraints.write_byte(SSH_AGENT_CONSTRAIN_LIFETIME)
constraints.write_long(lifetime)
end
constraints.write_byte(SSH_AGENT_CONSTRAIN_CONFIRM) if confirm
req_type = constraints.empty? ? SSH2_AGENT_ADD_IDENTITY : SSH2_AGENT_ADD_ID_CONSTRAINED
type, = send_and_wait(req_type, :string, priv_key.ssh_type, :raw, blob_for_add(priv_key),
:string, comment, :raw, constraints)
raise AgentError, "could not add identity to agent" if type != SSH_AGENT_SUCCESS
end
# Removes key from the agent.
def remove_identity(key)
type, = send_and_wait(SSH2_AGENT_REMOVE_IDENTITY, :string, key.to_blob)
raise AgentError, "could not remove identity from agent" if type != SSH_AGENT_SUCCESS
end
# Removes all identities from the agent.
def remove_all_identities
type, = send_and_wait(SSH2_AGENT_REMOVE_ALL_IDENTITIES)
raise AgentError, "could not remove all identity from agent" if type != SSH_AGENT_SUCCESS
end
private
def unix_socket_class
defined?(UNIXSocket) && UNIXSocket
end
# Send a new packet of the given type, with the associated data.
def send_packet(type, *args)
buffer = Buffer.from(*args)
data = [buffer.length + 1, type.to_i, buffer.to_s].pack("NCA*")
debug { "sending agent request #{type} len #{buffer.length}" }
@socket.send data, 0
end
# Read the next packet from the agent. This will return a two-part
# tuple consisting of the packet type, and the packet's body (which
# is returned as a Net::SSH::Buffer).
def read_packet
buffer = Net::SSH::Buffer.new(@socket.read(4))
buffer.append(@socket.read(buffer.read_long))
type = buffer.read_byte
debug { "received agent packet #{type} len #{buffer.length-4}" }
return type, buffer
end
# Send the given packet and return the subsequent reply from the agent.
# (See #send_packet and #read_packet).
def send_and_wait(type, *args)
send_packet(type, *args)
read_packet
end
# Returns +true+ if the parameter indicates a "failure" response from
# the agent, and +false+ otherwise.
def agent_failed(type)
type == SSH_AGENT_FAILURE ||
type == SSH2_AGENT_FAILURE ||
type == SSH_COM_AGENT2_FAILURE
end
def blob_for_add(priv_key)
# Ideally we'd have something like `to_private_blob` on the various key types, but the
# nuances with encoding (e.g. `n` and `e` are reversed for RSA keys) make this impractical.
case priv_key.ssh_type
when /^ssh-dss$/
Net::SSH::Buffer.from(:bignum, priv_key.p, :bignum, priv_key.q, :bignum, priv_key.g,
:bignum, priv_key.pub_key, :bignum, priv_key.priv_key).to_s
when /^ssh-dss-cert-v01@openssh\.com$/
Net::SSH::Buffer.from(:string, priv_key.to_blob, :bignum, priv_key.key.priv_key).to_s
when /^ecdsa\-sha2\-(\w*)$/
curve_name = OpenSSL::PKey::EC::CurveNameAliasInv[priv_key.group.curve_name]
Net::SSH::Buffer.from(:string, curve_name, :mstring, priv_key.public_key.to_bn.to_s(2),
:bignum, priv_key.private_key).to_s
when /^ecdsa\-sha2\-(\w*)-cert-v01@openssh\.com$/
Net::SSH::Buffer.from(:string, priv_key.to_blob, :bignum, priv_key.key.private_key).to_s
when /^ssh-ed25519$/
Net::SSH::Buffer.from(:string, priv_key.public_key.verify_key.to_bytes,
:string, priv_key.sign_key.keypair_bytes).to_s
when /^ssh-ed25519-cert-v01@openssh\.com$/
# Unlike the other certificate types, the public key is included after the certifiate.
Net::SSH::Buffer.from(:string, priv_key.to_blob,
:string, priv_key.key.public_key.verify_key.to_bytes,
:string, priv_key.key.sign_key.keypair_bytes).to_s
when /^ssh-rsa$/
# `n` and `e` are reversed compared to the ordering in `OpenSSL::PKey::RSA#to_blob`.
Net::SSH::Buffer.from(:bignum, priv_key.n, :bignum, priv_key.e, :bignum, priv_key.d,
:bignum, priv_key.iqmp, :bignum, priv_key.p, :bignum, priv_key.q).to_s
when /^ssh-rsa-cert-v01@openssh\.com$/
Net::SSH::Buffer.from(:string, priv_key.to_blob, :bignum, priv_key.key.d,
:bignum, priv_key.key.iqmp, :bignum, priv_key.key.p,
:bignum, priv_key.key.q).to_s
end
end
end
end; end; end
net-ssh-4.2.0/lib/net/ssh/authentication/certificate.rb 0000664 0000000 0000000 00000011303 13153765720 0023064 0 ustar 00root root 0000000 0000000 require 'securerandom'
module Net; module SSH; module Authentication
# Class for representing an SSH certificate.
#
# http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/usr.bin/ssh/PROTOCOL.certkeys?rev=1.10&content-type=text/plain
class Certificate
attr_accessor :nonce
attr_accessor :key
attr_accessor :serial
attr_accessor :type
attr_accessor :key_id
attr_accessor :valid_principals
attr_accessor :valid_after
attr_accessor :valid_before
attr_accessor :critical_options
attr_accessor :extensions
attr_accessor :reserved
attr_accessor :signature_key
attr_accessor :signature
# Read a certificate blob associated with a key of the given type.
def self.read_certblob(buffer, type)
cert = Certificate.new
cert.nonce = buffer.read_string
cert.key = buffer.read_keyblob(type)
cert.serial = buffer.read_int64
cert.type = type_symbol(buffer.read_long)
cert.key_id = buffer.read_string
cert.valid_principals = buffer.read_buffer.read_all(&:read_string)
cert.valid_after = Time.at(buffer.read_int64)
cert.valid_before = Time.at(buffer.read_int64)
cert.critical_options = read_options(buffer)
cert.extensions = read_options(buffer)
cert.reserved = buffer.read_string
cert.signature_key = buffer.read_buffer.read_key
cert.signature = buffer.read_string
cert
end
def ssh_type
key.ssh_type + "-cert-v01@openssh.com"
end
def ssh_signature_type
key.ssh_type
end
# Serializes the certificate (and key).
def to_blob
Buffer.from(
:raw, to_blob_without_signature,
:string, signature
).to_s
end
def ssh_do_sign(data)
key.ssh_do_sign(data)
end
def ssh_do_verify(sig, data)
key.ssh_do_verify(sig, data)
end
def to_pem
key.to_pem
end
def fingerprint
key.fingerprint
end
# Signs the certificate with key.
def sign!(key, sign_nonce=nil)
# ssh-keygen uses 32 bytes of nonce.
self.nonce = sign_nonce || SecureRandom.random_bytes(32)
self.signature_key = key
self.signature = Net::SSH::Buffer.from(
:string, key.ssh_signature_type,
:mstring, key.ssh_do_sign(to_blob_without_signature)
).to_s
self
end
def sign(key, sign_nonce=nil)
cert = clone
cert.sign!(key, sign_nonce)
end
# Checks whether the certificate's signature was signed by signature key.
def signature_valid?
buffer = Buffer.new(signature)
buffer.read_string # skip signature format
signature_key.ssh_do_verify(buffer.read_string, to_blob_without_signature)
end
def self.read_options(buffer)
names = []
options = buffer.read_buffer.read_all do |b|
name = b.read_string
names << name
data = b.read_string
data = Buffer.new(data).read_string unless data.empty?
[name, data]
end
if names.sort != names
raise ArgumentError, "option/extension names must be in sorted order"
end
Hash[options]
end
private_class_method :read_options
def self.type_symbol(type)
types = {1 => :user, 2 => :host}
raise ArgumentError("unsupported type: #{type}") unless types.include?(type)
types.fetch(type)
end
private_class_method :type_symbol
private
def type_value(type)
types = {user: 1, host: 2}
raise ArgumentError("unsupported type: #{type}") unless types.include?(type)
types.fetch(type)
end
def ssh_time(t)
# Times in certificates are represented as a uint64.
[[t.to_i, 0].max, 2<<64 - 1].min
end
def to_blob_without_signature
Buffer.from(
:string, ssh_type,
:string, nonce,
:raw, key_without_type,
:int64, serial,
:long, type_value(type),
:string, key_id,
:string, valid_principals.inject(Buffer.new) { |acc, elem| acc.write_string(elem) }.to_s,
:int64, ssh_time(valid_after),
:int64, ssh_time(valid_before),
:string, options_to_blob(critical_options),
:string, options_to_blob(extensions),
:string, reserved,
:string, signature_key.to_blob
).to_s
end
def key_without_type
# key.to_blob gives us e.g. "ssh-rsa," but we just want "".
tmp = Buffer.new(key.to_blob)
tmp.read_string # skip the underlying key type
tmp.read
end
def options_to_blob(options)
options.keys.sort.inject(Buffer.new) do |b, name|
b.write_string(name)
data = options.fetch(name)
data = Buffer.from(:string, data).to_s unless data.empty?
b.write_string(data)
end.to_s
end
end
end; end; end
net-ssh-4.2.0/lib/net/ssh/authentication/constants.rb 0000664 0000000 0000000 00000001067 13153765720 0022624 0 ustar 00root root 0000000 0000000 module Net; module SSH; module Authentication
# Describes the constants used by the Net::SSH::Authentication components
# of the Net::SSH library. Individual authentication method implemenations
# may define yet more constants that are specific to their implementation.
module Constants
USERAUTH_REQUEST = 50
USERAUTH_FAILURE = 51
USERAUTH_SUCCESS = 52
USERAUTH_BANNER = 53
USERAUTH_PASSWD_CHANGEREQ = 60
USERAUTH_PK_OK = 60
USERAUTH_METHOD_RANGE = 60..79
end
end; end; end net-ssh-4.2.0/lib/net/ssh/authentication/ed25519.rb 0000664 0000000 0000000 00000010510 13153765720 0021577 0 ustar 00root root 0000000 0000000 gem 'rbnacl', '>= 3.2.0', '< 5.0'
gem 'bcrypt_pbkdf', '~> 1.0' unless RUBY_PLATFORM == "java"
begin
require 'rbnacl/libsodium'
rescue LoadError # rubocop:disable Lint/HandleExceptions
end
require 'rbnacl'
require 'rbnacl/signatures/ed25519/verify_key'
require 'rbnacl/signatures/ed25519/signing_key'
require 'rbnacl/hash'
require 'base64'
require 'net/ssh/transport/cipher_factory'
require 'bcrypt_pbkdf' unless RUBY_PLATFORM == "java"
module Net; module SSH; module Authentication
module ED25519
class SigningKeyFromFile < RbNaCl::Signatures::Ed25519::SigningKey
def initialize(pk,sk)
@signing_key = sk
@verify_key = RbNaCl::Signatures::Ed25519::VerifyKey.new(pk)
end
end
class PubKey
attr_reader :verify_key
def initialize(data)
@verify_key = RbNaCl::Signatures::Ed25519::VerifyKey.new(data)
end
def self.read_keyblob(buffer)
PubKey.new(buffer.read_string)
end
def to_blob
Net::SSH::Buffer.from(:mstring,"ssh-ed25519",:string,@verify_key.to_bytes).to_s
end
def ssh_type
"ssh-ed25519"
end
def ssh_signature_type
ssh_type
end
def ssh_do_verify(sig,data)
@verify_key.verify(sig,data)
end
def to_pem
# TODO this is not pem
ssh_type + Base64.encode64(@verify_key.to_bytes)
end
def fingerprint
@fingerprint ||= OpenSSL::Digest::MD5.hexdigest(to_blob).scan(/../).join(":")
end
end
class PrivKey
CipherFactory = Net::SSH::Transport::CipherFactory
MBEGIN = "-----BEGIN OPENSSH PRIVATE KEY-----\n"
MEND = "-----END OPENSSH PRIVATE KEY-----\n"
MAGIC = "openssh-key-v1"
attr_reader :sign_key
def initialize(datafull,password)
raise ArgumentError.new("Expected #{MBEGIN} at start of private key") unless datafull.start_with?(MBEGIN)
raise ArgumentError.new("Expected #{MEND} at end of private key") unless datafull.end_with?(MEND)
datab64 = datafull[MBEGIN.size ... -MEND.size]
data = Base64.decode64(datab64)
raise ArgumentError.new("Expected #{MAGIC} at start of decoded private key") unless data.start_with?(MAGIC)
buffer = Net::SSH::Buffer.new(data[MAGIC.size+1 .. -1])
ciphername = buffer.read_string
raise ArgumentError.new("#{ciphername} in private key is not supported") unless
CipherFactory.supported?(ciphername)
kdfname = buffer.read_string
raise ArgumentError.new("Expected #{kdfname} to be or none or bcrypt") unless %w(none bcrypt).include?(kdfname)
kdfopts = Net::SSH::Buffer.new(buffer.read_string)
num_keys = buffer.read_long
raise ArgumentError.new("Only 1 key is supported in ssh keys #{num_keys} was in private key") unless num_keys == 1
_pubkey = buffer.read_string
len = buffer.read_long
keylen, blocksize, ivlen = CipherFactory.get_lengths(ciphername, iv_len: true)
raise ArgumentError.new("Private key len:#{len} is not a multiple of #{blocksize}") if
((len < blocksize) || ((blocksize > 0) && (len % blocksize) != 0))
if kdfname == 'bcrypt'
salt = kdfopts.read_string
rounds = kdfopts.read_long
raise "BCryptPbkdf is not implemented for jruby" if RUBY_PLATFORM == "java"
key = BCryptPbkdf::key(password, salt, keylen + ivlen, rounds)
else
key = '\x00' * (keylen + ivlen)
end
cipher = CipherFactory.get(ciphername, key: key[0...keylen], iv:key[keylen...keylen+ivlen], decrypt: true)
decoded = cipher.update(buffer.remainder_as_buffer.to_s)
decoded << cipher.final
decoded = Net::SSH::Buffer.new(decoded)
check1 = decoded.read_long
check2 = decoded.read_long
raise ArgumentError, "Decrypt failed on private key" if (check1 != check2)
_type_name = decoded.read_string
pk = decoded.read_string
sk = decoded.read_string
_comment = decoded.read_string
@pk = pk
@sign_key = SigningKeyFromFile.new(pk,sk)
end
def to_blob
public_key.to_blob
end
def ssh_type
"ssh-ed25519"
end
def ssh_signature_type
ssh_type
end
def public_key
PubKey.new(@pk)
end
def ssh_do_sign(data)
@sign_key.sign(data)
end
def self.read(data,password)
self.new(data,password)
end
def self.read_keyblob(buffer)
ED25519::PubKey.read_keyblob(buffer)
end
end
end
end; end; end
net-ssh-4.2.0/lib/net/ssh/authentication/ed25519_loader.rb 0000664 0000000 0000000 00000001722 13153765720 0023132 0 ustar 00root root 0000000 0000000 module Net; module SSH; module Authentication
# Loads ED25519 support which requires optinal dependecies like
# rbnacl, bcrypt_pbkdf
module ED25519Loader
begin
require 'net/ssh/authentication/ed25519'
LOADED = true
ERROR = nil
rescue LoadError => e
ERROR = e
LOADED = false
end
def self.raiseUnlessLoaded(message)
description = ERROR.is_a?(LoadError) ? dependenciesRequiredForED25519 : ''
description << "#{ERROR.class} : \"#{ERROR.message}\"\n" if ERROR
raise NotImplementedError, "#{message}\n#{description}" unless LOADED
end
def self.dependenciesRequiredForED25519
result = "net-ssh requires the following gems for ed25519 support:\n"
result << " * rbnacl (>= 3.2, < 5.0)\n"
result << " * rbnacl-libsodium, if your system doesn't have libsodium installed.\n"
result << " * bcrypt_pbkdf (>= 1.0, < 2.0)\n" unless RUBY_PLATFORM == "java"
result << "See https://github.com/net-ssh/net-ssh/issues/478 for more information\n"
end
end
end; end; end
net-ssh-4.2.0/lib/net/ssh/authentication/key_manager.rb 0000664 0000000 0000000 00000024473 13153765720 0023100 0 ustar 00root root 0000000 0000000 require 'net/ssh/errors'
require 'net/ssh/key_factory'
require 'net/ssh/loggable'
require 'net/ssh/authentication/agent'
module Net
module SSH
module Authentication
# A trivial exception class used to report errors in the key manager.
class KeyManagerError < Net::SSH::Exception; end
# This class encapsulates all operations done by clients on a user's
# private keys. In practice, the client should never need a reference
# to a private key; instead, they grab a list of "identities" (public
# keys) that are available from the KeyManager, and then use
# the KeyManager to do various private key operations using those
# identities.
#
# The KeyManager also uses the Agent class to encapsulate the
# ssh-agent. Thus, from a client's perspective it is completely
# hidden whether an identity comes from the ssh-agent or from a file
# on disk.
class KeyManager
include Loggable
# The list of user key files that will be examined
attr_reader :key_files
# The list of user key data that will be examined
attr_reader :key_data
# The map of loaded identities
attr_reader :known_identities
# The map of options that were passed to the key-manager
attr_reader :options
# Create a new KeyManager. By default, the manager will
# use the ssh-agent if it is running and the `:use_agent` option
# is not false.
def initialize(logger, options={})
self.logger = logger
@key_files = []
@key_data = []
@use_agent = !(options[:use_agent] == false)
@known_identities = {}
@agent = nil
@options = options
end
# Clear all knowledge of any loaded user keys. This also clears the list
# of default identity files that are to be loaded, thus making it
# appropriate to use if a client wishes to NOT use the default identity
# files.
def clear!
key_files.clear
key_data.clear
known_identities.clear
self
end
# Add the given key_file to the list of key files that will be used.
def add(key_file)
key_files.push(File.expand_path(key_file)).uniq!
self
end
# Add the given key_file to the list of keys that will be used.
def add_key_data(key_data_)
key_data.push(key_data_).uniq!
self
end
# This is used as a hint to the KeyManager indicating that the agent
# connection is no longer needed. Any other open resources may be closed
# at this time.
#
# Calling this does NOT indicate that the KeyManager will no longer
# be used. Identities may still be requested and operations done on
# loaded identities, in which case, the agent will be automatically
# reconnected. This method simply allows the client connection to be
# closed when it will not be used in the immediate future.
def finish
@agent.close if @agent
@agent = nil
end
# Iterates over all available identities (public keys) known to this
# manager. As it finds one, it will then yield it to the caller.
# The origin of the identities may be from files on disk or from an
# ssh-agent. Note that identities from an ssh-agent are always listed
# first in the array, with other identities coming after.
#
# If key manager was created with :keys_only option, any identity
# from ssh-agent will be ignored unless it present in key_files or
# key_data.
def each_identity
prepared_identities = prepare_identities_from_files + prepare_identities_from_data
user_identities = load_identities(prepared_identities, false, true)
if agent
agent.identities.each do |key|
corresponding_user_identity = user_identities.detect { |identity|
identity[:public_key] && identity[:public_key].to_pem == key.to_pem
}
user_identities.delete(corresponding_user_identity) if corresponding_user_identity
if !options[:keys_only] || corresponding_user_identity
known_identities[key] = { from: :agent }
yield key
end
end
end
user_identities = load_identities(user_identities, !options[:non_interactive], false)
user_identities.each do |identity|
key = identity.delete(:public_key)
known_identities[key] = identity
yield key
end
self
end
# Sign the given data, using the corresponding private key of the given
# identity. If the identity was originally obtained from an ssh-agent,
# then the ssh-agent will be used to sign the data, otherwise the
# private key for the identity will be loaded from disk (if it hasn't
# been loaded already) and will then be used to sign the data.
#
# Regardless of the identity's origin or who does the signing, this
# will always return the signature in an SSH2-specified "signature
# blob" format.
def sign(identity, data)
info = known_identities[identity] or raise KeyManagerError, "the given identity is unknown to the key manager"
if info[:key].nil? && info[:from] == :file
begin
info[:key] = KeyFactory.load_private_key(info[:file], options[:passphrase], !options[:non_interactive])
rescue OpenSSL::OpenSSLError, Exception => e
raise KeyManagerError, "the given identity is known, but the private key could not be loaded: #{e.class} (#{e.message})"
end
end
if info[:key]
return Net::SSH::Buffer.from(:string, identity.ssh_signature_type,
:mstring, info[:key].ssh_do_sign(data.to_s)).to_s
end
if info[:from] == :agent
raise KeyManagerError, "the agent is no longer available" unless agent
return agent.sign(identity, data.to_s)
end
raise KeyManagerError, "[BUG] can't determine identity origin (#{info.inspect})"
end
# Identifies whether the ssh-agent will be used or not.
def use_agent?
@use_agent
end
# Toggles whether the ssh-agent will be used or not. If true, an
# attempt will be made to use the ssh-agent. If false, any existing
# connection to an agent is closed and the agent will not be used.
def use_agent=(use_agent)
finish if !use_agent
@use_agent = use_agent
end
# Returns an Agent instance to use for communicating with an SSH
# agent process. Returns nil if use of an SSH agent has been disabled,
# or if the agent is otherwise not available.
def agent
return unless use_agent?
@agent ||= Agent.connect(logger, options[:agent_socket_factory])
rescue AgentNotAvailable
@use_agent = false
nil
end
private
# Prepares identities from user key_files for loading, preserving their order and sources.
def prepare_identities_from_files
key_files.map do |file|
if readable_file?(file)
identity = {}
cert_file = file + "-cert.pub"
public_key_file = file + ".pub"
if readable_file?(cert_file)
identity[:load_from] = :pubkey_file
identity[:pubkey_file] = cert_file
elsif readable_file?(public_key_file)
identity[:load_from] = :pubkey_file
identity[:pubkey_file] = public_key_file
else
identity[:load_from] = :privkey_file
end
identity.merge(privkey_file: file)
end
end.compact
end
def readable_file?(path)
File.file?(path) && File.readable?(path)
end
# Prepared identities from user key_data, preserving their order and sources.
def prepare_identities_from_data
key_data.map do |data|
{ load_from: :data, data: data }
end
end
# Load prepared identities. Private key decryption errors ignored if ignore_decryption_errors
def load_identities(identities, ask_passphrase, ignore_decryption_errors)
identities.map do |identity|
begin
case identity[:load_from]
when :pubkey_file
key = KeyFactory.load_public_key(identity[:pubkey_file])
{ public_key: key, from: :file, file: identity[:privkey_file] }
when :privkey_file
private_key = KeyFactory.load_private_key(identity[:privkey_file], options[:passphrase], ask_passphrase, options[:password_prompt])
key = private_key.send(:public_key)
{ public_key: key, from: :file, file: identity[:privkey_file], key: private_key }
when :data
private_key = KeyFactory.load_data_private_key(identity[:data], options[:passphrase], ask_passphrase, "", options[:password_prompt])
key = private_key.send(:public_key)
{ public_key: key, from: :key_data, data: identity[:data], key: private_key }
else
identity
end
rescue OpenSSL::PKey::RSAError, OpenSSL::PKey::DSAError, OpenSSL::PKey::ECError, OpenSSL::PKey::PKeyError, ArgumentError => e
if ignore_decryption_errors
identity
else
process_identity_loading_error(identity, e)
nil
end
rescue Exception => e
process_identity_loading_error(identity, e)
nil
end
end.compact
end
def process_identity_loading_error(identity, e)
case identity[:load_from]
when :pubkey_file
error { "could not load public key file `#{identity[:pubkey_file]}': #{e.class} (#{e.message})" }
when :privkey_file
error { "could not load private key file `#{identity[:privkey_file]}': #{e.class} (#{e.message})" }
else
raise e
end
end
end
end
end
end
net-ssh-4.2.0/lib/net/ssh/authentication/methods/ 0000775 0000000 0000000 00000000000 13153765720 0021722 5 ustar 00root root 0000000 0000000 net-ssh-4.2.0/lib/net/ssh/authentication/methods/abstract.rb 0000664 0000000 0000000 00000003626 13153765720 0024061 0 ustar 00root root 0000000 0000000 require 'net/ssh/buffer'
require 'net/ssh/errors'
require 'net/ssh/loggable'
require 'net/ssh/authentication/constants'
module Net; module SSH; module Authentication; module Methods
# The base class of all user authentication methods. It provides a few
# bits of common functionality.
class Abstract
include Constants, Loggable
# The authentication session object
attr_reader :session
# The key manager object. Not all authentication methods will require
# this.
attr_reader :key_manager
# Instantiates a new authentication method.
def initialize(session, options={})
@session = session
@key_manager = options[:key_manager]
@options = options
@prompt = options[:password_prompt]
self.logger = session.logger
end
# Returns the session-id, as generated during the first key exchange of
# an SSH connection.
def session_id
session.transport.algorithms.session_id
end
# Sends a message via the underlying transport layer abstraction. This
# will block until the message is completely sent.
def send_message(msg)
session.transport.send_message(msg)
end
# Creates a new USERAUTH_REQUEST packet. The extra arguments on the end
# must be either boolean values or strings, and are tacked onto the end
# of the packet. The new packet is returned, ready for sending.
def userauth_request(username, next_service, auth_method, *others)
buffer = Net::SSH::Buffer.from(:byte, USERAUTH_REQUEST,
:string, username, :string, next_service, :string, auth_method)
others.each do |value|
case value
when true, false then buffer.write_bool(value)
when String then buffer.write_string(value)
else raise ArgumentError, "don't know how to write #{value.inspect}"
end
end
buffer
end
private
attr_reader :prompt
end
end; end; end; end net-ssh-4.2.0/lib/net/ssh/authentication/methods/hostbased.rb 0000664 0000000 0000000 00000005065 13153765720 0024231 0 ustar 00root root 0000000 0000000 require 'net/ssh/authentication/methods/abstract'
module Net
module SSH
module Authentication
module Methods
# Implements the host-based SSH authentication method.
class Hostbased < Abstract
include Constants
# Attempts to perform host-based authorization of the user by trying
# all known keys.
def authenticate(next_service, username, password=nil)
return false unless key_manager
key_manager.each_identity do |identity|
return true if authenticate_with(identity, next_service,
username, key_manager)
end
return false
end
private
# Returns the hostname as reported by the underlying socket.
def hostname
session.transport.socket.client_name
end
# Attempts to perform host-based authentication of the user, using
# the given host identity (key).
def authenticate_with(identity, next_service, username, key_manager)
debug { "trying hostbased (#{identity.fingerprint})" }
client_username = ENV['USER'] || username
req = build_request(identity, next_service, username, "#{hostname}.", client_username)
sig_data = Buffer.from(:string, session_id, :raw, req)
sig = key_manager.sign(identity, sig_data.to_s)
message = Buffer.from(:raw, req, :string, sig)
send_message(message)
message = session.next_message
case message.type
when USERAUTH_SUCCESS
info { "hostbased succeeded (#{identity.fingerprint})" }
return true
when USERAUTH_FAILURE
info { "hostbased failed (#{identity.fingerprint})" }
raise Net::SSH::Authentication::DisallowedMethod unless
message[:authentications].split(/,/).include? 'hostbased'
return false
else
raise Net::SSH::Exception, "unexpected server response to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
end
end
# Build the "core" hostbased request string.
def build_request(identity, next_service, username, hostname, client_username)
userauth_request(username, next_service, "hostbased", identity.ssh_type,
Buffer.from(:key, identity).to_s, hostname, client_username).to_s
end
end
end
end
end
end
net-ssh-4.2.0/lib/net/ssh/authentication/methods/keyboard_interactive.rb 0000664 0000000 0000000 00000005450 13153765720 0026450 0 ustar 00root root 0000000 0000000 require 'net/ssh/prompt'
require 'net/ssh/authentication/methods/abstract'
module Net
module SSH
module Authentication
module Methods
# Implements the "keyboard-interactive" SSH authentication method.
class KeyboardInteractive < Abstract
USERAUTH_INFO_REQUEST = 60
USERAUTH_INFO_RESPONSE = 61
# Attempt to authenticate the given user for the given service.
def authenticate(next_service, username, password=nil)
debug { "trying keyboard-interactive" }
send_message(userauth_request(username, next_service, "keyboard-interactive", "", ""))
prompter = nil
loop do
message = session.next_message
case message.type
when USERAUTH_SUCCESS
debug { "keyboard-interactive succeeded" }
prompter.success if prompter
return true
when USERAUTH_FAILURE
debug { "keyboard-interactive failed" }
raise Net::SSH::Authentication::DisallowedMethod unless
message[:authentications].split(/,/).include? 'keyboard-interactive'
return false unless interactive?
password = nil
debug { "retrying keyboard-interactive" }
send_message(userauth_request(username, next_service, "keyboard-interactive", "", ""))
when USERAUTH_INFO_REQUEST
name = message.read_string
instruction = message.read_string
debug { "keyboard-interactive info request" }
if password.nil? && interactive? && prompter.nil?
prompter = prompt.start(type: 'keyboard-interactive', name: name, instruction: instruction)
end
_ = message.read_string # lang_tag
responses =[]
message.read_long.times do
text = message.read_string
echo = message.read_bool
password_to_send = password || (prompter && prompter.ask(text, echo))
responses << password_to_send
end
# if the password failed the first time around, don't try
# and use it on subsequent requests.
password = nil
msg = Buffer.from(:byte, USERAUTH_INFO_RESPONSE, :long, responses.length, :string, responses)
send_message(msg)
else
raise Net::SSH::Exception, "unexpected reply in keyboard interactive: #{message.type} (#{message.inspect})"
end
end
end
def interactive?
options = session.transport.options || {}
!options[:non_interactive]
end
end
end
end
end
end
net-ssh-4.2.0/lib/net/ssh/authentication/methods/none.rb 0000664 0000000 0000000 00000002133 13153765720 0023205 0 ustar 00root root 0000000 0000000 require 'net/ssh/errors'
require 'net/ssh/authentication/methods/abstract'
module Net
module SSH
module Authentication
module Methods
# Implements the "none" SSH authentication method.
class None < Abstract
# Attempt to authenticate as "none"
def authenticate(next_service, user="", password="")
send_message(userauth_request(user, next_service, "none"))
message = session.next_message
case message.type
when USERAUTH_SUCCESS
debug { "none succeeded" }
return true
when USERAUTH_FAILURE
debug { "none failed" }
raise Net::SSH::Authentication::DisallowedMethod unless
message[:authentications].split(/,/).include? 'none'
return false
else
raise Net::SSH::Exception, "unexpected reply to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
end
end
end
end
end
end
end
net-ssh-4.2.0/lib/net/ssh/authentication/methods/password.rb 0000664 0000000 0000000 00000005212 13153765720 0024111 0 ustar 00root root 0000000 0000000 require 'net/ssh/errors'
require 'net/ssh/prompt'
require 'net/ssh/authentication/methods/abstract'
module Net
module SSH
module Authentication
module Methods
# Implements the "password" SSH authentication method.
class Password < Abstract
# Attempt to authenticate the given user for the given service. If
# the password parameter is nil, this will ask for password
def authenticate(next_service, username, password=nil)
clear_prompter!
retries = 0
max_retries = get_max_retries
return false if !password && max_retries == 0
begin
password_to_send = password || ask_password(username)
send_message(userauth_request(username, next_service, "password", false, password_to_send))
message = session.next_message
retries += 1
if message.type == USERAUTH_FAILURE
debug { "password failed" }
raise Net::SSH::Authentication::DisallowedMethod unless
message[:authentications].split(/,/).include? 'password'
password = nil
end
end until (message.type != USERAUTH_FAILURE || retries >= max_retries)
case message.type
when USERAUTH_SUCCESS
debug { "password succeeded" }
@prompter.success if @prompter
return true
when USERAUTH_FAILURE
return false
when USERAUTH_PASSWD_CHANGEREQ
debug { "password change request received, failing" }
return false
else
raise Net::SSH::Exception, "unexpected reply to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
end
end
private
NUMBER_OF_PASSWORD_PROMPTS = 3
def clear_prompter!
@prompt_info = nil
@prompter = nil
end
def ask_password(username)
host = session.transport.host
prompt_info = {type: 'password', user: username, host: host}
if @prompt_info != prompt_info
@prompt_info = prompt_info
@prompter = prompt.start(prompt_info)
end
echo = false
@prompter.ask("#{username}@#{host}'s password:", echo)
end
def get_max_retries
options = session.transport.options || {}
result = options[:number_of_password_prompts] || NUMBER_OF_PASSWORD_PROMPTS
options[:non_interactive] ? 0 : result
end
end
end
end
end
end
net-ssh-4.2.0/lib/net/ssh/authentication/methods/publickey.rb 0000664 0000000 0000000 00000007026 13153765720 0024243 0 ustar 00root root 0000000 0000000 require 'net/ssh/buffer'
require 'net/ssh/errors'
require 'net/ssh/authentication/methods/abstract'
module Net
module SSH
module Authentication
module Methods
# Implements the "publickey" SSH authentication method.
class Publickey < Abstract
# Attempts to perform public-key authentication for the given
# username, trying each identity known to the key manager. If any of
# them succeed, returns +true+, otherwise returns +false+. This
# requires the presence of a key manager.
def authenticate(next_service, username, password=nil)
return false unless key_manager
key_manager.each_identity do |identity|
return true if authenticate_with(identity, next_service, username)
end
return false
end
private
# Builds a packet that contains the request formatted for sending
# a public-key request to the server.
def build_request(pub_key, username, next_service, has_sig)
blob = Net::SSH::Buffer.new
blob.write_key pub_key
userauth_request(username, next_service, "publickey", has_sig,
pub_key.ssh_type, blob.to_s)
end
# Builds and sends a request formatted for a public-key
# authentication request.
def send_request(pub_key, username, next_service, signature=nil)
msg = build_request(pub_key, username, next_service, !signature.nil?)
msg.write_string(signature) if signature
send_message(msg)
end
# Attempts to perform public-key authentication for the given
# username, with the given identity (public key). Returns +true+ if
# successful, or +false+ otherwise.
def authenticate_with(identity, next_service, username)
debug { "trying publickey (#{identity.fingerprint})" }
send_request(identity, username, next_service)
message = session.next_message
case message.type
when USERAUTH_PK_OK
buffer = build_request(identity, username, next_service, true)
sig_data = Net::SSH::Buffer.new
sig_data.write_string(session_id)
sig_data.append(buffer.to_s)
sig_blob = key_manager.sign(identity, sig_data)
send_request(identity, username, next_service, sig_blob.to_s)
message = session.next_message
case message.type
when USERAUTH_SUCCESS
debug { "publickey succeeded (#{identity.fingerprint})" }
return true
when USERAUTH_FAILURE
debug { "publickey failed (#{identity.fingerprint})" }
raise Net::SSH::Authentication::DisallowedMethod unless
message[:authentications].split(/,/).include? 'publickey'
return false
else
raise Net::SSH::Exception,
"unexpected server response to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
end
when USERAUTH_FAILURE
return false
else
raise Net::SSH::Exception, "unexpected reply to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
end
end
end
end
end
end
end
net-ssh-4.2.0/lib/net/ssh/authentication/pageant.rb 0000664 0000000 0000000 00000036661 13153765720 0022237 0 ustar 00root root 0000000 0000000 if RUBY_VERSION < "1.9"
require 'dl/import'
require 'dl/struct'
elsif RUBY_VERSION < "2.1"
require 'dl/import'
require 'dl/types'
require 'dl'
else
require 'fiddle'
require 'fiddle/types'
require 'fiddle/import'
# For now map DL to Fiddler versus updating all the code below
module DL
CPtr ||= Fiddle::Pointer
if RUBY_PLATFORM != "java"
RUBY_FREE ||= Fiddle::RUBY_FREE
end
end
end
require 'net/ssh/errors'
module Net; module SSH; module Authentication
# This module encapsulates the implementation of a socket factory that
# uses the PuTTY "pageant" utility to obtain information about SSH
# identities.
#
# This code is a slightly modified version of the original implementation
# by Guillaume Marçais (guillaume.marcais@free.fr). It is used and
# relicensed by permission.
module Pageant
# From Putty pageant.c
AGENT_MAX_MSGLEN = 8192
AGENT_COPYDATA_ID = 0x804e50ba
# The definition of the Windows methods and data structures used in
# communicating with the pageant process.
module Win # rubocop:disable Metrics/ModuleLength
# Compatibility on initialization
if RUBY_VERSION < "1.9"
extend DL::Importable
dlload 'user32'
dlload 'kernel32'
dlload 'advapi32'
SIZEOF_DWORD = DL.sizeof('L')
elsif RUBY_VERSION < "2.1"
extend DL::Importer
dlload 'user32','kernel32', 'advapi32'
include DL::Win32Types
SIZEOF_DWORD = DL::SIZEOF_LONG
else
extend Fiddle::Importer
dlload 'user32','kernel32', 'advapi32'
include Fiddle::Win32Types
SIZEOF_DWORD = Fiddle::SIZEOF_LONG
end
if RUBY_ENGINE=="jruby"
typealias("HANDLE", "void *") # From winnt.h
typealias("PHANDLE", "void *") # From winnt.h
typealias("ULONG_PTR", "unsigned long*")
end
typealias("LPCTSTR", "char *") # From winnt.h
typealias("LPVOID", "void *") # From winnt.h
typealias("LPCVOID", "const void *") # From windef.h
typealias("LRESULT", "long") # From windef.h
typealias("WPARAM", "unsigned int *") # From windef.h
typealias("LPARAM", "long *") # From windef.h
typealias("PDWORD_PTR", "long *") # From basetsd.h
typealias("USHORT", "unsigned short") # From windef.h
# From winbase.h, winnt.h
INVALID_HANDLE_VALUE = -1
NULL = nil
PAGE_READWRITE = 0x0004
FILE_MAP_WRITE = 2
WM_COPYDATA = 74
SMTO_NORMAL = 0 # From winuser.h
SUFFIX = if RUBY_ENGINE == "jruby"
"A"
else
""
end
# args: lpClassName, lpWindowName
extern "HWND FindWindow#{SUFFIX}(LPCTSTR, LPCTSTR)"
# args: none
extern 'DWORD GetCurrentThreadId()'
# args: hFile, (ignored), flProtect, dwMaximumSizeHigh,
# dwMaximumSizeLow, lpName
extern "HANDLE CreateFileMapping#{SUFFIX}(HANDLE, void *, DWORD, " +
"DWORD, DWORD, LPCTSTR)"
# args: hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh,
# dwfileOffsetLow, dwNumberOfBytesToMap
extern 'LPVOID MapViewOfFile(HANDLE, DWORD, DWORD, DWORD, DWORD)'
# args: lpBaseAddress
extern 'BOOL UnmapViewOfFile(LPCVOID)'
# args: hObject
extern 'BOOL CloseHandle(HANDLE)'
# args: hWnd, Msg, wParam, lParam, fuFlags, uTimeout, lpdwResult
extern "LRESULT SendMessageTimeout#{SUFFIX}(HWND, UINT, WPARAM, LPARAM, " +
"UINT, UINT, PDWORD_PTR)"
# args: none
extern 'DWORD GetLastError()'
# args: none
extern 'HANDLE GetCurrentProcess()'
# args: hProcessHandle, dwDesiredAccess, (out) phNewTokenHandle
extern 'BOOL OpenProcessToken(HANDLE, DWORD, PHANDLE)'
# args: hTokenHandle, uTokenInformationClass,
# (out) lpTokenInformation, dwTokenInformationLength
# (out) pdwInfoReturnLength
extern 'BOOL GetTokenInformation(HANDLE, UINT, LPVOID, DWORD, ' +
'PDWORD)'
# args: (out) lpSecurityDescriptor, dwRevisionLevel
extern 'BOOL InitializeSecurityDescriptor(LPVOID, DWORD)'
# args: (out) lpSecurityDescriptor, lpOwnerSid, bOwnerDefaulted
extern 'BOOL SetSecurityDescriptorOwner(LPVOID, LPVOID, BOOL)'
# args: pSecurityDescriptor
extern 'BOOL IsValidSecurityDescriptor(LPVOID)'
# Constants needed for security attribute retrieval.
# Specifies the access mask corresponding to the desired access
# rights.
TOKEN_QUERY = 0x8
# The value of TOKEN_USER from the TOKEN_INFORMATION_CLASS enum.
TOKEN_USER_INFORMATION_CLASS = 1
# The initial revision level assigned to the security descriptor.
REVISION = 1
# Structs for security attribute functions.
# Holds the retrieved user access token.
TOKEN_USER = struct ['void * SID', 'DWORD ATTRIBUTES']
# Contains the security descriptor, this gets passed to the
# function that constructs the shared memory map.
SECURITY_ATTRIBUTES = struct ['DWORD nLength',
'LPVOID lpSecurityDescriptor',
'BOOL bInheritHandle']
# The security descriptor holds security information.
SECURITY_DESCRIPTOR = struct ['UCHAR Revision', 'UCHAR Sbz1',
'USHORT Control', 'LPVOID Owner',
'LPVOID Group', 'LPVOID Sacl',
'LPVOID Dacl']
# The COPYDATASTRUCT is used to send WM_COPYDATA messages
COPYDATASTRUCT = if RUBY_ENGINE == "jruby"
struct ['ULONG_PTR dwData', 'DWORD cbData', 'LPVOID lpData']
else
struct ['uintptr_t dwData', 'DWORD cbData', 'LPVOID lpData']
end
# Compatibility for security attribute retrieval.
if RUBY_VERSION < "1.9"
# Alias functions to > 1.9 capitalization
%w(findWindow
getCurrentProcess
initializeSecurityDescriptor
setSecurityDescriptorOwner
isValidSecurityDescriptor
openProcessToken
getTokenInformation
getLastError
getCurrentThreadId
createFileMapping
mapViewOfFile
sendMessageTimeout
unmapViewOfFile
closeHandle).each do |name|
new_name = name[0].chr.upcase + name[1..name.length]
alias_method new_name, name
module_function new_name
end
def self.malloc_ptr(size)
return DL.malloc(size)
end
def self.get_ptr(data)
return data.to_ptr
end
def self.set_ptr_data(ptr, data)
ptr[0] = data
end
elsif RUBY_ENGINE == "jruby"
%w(FindWindow CreateFileMapping SendMessageTimeout).each do |name|
alias_method name, name+"A"
module_function name
end
# :nodoc:
module LibC
extend FFI::Library
ffi_lib FFI::Library::LIBC
attach_function :malloc, [:size_t], :pointer
attach_function :free, [:pointer], :void
end
def self.malloc_ptr(size)
Fiddle::Pointer.new(LibC.malloc(size), size, LibC.method(:free))
end
def self.get_ptr(ptr)
return data.address
end
def self.set_ptr_data(ptr, data)
ptr.write_string_length(data, data.size)
end
else
def self.malloc_ptr(size)
return DL::CPtr.malloc(size, DL::RUBY_FREE)
end
def self.get_ptr(data)
return DL::CPtr.to_ptr data
end
def self.set_ptr_data(ptr, data)
DL::CPtr.new(ptr)[0,data.size] = data
end
end
def self.get_security_attributes_for_user
user = get_current_user
psd_information = malloc_ptr(Win::SECURITY_DESCRIPTOR.size)
raise_error_if_zero(
Win.InitializeSecurityDescriptor(psd_information,
Win::REVISION)
)
raise_error_if_zero(
Win.SetSecurityDescriptorOwner(psd_information, get_sid_ptr(user),
0)
)
raise_error_if_zero(
Win.IsValidSecurityDescriptor(psd_information)
)
sa = Win::SECURITY_ATTRIBUTES.new(to_struct_ptr(malloc_ptr(Win::SECURITY_ATTRIBUTES.size)))
sa.nLength = Win::SECURITY_ATTRIBUTES.size
sa.lpSecurityDescriptor = psd_information.to_i
sa.bInheritHandle = 1
return sa
end
if RUBY_ENGINE == "jruby"
def self.ptr_to_s(ptr, size)
ret = ptr.to_s(size)
ret << "\x00" while ret.size < size
ret
end
def self.ptr_to_handle(phandle)
phandle.ptr
end
def self.ptr_to_dword(ptr)
first = ptr.ptr.to_i
second = ptr_to_s(ptr,Win::SIZEOF_DWORD).unpack('L')[0]
raise "Error" unless first == second
first
end
def self.to_token_user(ptoken_information)
TOKEN_USER.new(ptoken_information.to_ptr)
end
def self.to_struct_ptr(ptr)
ptr.to_ptr
end
def self.get_sid(user)
ptr_to_s(user.to_ptr.ptr,Win::SIZEOF_DWORD).unpack('L')[0]
end
def self.get_sid_ptr(user)
user.to_ptr.ptr
end
else
def self.get_sid(user)
user.SID
end
def self.ptr_to_handle(phandle)
phandle.ptr.to_i
end
def self.to_struct_ptr(ptr)
ptr
end
def self.ptr_to_dword(ptr)
ptr.to_s(Win::SIZEOF_DWORD).unpack('L')[0]
end
def self.to_token_user(ptoken_information)
TOKEN_USER.new(ptoken_information)
end
def self.get_sid_ptr(user)
user.SID
end
end
def self.get_current_user
token_handle = open_process_token(Win.GetCurrentProcess,
Win::TOKEN_QUERY)
token_user = get_token_information(token_handle,
Win::TOKEN_USER_INFORMATION_CLASS)
return token_user
end
def self.open_process_token(process_handle, desired_access)
ptoken_handle = malloc_ptr(Win::SIZEOF_DWORD)
raise_error_if_zero(
Win.OpenProcessToken(process_handle, desired_access,
ptoken_handle)
)
token_handle = ptr_to_handle(ptoken_handle)
return token_handle
end
def self.get_token_information(token_handle,
token_information_class)
# Hold the size of the information to be returned
preturn_length = malloc_ptr(Win::SIZEOF_DWORD)
# Going to throw an INSUFFICIENT_BUFFER_ERROR, but that is ok
# here. This is retrieving the size of the information to be
# returned.
Win.GetTokenInformation(token_handle,
token_information_class,
Win::NULL, 0, preturn_length)
ptoken_information = malloc_ptr(ptr_to_dword(preturn_length))
# This call is going to write the requested information to
# the memory location referenced by token_information.
raise_error_if_zero(
Win.GetTokenInformation(token_handle,
token_information_class,
ptoken_information,
ptoken_information.size,
preturn_length)
)
return to_token_user(ptoken_information)
end
def self.raise_error_if_zero(result)
if result == 0
raise "Windows error: #{Win.GetLastError}"
end
end
# Get a null-terminated string given a string.
def self.get_cstr(str)
return str + "\000"
end
end
# This is the pseudo-socket implementation that mimics the interface of
# a socket, translating each request into a Windows messaging call to
# the pageant daemon. This allows pageant support to be implemented
# simply by replacing the socket factory used by the Agent class.
class Socket
private_class_method :new
# The factory method for creating a new Socket instance.
def self.open
new
end
# Create a new instance that communicates with the running pageant
# instance. If no such instance is running, this will cause an error.
def initialize
@win = Win.FindWindow("Pageant", "Pageant")
if @win.to_i == 0
raise Net::SSH::Exception,
"pageant process not running"
end
@input_buffer = Net::SSH::Buffer.new
@output_buffer = Net::SSH::Buffer.new
end
# Forwards the data to #send_query, ignoring any arguments after
# the first.
def send(data, *args)
@input_buffer.append(data)
ret = data.length
while true
return ret if @input_buffer.length < 4
msg_length = @input_buffer.read_long + 4
@input_buffer.reset!
return ret if @input_buffer.length < msg_length
msg = @input_buffer.read!(msg_length)
@output_buffer.append(send_query(msg))
end
end
# Reads +n+ bytes from the cached result of the last query. If +n+
# is +nil+, returns all remaining data from the last query.
def read(n = nil)
@output_buffer.read(n)
end
def close; end
# Packages the given query string and sends it to the pageant
# process via the Windows messaging subsystem. The result is
# cached, to be returned piece-wise when #read is called.
def send_query(query)
res = nil
filemap = 0
ptr = nil
id = Win.malloc_ptr(Win::SIZEOF_DWORD)
mapname = "PageantRequest%08x" % Win.GetCurrentThreadId()
security_attributes = Win.get_ptr Win.get_security_attributes_for_user
filemap = Win.CreateFileMapping(Win::INVALID_HANDLE_VALUE,
security_attributes,
Win::PAGE_READWRITE, 0,
AGENT_MAX_MSGLEN, mapname)
if filemap == 0 || filemap == Win::INVALID_HANDLE_VALUE
raise Net::SSH::Exception,
"Creation of file mapping failed with error: #{Win.GetLastError}"
end
ptr = Win.MapViewOfFile(filemap, Win::FILE_MAP_WRITE, 0, 0,
0)
if ptr.nil? || ptr.null?
raise Net::SSH::Exception, "Mapping of file failed"
end
Win.set_ptr_data(ptr, query)
# using struct to achieve proper alignment and field size on 64-bit platform
cds = Win::COPYDATASTRUCT.new(Win.malloc_ptr(Win::COPYDATASTRUCT.size))
cds.dwData = AGENT_COPYDATA_ID
cds.cbData = mapname.size + 1
cds.lpData = Win.get_cstr(mapname)
succ = Win.SendMessageTimeout(@win, Win::WM_COPYDATA, Win::NULL,
cds.to_ptr, Win::SMTO_NORMAL, 5000, id)
if succ > 0
retlen = 4 + ptr.to_s(4).unpack("N")[0]
res = ptr.to_s(retlen)
else
raise Net::SSH::Exception, "Message failed with error: #{Win.GetLastError}"
end
return res
ensure
Win.UnmapViewOfFile(ptr) unless ptr.nil? || ptr.null?
Win.CloseHandle(filemap) if filemap != 0
end
end
end
end; end; end
net-ssh-4.2.0/lib/net/ssh/authentication/session.rb 0000664 0000000 0000000 00000012416 13153765720 0022273 0 ustar 00root root 0000000 0000000 require 'net/ssh/loggable'
require 'net/ssh/transport/constants'
require 'net/ssh/authentication/constants'
require 'net/ssh/authentication/key_manager'
require 'net/ssh/authentication/methods/none'
require 'net/ssh/authentication/methods/publickey'
require 'net/ssh/authentication/methods/hostbased'
require 'net/ssh/authentication/methods/password'
require 'net/ssh/authentication/methods/keyboard_interactive'
module Net; module SSH; module Authentication
# Raised if the current authentication method is not allowed
class DisallowedMethod < Net::SSH::Exception
end
# Represents an authentication session. It manages the authentication of
# a user over an established connection (the "transport" object, see
# Net::SSH::Transport::Session).
#
# The use of an authentication session to manage user authentication is
# internal to Net::SSH (specifically Net::SSH.start). Consumers of the
# Net::SSH library will never need to access this class directly.
class Session
include Transport::Constants, Constants, Loggable
# transport layer abstraction
attr_reader :transport
# the list of authentication methods to try
attr_reader :auth_methods
# the list of authentication methods that are allowed
attr_reader :allowed_auth_methods
# a hash of options, given at construction time
attr_reader :options
# Instantiates a new Authentication::Session object over the given
# transport layer abstraction.
def initialize(transport, options={})
self.logger = transport.logger
@transport = transport
@auth_methods = options[:auth_methods] || Net::SSH::Config.default_auth_methods
@options = options
@allowed_auth_methods = @auth_methods
end
# Attempts to authenticate the given user, in preparation for the next
# service request. Returns true if an authentication method succeeds in
# authenticating the user, and false otherwise.
def authenticate(next_service, username, password=nil)
debug { "beginning authentication of `#{username}'" }
transport.send_message(transport.service_request("ssh-userauth"))
expect_message(SERVICE_ACCEPT)
key_manager = KeyManager.new(logger, options)
keys.each { |key| key_manager.add(key) } unless keys.empty?
key_data.each { |key2| key_manager.add_key_data(key2) } unless key_data.empty?
attempted = []
@auth_methods.each do |name|
begin
next unless @allowed_auth_methods.include?(name)
attempted << name
debug { "trying #{name}" }
begin
auth_class = Methods.const_get(name.split(/\W+/).map { |p| p.capitalize }.join)
method = auth_class.new(self, key_manager: key_manager, password_prompt: options[:password_prompt])
rescue NameError
debug{"Mechanism #{name} was requested, but isn't a known type. Ignoring it."}
next
end
return true if method.authenticate(next_service, username, password)
rescue Net::SSH::Authentication::DisallowedMethod
end
end
error { "all authorization methods failed (tried #{attempted.join(', ')})" }
return false
ensure
key_manager.finish if key_manager
end
# Blocks until a packet is received. It silently handles USERAUTH_BANNER
# packets, and will raise an error if any packet is received that is not
# valid during user authentication.
def next_message
loop do
packet = transport.next_message
case packet.type
when USERAUTH_BANNER
info { packet[:message] }
# TODO add a hook for people to retrieve the banner when it is sent
when USERAUTH_FAILURE
@allowed_auth_methods = packet[:authentications].split(/,/)
debug { "allowed methods: #{packet[:authentications]}" }
return packet
when USERAUTH_METHOD_RANGE, SERVICE_ACCEPT
return packet
when USERAUTH_SUCCESS
transport.hint :authenticated
return packet
else
raise Net::SSH::Exception, "unexpected message #{packet.type} (#{packet})"
end
end
end
# Blocks until a packet is received, and returns it if it is of the given
# type. If it is not, an exception is raised.
def expect_message(type)
message = next_message
unless message.type == type
raise Net::SSH::Exception, "expected #{type}, got #{message.type} (#{message})"
end
message
end
private
# Returns an array of paths to the key files usually defined
# by system default.
def default_keys
if defined?(OpenSSL::PKey::EC)
%w(~/.ssh/id_ed25519 ~/.ssh/id_rsa ~/.ssh/id_dsa ~/.ssh/id_ecdsa
~/.ssh2/id_ed25519 ~/.ssh2/id_rsa ~/.ssh2/id_dsa ~/.ssh2/id_ecdsa)
else
%w(~/.ssh/id_dsa ~/.ssh/id_rsa ~/.ssh2/id_dsa ~/.ssh2/id_rsa)
end
end
# Returns an array of paths to the key files that should be used when
# attempting any key-based authentication mechanism.
def keys
Array(options[:keys] || default_keys)
end
# Returns an array of the key data that should be used when
# attempting any key-based authentication mechanism.
def key_data
Array(options[:key_data])
end
end
end; end; end
net-ssh-4.2.0/lib/net/ssh/buffer.rb 0000664 0000000 0000000 00000031745 13153765720 0017050 0 ustar 00root root 0000000 0000000 require 'net/ssh/ruby_compat'
require 'net/ssh/transport/openssl'
require 'net/ssh/authentication/certificate'
require 'net/ssh/authentication/ed25519_loader'
module Net; module SSH
# Net::SSH::Buffer is a flexible class for building and parsing binary
# data packets. It provides a stream-like interface for sequentially
# reading data items from the buffer, as well as a useful helper method
# for building binary packets given a signature.
#
# Writing to a buffer always appends to the end, regardless of where the
# read cursor is. Reading, on the other hand, always begins at the first
# byte of the buffer and increments the read cursor, with subsequent reads
# taking up where the last left off.
#
# As a consumer of the Net::SSH library, you will rarely come into contact
# with these buffer objects directly, but it could happen. Also, if you
# are ever implementing a protocol on top of SSH (e.g. SFTP), this buffer
# class can be quite handy.
class Buffer
# This is a convenience method for creating and populating a new buffer
# from a single command. The arguments must be even in length, with the
# first of each pair of arguments being a symbol naming the type of the
# data that follows. If the type is :raw, the value is written directly
# to the hash.
#
# b = Buffer.from(:byte, 1, :string, "hello", :raw, "\1\2\3\4")
# #-> "\1\0\0\0\5hello\1\2\3\4"
#
# The supported data types are:
#
# * :raw => write the next value verbatim (#write)
# * :int64 => write an 8-byte integer (#write_int64)
# * :long => write a 4-byte integer (#write_long)
# * :byte => write a single byte (#write_byte)
# * :string => write a 4-byte length followed by character data (#write_string)
# * :mstring => same as string, but caller cannot resuse the string, avoids potential duplication (#write_moved)
# * :bool => write a single byte, interpreted as a boolean (#write_bool)
# * :bignum => write an SSH-encoded bignum (#write_bignum)
# * :key => write an SSH-encoded key value (#write_key)
#
# Any of these, except for :raw, accepts an Array argument, to make it
# easier to write multiple values of the same type in a briefer manner.
def self.from(*args)
raise ArgumentError, "odd number of arguments given" unless args.length % 2 == 0
buffer = new
0.step(args.length-1, 2) do |index|
type = args[index]
value = args[index+1]
if type == :raw
buffer.append(value.to_s)
elsif Array === value
buffer.send("write_#{type}", *value)
else
buffer.send("write_#{type}", value)
end
end
buffer
end
# exposes the raw content of the buffer
attr_reader :content
# the current position of the pointer in the buffer
attr_accessor :position
# Creates a new buffer, initialized to the given content. The position
# is initialized to the beginning of the buffer.
def initialize(content="")
@content = content.to_s
@position = 0
end
# Returns the length of the buffer's content.
def length
@content.length
end
# Returns the number of bytes available to be read (e.g., how many bytes
# remain between the current position and the end of the buffer).
def available
length - position
end
# Returns a copy of the buffer's content.
def to_s
(@content || "").dup
end
# Compares the contents of the two buffers, returning +true+ only if they
# are identical in size and content.
def ==(buffer)
to_s == buffer.to_s
end
# Returns +true+ if the buffer contains no data (e.g., it is of zero length).
def empty?
@content.empty?
end
# Resets the pointer to the start of the buffer. Subsequent reads will
# begin at position 0.
def reset!
@position = 0
end
# Returns true if the pointer is at the end of the buffer. Subsequent
# reads will return nil, in this case.
def eof?
@position >= length
end
# Resets the buffer, making it empty. Also, resets the read position to
# 0.
def clear!
@content = ""
@position = 0
end
# Consumes n bytes from the buffer, where n is the current position
# unless otherwise specified. This is useful for removing data from the
# buffer that has previously been read, when you are expecting more data
# to be appended. It helps to keep the size of buffers down when they
# would otherwise tend to grow without bound.
#
# Returns the buffer object itself.
def consume!(n=position)
if n >= length
# optimize for a fairly common case
clear!
elsif n > 0
@content = @content[n..-1] || ""
@position -= n
@position = 0 if @position < 0
end
self
end
# Appends the given text to the end of the buffer. Does not alter the
# read position. Returns the buffer object itself.
def append(text)
@content << text
self
end
# Returns all text from the current pointer to the end of the buffer as
# a new Net::SSH::Buffer object.
def remainder_as_buffer
Buffer.new(@content[@position..-1])
end
# Reads all data up to and including the given pattern, which may be a
# String, Fixnum, or Regexp and is interpreted exactly as String#index
# does. Returns nil if nothing matches. Increments the position to point
# immediately after the pattern, if it does match. Returns all data up to
# and including the text that matched the pattern.
def read_to(pattern)
index = @content.index(pattern, @position) or return nil
length = case pattern
when String then pattern.length
when Integer then 1
when Regexp then $&.length
end
index && read(index+length)
end
# Reads and returns the next +count+ bytes from the buffer, starting from
# the read position. If +count+ is +nil+, this will return all remaining
# text in the buffer. This method will increment the pointer.
def read(count=nil)
count ||= length
count = length - @position if @position + count > length
@position += count
@content[@position-count, count]
end
# Reads (as #read) and returns the given number of bytes from the buffer,
# and then consumes (as #consume!) all data up to the new read position.
def read!(count=nil)
data = read(count)
consume!
data
end
# Calls block(self) until the buffer is empty, and returns all results.
def read_all(&block)
Enumerator.new { |e| e << yield(self) until eof? }.to_a
end
# Return the next 8 bytes as a 64-bit integer (in network byte order).
# Returns nil if there are less than 8 bytes remaining to be read in the
# buffer.
def read_int64
hi = read_long or return nil
lo = read_long or return nil
return (hi << 32) + lo
end
# Return the next four bytes as a long integer (in network byte order).
# Returns nil if there are less than 4 bytes remaining to be read in the
# buffer.
def read_long
b = read(4) or return nil
b.unpack("N").first
end
# Read and return the next byte in the buffer. Returns nil if called at
# the end of the buffer.
def read_byte
b = read(1) or return nil
b.getbyte(0)
end
# Read and return an SSH2-encoded string. The string starts with a long
# integer that describes the number of bytes remaining in the string.
# Returns nil if there are not enough bytes to satisfy the request.
def read_string
length = read_long or return nil
read(length)
end
# Read a single byte and convert it into a boolean, using 'C' rules
# (i.e., zero is false, non-zero is true).
def read_bool
b = read_byte or return nil
b != 0
end
# Read a bignum (OpenSSL::BN) from the buffer, in SSH2 format. It is
# essentially just a string, which is reinterpreted to be a bignum in
# binary format.
def read_bignum
data = read_string
return unless data
OpenSSL::BN.new(data, 2)
end
# Read a key from the buffer. The key will start with a string
# describing its type. The remainder of the key is defined by the
# type that was read.
def read_key
type = read_string
return (type ? read_keyblob(type) : nil)
end
# Read a keyblob of the given type from the buffer, and return it as
# a key. Only RSA, DSA, and ECDSA keys are supported.
def read_keyblob(type)
case type
when /^(.*)-cert-v01@openssh\.com$/
key = Net::SSH::Authentication::Certificate.read_certblob(self, $1)
when /^ssh-dss$/
key = OpenSSL::PKey::DSA.new
if key.respond_to?(:set_pqg)
key.set_pqg(read_bignum, read_bignum, read_bignum)
else
key.p = read_bignum
key.q = read_bignum
key.g = read_bignum
end
if key.respond_to?(:set_key)
key.set_key(read_bignum, nil)
else
key.pub_key = read_bignum
end
when /^ssh-rsa$/
key = OpenSSL::PKey::RSA.new
if key.respond_to?(:set_key)
e = read_bignum
n = read_bignum
key.set_key(n, e, nil)
else
key.e = read_bignum
key.n = read_bignum
end
when /^ssh-ed25519$/
Net::SSH::Authentication::ED25519Loader.raiseUnlessLoaded("unsupported key type `#{type}'")
key = Net::SSH::Authentication::ED25519::PubKey.read_keyblob(self)
when /^ecdsa\-sha2\-(\w*)$/
unless defined?(OpenSSL::PKey::EC)
raise NotImplementedError, "unsupported key type `#{type}'"
else
begin
key = OpenSSL::PKey::EC.read_keyblob($1, self)
rescue OpenSSL::PKey::ECError
raise NotImplementedError, "unsupported key type `#{type}'"
end
end
else
raise NotImplementedError, "unsupported key type `#{type}'"
end
return key
end
# Reads the next string from the buffer, and returns a new Buffer
# object that wraps it.
def read_buffer
Buffer.new(read_string)
end
# Writes the given data literally into the string. Does not alter the
# read position. Returns the buffer object.
def write(*data)
data.each { |datum| @content << datum.dup.force_encoding('BINARY') }
self
end
# Optimized version of write where the caller gives up ownership of string
# to the method. This way we can mutate the string.
def write_moved(string)
@content << string.force_encoding('BINARY')
self
end
# Writes each argument to the buffer as a network-byte-order-encoded
# 64-bit integer (8 bytes). Does not alter the read position. Returns the
# buffer object.
def write_int64(*n)
n.each do |i|
hi = (i >> 32) & 0xFFFFFFFF
lo = i & 0xFFFFFFFF
@content << [hi, lo].pack("N2")
end
self
end
# Writes each argument to the buffer as a network-byte-order-encoded
# long (4-byte) integer. Does not alter the read position. Returns the
# buffer object.
def write_long(*n)
@content << n.pack("N*")
self
end
# Writes each argument to the buffer as a byte. Does not alter the read
# position. Returns the buffer object.
def write_byte(*n)
n.each { |b| @content << b.chr }
self
end
# Writes each argument to the buffer as an SSH2-encoded string. Each
# string is prefixed by its length, encoded as a 4-byte long integer.
# Does not alter the read position. Returns the buffer object.
def write_string(*text)
text.each do |string|
s = string.to_s
write_long(s.bytesize)
write(s)
end
self
end
# Writes each argument to the buffer as an SSH2-encoded string. Each
# string is prefixed by its length, encoded as a 4-byte long integer.
# Does not alter the read position. Returns the buffer object.
# Might alter arguments see write_moved
def write_mstring(*text)
text.each do |string|
s = string.to_s
write_long(s.bytesize)
write_moved(s)
end
self
end
# Writes each argument to the buffer as a (C-style) boolean, with 1
# meaning true, and 0 meaning false. Does not alter the read position.
# Returns the buffer object.
def write_bool(*b)
b.each { |v| @content << (v ? "\1" : "\0") }
self
end
# Writes each argument to the buffer as a bignum (SSH2-style). No
# checking is done to ensure that the arguments are, in fact, bignums.
# Does not alter the read position. Returns the buffer object.
def write_bignum(*n)
@content << n.map { |b| b.to_ssh }.join
self
end
# Writes the given arguments to the buffer as SSH2-encoded keys. Does not
# alter the read position. Returns the buffer object.
def write_key(*key)
key.each { |k| append(k.to_blob) }
self
end
end
end; end;
net-ssh-4.2.0/lib/net/ssh/buffered_io.rb 0000664 0000000 0000000 00000014033 13153765720 0020037 0 ustar 00root root 0000000 0000000 require 'net/ssh/buffer'
require 'net/ssh/loggable'
require 'net/ssh/ruby_compat'
module Net; module SSH
# This module is used to extend sockets and other IO objects, to allow
# them to be buffered for both read and write. This abstraction makes it
# quite easy to write a select-based event loop
# (see Net::SSH::Connection::Session#listen_to).
#
# The general idea is that instead of calling #read directly on an IO that
# has been extended with this module, you call #fill (to add pending input
# to the internal read buffer), and then #read_available (to read from that
# buffer). Likewise, you don't call #write directly, you call #enqueue to
# add data to the write buffer, and then #send_pending or #wait_for_pending_sends
# to actually send the data across the wire.
#
# In this way you can easily use the object as an argument to IO.select,
# calling #fill when it is available for read, or #send_pending when it is
# available for write, and then call #enqueue and #read_available during
# the idle times.
#
# socket = TCPSocket.new(address, port)
# socket.extend(Net::SSH::BufferedIo)
#
# ssh.listen_to(socket)
#
# ssh.loop do
# if socket.available > 0
# puts socket.read_available
# socket.enqueue("response\n")
# end
# end
#
# Note that this module must be used to extend an instance, and should not
# be included in a class. If you do want to use it via an include, then you
# must make sure to invoke the private #initialize_buffered_io method in
# your class' #initialize method:
#
# class Foo < IO
# include Net::SSH::BufferedIo
#
# def initialize
# initialize_buffered_io
# # ...
# end
# end
module BufferedIo
include Loggable
# Called when the #extend is called on an object, with this module as the
# argument. It ensures that the modules instance variables are all properly
# initialized.
def self.extended(object) #:nodoc:
# need to use __send__ because #send is overridden in Socket
object.__send__(:initialize_buffered_io)
end
# Tries to read up to +n+ bytes of data from the remote end, and appends
# the data to the input buffer. It returns the number of bytes read, or 0
# if no data was available to be read.
def fill(n=8192)
input.consume!
data = recv(n)
debug { "read #{data.length} bytes" }
input.append(data)
return data.length
rescue EOFError => e
@input_errors << e
return 0
end
# Read up to +length+ bytes from the input buffer. If +length+ is nil,
# all available data is read from the buffer. (See #available.)
def read_available(length=nil)
input.read(length || available)
end
# Returns the number of bytes available to be read from the input buffer.
# (See #read_available.)
def available
input.available
end
# Enqueues data in the output buffer, to be written when #send_pending
# is called. Note that the data is _not_ sent immediately by this method!
def enqueue(data)
output.append(data)
end
# Returns +true+ if there is data waiting in the output buffer, and
# +false+ otherwise.
def pending_write?
output.length > 0
end
# Sends as much of the pending output as possible. Returns +true+ if any
# data was sent, and +false+ otherwise.
def send_pending
if output.length > 0
sent = send(output.to_s, 0)
debug { "sent #{sent} bytes" }
output.consume!(sent)
return sent > 0
else
return false
end
end
# Calls #send_pending repeatedly, if necessary, blocking until the output
# buffer is empty.
def wait_for_pending_sends
send_pending
while output.length > 0
result = Net::SSH::Compat.io_select(nil, [self]) or next
next unless result[1].any?
send_pending
end
end
public # these methods are primarily for use in tests
def write_buffer #:nodoc:
output.to_s
end
def read_buffer #:nodoc:
input.to_s
end
private
#--
# Can't use attr_reader here (after +private+) without incurring the
# wrath of "ruby -w". We hates it.
#++
def input; @input; end
def output; @output; end
# Initializes the intput and output buffers for this object. This method
# is called automatically when the module is mixed into an object via
# Object#extend (see Net::SSH::BufferedIo.extended), but must be called
# explicitly in the +initialize+ method of any class that uses
# Module#include to add this module.
def initialize_buffered_io
@input = Net::SSH::Buffer.new
@input_errors = []
@output = Net::SSH::Buffer.new
@output_errors = []
end
end
# Fixes for two issues by Miklós Fazekas:
#
# * if client closes a forwarded connection, but the server is
# reading, net-ssh terminates with IOError socket closed.
# * if client force closes (RST) a forwarded connection, but
# server is reading, net-ssh terminates with [an exception]
#
# See:
#
# http://net-ssh.lighthouseapp.com/projects/36253/tickets/7
# http://github.com/net-ssh/net-ssh/tree/portfwfix
#
module ForwardedBufferedIo
def fill(n=8192)
begin
super(n)
rescue Errno::ECONNRESET => e
debug { "connection was reset => shallowing exception:#{e}" }
return 0
rescue IOError => e
if e.message =~ /closed/ then
debug { "connection was reset => shallowing exception:#{e}" }
return 0
else
raise
end
end
end
def send_pending
begin
super
rescue Errno::ECONNRESET => e
debug { "connection was reset => shallowing exception:#{e}" }
return 0
rescue IOError => e
if e.message =~ /closed/ then
debug { "connection was reset => shallowing exception:#{e}" }
return 0
else
raise
end
end
end
end
end; end
net-ssh-4.2.0/lib/net/ssh/config.rb 0000664 0000000 0000000 00000030032 13153765720 0017030 0 ustar 00root root 0000000 0000000 module Net; module SSH
# The Net::SSH::Config class is used to parse OpenSSH configuration files,
# and translates that syntax into the configuration syntax that Net::SSH
# understands. This lets Net::SSH scripts read their configuration (to
# some extent) from OpenSSH configuration files (~/.ssh/config, /etc/ssh_config,
# and so forth).
#
# Only a subset of OpenSSH configuration options are understood:
#
# * ChallengeResponseAuthentication => maps to the :auth_methods option challenge-response (then coleasced into keyboard-interactive)
# * KbdInteractiveAuthentication => maps to the :auth_methods keyboard-interactive
# * Ciphers => maps to the :encryption option
# * Compression => :compression
# * CompressionLevel => :compression_level
# * ConnectTimeout => maps to the :timeout option
# * ForwardAgent => :forward_agent
# * GlobalKnownHostsFile => :global_known_hosts_file
# * HostBasedAuthentication => maps to the :auth_methods option
# * HostKeyAlgorithms => maps to :host_key option
# * HostKeyAlias => :host_key_alias
# * HostName => :host_name
# * IdentityFile => maps to the :keys option
# * IdentitiesOnly => :keys_only
# * Macs => maps to the :hmac option
# * PasswordAuthentication => maps to the :auth_methods option password
# * Port => :port
# * PreferredAuthentications => maps to the :auth_methods option
# * ProxyCommand => maps to the :proxy option
# * ProxyJump => maps to the :proxy option
# * PubKeyAuthentication => maps to the :auth_methods option
# * RekeyLimit => :rekey_limit
# * User => :user
# * UserKnownHostsFile => :user_known_hosts_file
# * NumberOfPasswordPrompts => :number_of_password_prompts
#
# Note that you will never need to use this class directly--you can control
# whether the OpenSSH configuration files are read by passing the :config
# option to Net::SSH.start. (They are, by default.)
class Config
class << self
@@default_files = %w(~/.ssh/config /etc/ssh_config /etc/ssh/ssh_config)
# The following defaults follow the openssh client ssh_config defaults.
# http://lwn.net/Articles/544640/
# "hostbased" is off and "none" is not supported but we allow it since
# it's used by some clients to query the server for allowed auth methods
@@default_auth_methods = %w(none publickey password keyboard-interactive)
# Returns an array of locations of OpenSSH configuration files
# to parse by default.
def default_files
@@default_files
end
def default_auth_methods
@@default_auth_methods
end
# Loads the configuration data for the given +host+ from all of the
# given +files+ (defaulting to the list of files returned by
# #default_files), translates the resulting hash into the options
# recognized by Net::SSH, and returns them.
def for(host, files=expandable_default_files)
translate(files.inject({}) { |settings, file|
load(file, host, settings)
})
end
# Load the OpenSSH configuration settings in the given +file+ for the
# given +host+. If +settings+ is given, the options are merged into
# that hash, with existing values taking precedence over newly parsed
# ones. Returns a hash containing the OpenSSH options. (See
# #translate for how to convert the OpenSSH options into Net::SSH
# options.)
def load(path, host, settings={}, base_dir = nil)
file = File.expand_path(path)
base_dir ||= File.dirname(file)
return settings unless File.readable?(file)
globals = {}
host_matched = false
seen_host = false
IO.foreach(file) do |line|
next if line =~ /^\s*(?:#.*)?$/
if line =~ /^\s*(\S+)\s*=(.*)$/
key, value = $1, $2
else
key, value = line.strip.split(/\s+/, 2)
end
# silently ignore malformed entries
next if value.nil?
key.downcase!
value = $1 if value =~ /^"(.*)"$/
value = case value.strip
when /^\d+$/ then value.to_i
when /^no$/i then false
when /^yes$/i then true
else value
end
if key == 'host'
# Support "Host host1 host2 hostN".
# See http://github.com/net-ssh/net-ssh/issues#issue/6
negative_hosts, positive_hosts = value.to_s.split(/\s+/).partition { |h| h.start_with?('!') }
# Check for negative patterns first. If the host matches, that overrules any other positive match.
# The host substring code is used to strip out the starting "!" so the regexp will be correct.
negative_matched = negative_hosts.any? { |h| host =~ pattern2regex(h[1..-1]) }
if negative_matched
host_matched = false
else
host_matched = positive_hosts.any? { |h| host =~ pattern2regex(h) }
end
seen_host = true
settings[key] = host
elsif !seen_host
case key
when 'identityfile'
(globals[key] ||= []) << value
when 'include'
included_file_paths(base_dir, value).each do |file_path|
globals = load(file_path, host, globals, base_dir)
end
else
globals[key] = value unless settings.key?(key)
end
elsif host_matched
case key
when 'identityfile'
(settings[key] ||= []) << value
when 'include'
included_file_paths(base_dir, value).each do |file_path|
settings = load(file_path, host, settings, base_dir)
end
else
settings[key] = value unless settings.key?(key)
end
end
end
if globals
settings = globals.merge(settings) do |key, oldval, newval|
case key
when 'identityfile'
oldval + newval
else
newval
end
end
end
return settings
end
# Given a hash of OpenSSH configuration options, converts them into
# a hash of Net::SSH options. Unrecognized options are ignored. The
# +settings+ hash must have Strings for keys, all downcased, and
# the returned hash will have Symbols for keys.
def translate(settings)
auth_methods = default_auth_methods.clone
(auth_methods << 'challenge-response').uniq!
ret = settings.inject({auth_methods: auth_methods}) do |hash, (key, value)|
translate_config_key(hash, key.to_sym, value, settings)
hash
end
merge_challenge_response_with_keyboard_interactive(ret)
end
# Filters default_files down to the files that are expandable.
def expandable_default_files
default_files.keep_if do |path|
begin
File.expand_path(path)
true
rescue ArgumentError
false
end
end
end
private
def translate_config_key(hash, key, value, settings)
rename = {
bindaddress: :bind_address,
compression: :compression,
compressionlevel: :compression_level,
connecttimeout: :timeout,
forwardagent: :forward_agent,
identitiesonly: :keys_only,
globalknownhostsfile: :global_known_hosts_file,
hostkeyalias: :host_key_alias,
identityfile: :keys,
port: :port,
user: :user,
userknownhostsfile: :user_known_hosts_file
}
case key
when :ciphers
hash[:encryption] = value.split(/,/)
when :hostbasedauthentication
if value
(hash[:auth_methods] << "hostbased").uniq!
else
hash[:auth_methods].delete("hostbased")
end
when :hostkeyalgorithms
hash[:host_key] = value.split(/,/)
when :hostname
hash[:host_name] = value.gsub(/%h/, settings['host'])
when :macs
hash[:hmac] = value.split(/,/)
when :serveralivecountmax
hash[:keepalive_maxcount] = value.to_i if value
when :serveraliveinterval
if value && value.to_i > 0
hash[:keepalive] = true
hash[:keepalive_interval] = value.to_i
else
hash[:keepalive] = false
end
when :passwordauthentication
if value
(hash[:auth_methods] << 'password').uniq!
else
hash[:auth_methods].delete('password')
end
when :challengeresponseauthentication
if value
(hash[:auth_methods] << 'challenge-response').uniq!
else
hash[:auth_methods].delete('challenge-response')
end
when :kbdinteractiveauthentication
if value
(hash[:auth_methods] << 'keyboard-interactive').uniq!
else
hash[:auth_methods].delete('keyboard-interactive')
end
when :preferredauthentications
hash[:auth_methods] = value.split(/,/) # TODO we should place to preferred_auth_methods rather than auth_methods
when :proxycommand
if value and !(value =~ /^none$/)
require 'net/ssh/proxy/command'
hash[:proxy] = Net::SSH::Proxy::Command.new(value)
end
when :proxyjump
if value
require 'net/ssh/proxy/jump'
hash[:proxy] = Net::SSH::Proxy::Jump.new(value)
end
when :pubkeyauthentication
if value
(hash[:auth_methods] << 'publickey').uniq!
else
hash[:auth_methods].delete('publickey')
end
when :rekeylimit
hash[:rekey_limit] = interpret_size(value)
when :sendenv
multi_send_env = value.to_s.split(/\s+/)
hash[:send_env] = multi_send_env.map { |e| Regexp.new pattern2regex(e).source, false }
when :numberofpasswordprompts
hash[:number_of_password_prompts] = value.to_i
when *rename.keys
hash[rename[key]] = value
end
end
# Converts an ssh_config pattern into a regex for matching against
# host names.
def pattern2regex(pattern)
tail = pattern
prefix = ""
while !tail.empty? do
head,sep,tail = tail.partition(/[\*\?]/)
prefix = prefix + Regexp.quote(head)
case sep
when '*'
prefix += '.*'
when '?'
prefix += '.'
when ''
else
fail "Unpexpcted sep:#{sep}"
end
end
Regexp.new("^" + prefix + "$", true)
end
# Converts the given size into an integer number of bytes.
def interpret_size(size)
case size
when /k$/i then size.to_i * 1024
when /m$/i then size.to_i * 1024 * 1024
when /g$/i then size.to_i * 1024 * 1024 * 1024
else size.to_i
end
end
def merge_challenge_response_with_keyboard_interactive(hash)
if hash[:auth_methods].include?('challenge-response')
hash[:auth_methods].delete('challenge-response')
(hash[:auth_methods] << 'keyboard-interactive').uniq!
end
hash
end
def included_file_paths(base_dir, config_paths)
tokenize_config_value(config_paths).flat_map do |path|
Dir.glob(File.expand_path(path, base_dir)).select { |f| File.file?(f) }
end
end
# Tokenize string into tokens.
# A token is a word or a quoted sequence of words, separated by whitespaces.
def tokenize_config_value(str)
str.scan(/([^"\s]+)?(?:"([^"]+)")?\s*/).map(&:join)
end
end
end
end; end
net-ssh-4.2.0/lib/net/ssh/connection/ 0000775 0000000 0000000 00000000000 13153765720 0017377 5 ustar 00root root 0000000 0000000 net-ssh-4.2.0/lib/net/ssh/connection/channel.rb 0000664 0000000 0000000 00000064702 13153765720 0021345 0 ustar 00root root 0000000 0000000 require 'net/ssh/loggable'
require 'net/ssh/connection/constants'
require 'net/ssh/connection/term'
module Net; module SSH; module Connection
# The channel abstraction. Multiple "channels" can be multiplexed onto a
# single SSH channel, each operating independently and seemingly in parallel.
# This class represents a single such channel. Most operations performed
# with the Net::SSH library will involve using one or more channels.
#
# Channels are intended to be used asynchronously. You request that one be
# opened (via Connection::Session#open_channel), and when it is opened, your
# callback is invoked. Then, you set various other callbacks on the newly
# opened channel, which are called in response to the corresponding events.
# Programming with Net::SSH works best if you think of your programs as
# state machines. Complex programs are best implemented as objects that
# wrap a channel. See Net::SCP and Net::SFTP for examples of how complex
# state machines can be built on top of the SSH protocol.
#
# ssh.open_channel do |channel|
# channel.exec("/invoke/some/command") do |ch, success|
# abort "could not execute command" unless success
#
# channel.on_data do |ch, data|
# puts "got stdout: #{data}"
# channel.send_data "something for stdin\n"
# end
#
# channel.on_extended_data do |ch, type, data|
# puts "got stderr: #{data}"
# end
#
# channel.on_close do |ch|
# puts "channel is closing!"
# end
# end
# end
#
# ssh.loop
#
# Channels also have a basic hash-like interface, that allows programs to
# store arbitrary state information on a channel object. This helps simplify
# the writing of state machines, especially when you may be juggling
# multiple open channels at the same time.
#
# Note that data sent across SSH channels are governed by maximum packet
# sizes and maximum window sizes. These details are managed internally
# by Net::SSH::Connection::Channel, so you may remain blissfully ignorant
# if you so desire, but you can always inspect the current maximums, as
# well as the remaining window size, using the reader attributes for those
# values.
class Channel
include Constants, Loggable
# The local id for this channel, assigned by the Net::SSH::Connection::Session instance.
attr_reader :local_id
# The remote id for this channel, assigned by the remote host.
attr_reader :remote_id
# The type of this channel, usually "session".
attr_reader :type
# The underlying Net::SSH::Connection::Session instance that supports this channel.
attr_reader :connection
# The maximum packet size that the local host can receive.
attr_reader :local_maximum_packet_size
# The maximum amount of data that the local end of this channel can
# receive. This is a total, not per-packet.
attr_reader :local_maximum_window_size
# The maximum packet size that the remote host can receive.
attr_reader :remote_maximum_packet_size
# The maximum amount of data that the remote end of this channel can
# receive. This is a total, not per-packet.
attr_reader :remote_maximum_window_size
# This is the remaining window size on the local end of this channel. When
# this reaches zero, no more data can be received.
attr_reader :local_window_size
# This is the remaining window size on the remote end of this channel. When
# this reaches zero, no more data can be sent.
attr_reader :remote_window_size
# A hash of properties for this channel. These can be used to store state
# information about this channel. See also #[] and #[]=.
attr_reader :properties
# The output buffer for this channel. Data written to the channel is
# enqueued here, to be written as CHANNEL_DATA packets during each pass of
# the event loop. See Connection::Session#process and #enqueue_pending_output.
attr_reader :output #:nodoc:
# The list of pending requests. Each time a request is sent which requires
# a reply, the corresponding callback is pushed onto this queue. As responses
# arrive, they are shifted off the front and handled.
attr_reader :pending_requests #:nodoc:
# Instantiates a new channel on the given connection, of the given type,
# and with the given id. If a block is given, it will be remembered until
# the channel is confirmed open by the server, and will be invoked at
# that time (see #do_open_confirmation).
#
# This also sets the default maximum packet size and maximum window size.
def initialize(connection, type, local_id, max_pkt_size = 0x8000, max_win_size = 0x20000, &on_confirm_open)
self.logger = connection.logger
@connection = connection
@type = type
@local_id = local_id
@local_maximum_packet_size = max_pkt_size
@local_window_size = @local_maximum_window_size = max_win_size
@on_confirm_open = on_confirm_open
@output = Buffer.new
@properties = {}
@pending_requests = []
@on_open_failed = @on_data = @on_extended_data = @on_process = @on_close = @on_eof = nil
@on_request = {}
@closing = @eof = @sent_eof = @local_closed = @remote_closed = false
end
# A shortcut for accessing properties of the channel (see #properties).
def [](name)
@properties[name]
end
# A shortcut for setting properties of the channel (see #properties).
def []=(name, value)
@properties[name] = value
end
# Syntactic sugar for executing a command. Sends a channel request asking
# that the given command be invoked. If the block is given, it will be
# called when the server responds. The first parameter will be the
# channel, and the second will be true or false, indicating whether the
# request succeeded or not. In this case, success means that the command
# is being executed, not that it has completed, and failure means that the
# command altogether failed to be executed.
#
# channel.exec "ls -l /home" do |ch, success|
# if success
# puts "command has begun executing..."
# # this is a good place to hang callbacks like #on_data...
# else
# puts "alas! the command could not be invoked!"
# end
# end
def exec(command, &block)
send_channel_request("exec", :string, command, &block)
end
# Syntactic sugar for requesting that a subsystem be started. Subsystems
# are a way for other protocols (like SFTP) to be run, using SSH as
# the transport. Generally, you'll never need to call this directly unless
# you are the implementor of something that consumes an SSH subsystem, like
# SFTP.
#
# channel.subsystem("sftp") do |ch, success|
# if success
# puts "subsystem successfully started"
# else
# puts "subsystem could not be started"
# end
# end
def subsystem(subsystem, &block)
send_channel_request("subsystem", :string, subsystem, &block)
end
# Syntactic sugar for setting an environment variable in the remote
# process' environment. Note that for security reasons, the server may
# refuse to set certain environment variables, or all, at the server's
# discretion. If you are connecting to an OpenSSH server, you will
# need to update the AcceptEnv setting in the sshd_config to include the
# environment variables you want to send.
#
# channel.env "PATH", "/usr/local/bin"
def env(variable_name, variable_value, &block)
send_channel_request("env", :string, variable_name, :string, variable_value, &block)
end
# A hash of the valid PTY options (see #request_pty).
VALID_PTY_OPTIONS = { term: "xterm",
chars_wide: 80,
chars_high: 24,
pixels_wide: 640,
pixels_high: 480,
modes: {} }
# Requests that a pseudo-tty (or "pty") be made available for this channel.
# This is useful when you want to invoke and interact with some kind of
# screen-based program (e.g., vim, or some menuing system).
#
# Note, that without a pty some programs (e.g. sudo, or subversion) on
# some systems, will not be able to run interactively, and will error
# instead of prompt if they ever need some user interaction.
#
# Note, too, that when a pty is requested, user's shell configuration
# scripts (.bashrc and such) are not run by default, whereas they are
# run when a pty is not present.
#
# channel.request_pty do |ch, success|
# if success
# puts "pty successfully obtained"
# else
# puts "could not obtain pty"
# end
# end
def request_pty(opts={}, &block)
extra = opts.keys - VALID_PTY_OPTIONS.keys
raise ArgumentError, "invalid option(s) to request_pty: #{extra.inspect}" if extra.any?
opts = VALID_PTY_OPTIONS.merge(opts)
modes = opts[:modes].inject(Buffer.new) do |memo, (mode, data)|
memo.write_byte(mode).write_long(data)
end
# mark the end of the mode opcode list with a 0 byte
modes.write_byte(0)
send_channel_request("pty-req", :string, opts[:term],
:long, opts[:chars_wide], :long, opts[:chars_high],
:long, opts[:pixels_wide], :long, opts[:pixels_high],
:string, modes.to_s, &block)
end
# Sends data to the channel's remote endpoint. This usually has the
# effect of sending the given string to the remote process' stdin stream.
# Note that it does not immediately send the data across the channel,
# but instead merely appends the given data to the channel's output buffer,
# preparatory to being packaged up and sent out the next time the connection
# is accepting data. (A connection might not be accepting data if, for
# instance, it has filled its data window and has not yet been resized by
# the remote end-point.)
#
# This will raise an exception if the channel has previously declared
# that no more data will be sent (see #eof!).
#
# channel.send_data("the password\n")
def send_data(data)
raise EOFError, "cannot send data if channel has declared eof" if eof?
output.append(data.to_s)
end
# Returns true if the channel exists in the channel list of the session,
# and false otherwise. This can be used to determine whether a channel has
# been closed or not.
#
# ssh.loop { channel.active? }
def active?
connection.channels.key?(local_id)
end
# Runs the SSH event loop until the channel is no longer active. This is
# handy for blocking while you wait for some channel to finish.
#
# channel.exec("grep ...") { ... }
# channel.wait
def wait
connection.loop { active? }
end
# True if close() has been called; NOTE: if the channel has data waiting to
# be sent then the channel will close after all the data is sent. See
# closed?() to determine if we have actually sent CHANNEL_CLOSE to server.
# This may be true for awhile before closed? returns true if we are still
# sending buffered output to server.
def closing?
@closing
end
# True if we have sent CHANNEL_CLOSE to the remote server.
def local_closed?
@local_closed
end
def remote_closed?
@remote_closed
end
def remote_closed!
@remote_closed = true
end
# Requests that the channel be closed. It only marks the channel to be closed
# the CHANNEL_CLOSE message will be sent from event loop
def close
return if @closing
@closing = true
end
# Returns true if the local end of the channel has declared that no more
# data is forthcoming (see #eof!). Trying to send data via #send_data when
# this is true will result in an exception being raised.
def eof?
@eof
end
# Tells the remote end of the channel that no more data is forthcoming
# from this end of the channel. The remote end may still send data.
# The CHANNEL_EOF packet will be sent once the output buffer is empty.
def eof!
return if eof?
@eof = true
end
# If an #on_process handler has been set up, this will cause it to be
# invoked (passing the channel itself as an argument). It also causes all
# pending output to be enqueued as CHANNEL_DATA packets (see #enqueue_pending_output).
def process
@on_process.call(self) if @on_process
enqueue_pending_output
if @eof and not @sent_eof and output.empty? and remote_id and not @local_closed
connection.send_message(Buffer.from(:byte, CHANNEL_EOF, :long, remote_id))
@sent_eof = true
end
if @closing and not @local_closed and output.empty? and remote_id
connection.send_message(Buffer.from(:byte, CHANNEL_CLOSE, :long, remote_id))
@local_closed = true
connection.cleanup_channel(self)
end
end
# Registers a callback to be invoked when data packets are received by the
# channel. The callback is called with the channel as the first argument,
# and the data as the second.
#
# channel.on_data do |ch, data|
# puts "got data: #{data.inspect}"
# end
#
# Data received this way is typically the data written by the remote
# process to its +stdout+ stream.
def on_data(&block)
old, @on_data = @on_data, block
old
end
# Registers a callback to be invoked when extended data packets are received
# by the channel. The callback is called with the channel as the first
# argument, the data type (as an integer) as the second, and the data as
# the third. Extended data is almost exclusively used to send +stderr+ data
# (+type+ == 1). Other extended data types are not defined by the SSH
# protocol.
#
# channel.on_extended_data do |ch, type, data|
# puts "got stderr: #{data.inspect}"
# end
def on_extended_data(&block)
old, @on_extended_data = @on_extended_data, block
old
end
# Registers a callback to be invoked for each pass of the event loop for
# this channel. There are no guarantees on timeliness in the event loop,
# but it will be called roughly once for each packet received by the
# connection (not the channel). This callback is invoked with the channel
# as the sole argument.
#
# Here's an example that accumulates the channel data into a variable on
# the channel itself, and displays individual lines in the input one
# at a time when the channel is processed:
#
# channel[:data] = ""
#
# channel.on_data do |ch, data|
# channel[:data] << data
# end
#
# channel.on_process do |ch|
# if channel[:data] =~ /^.*?\n/
# puts $&
# channel[:data] = $'
# end
# end
def on_process(&block)
old, @on_process = @on_process, block
old
end
# Registers a callback to be invoked when the server acknowledges that a
# channel is closed. This is invoked with the channel as the sole argument.
#
# channel.on_close do |ch|
# puts "remote end is closing!"
# end
def on_close(&block)
old, @on_close = @on_close, block
old
end
# Registers a callback to be invoked when the server indicates that no more
# data will be sent to the channel (although the channel can still send
# data to the server). The channel is the sole argument to the callback.
#
# channel.on_eof do |ch|
# puts "remote end is done sending data"
# end
def on_eof(&block)
old, @on_eof = @on_eof, block
old
end
# Registers a callback to be invoked when the server was unable to open
# the requested channel. The channel itself will be passed to the block,
# along with the integer "reason code" for the failure, and a textual
# description of the failure from the server.
#
# channel = session.open_channel do |ch|
# # ..
# end
#
# channel.on_open_failed { |ch, code, desc| ... }
def on_open_failed(&block)
old, @on_open_failed = @on_open_failed, block
old
end
# Registers a callback to be invoked when a channel request of the given
# type is received. The callback will receive the channel as the first
# argument, and the associated (unparsed) data as the second. The data
# will be a Net::SSH::Buffer that you will need to parse, yourself,
# according to the kind of request you are watching.
#
# By default, if the request wants a reply, Net::SSH will send a
# CHANNEL_SUCCESS response for any request that was handled by a registered
# callback, and CHANNEL_FAILURE for any that wasn't, but if you want your
# registered callback to result in a CHANNEL_FAILURE response, just raise
# Net::SSH::ChannelRequestFailed.
#
# Some common channel requests that your programs might want to listen
# for are:
#
# * "exit-status" : the exit status of the remote process will be reported
# as a long integer in the data buffer, which you can grab via
# data.read_long.
# * "exit-signal" : if the remote process died as a result of a signal
# being sent to it, the signal will be reported as a string in the
# data, via data.read_string. (Not all SSH servers support this channel
# request type.)
#
# channel.on_request "exit-status" do |ch, data|
# puts "process terminated with exit status: #{data.read_long}"
# end
def on_request(type, &block)
old, @on_request[type] = @on_request[type], block
old
end
# Sends a new channel request with the given name. The extra +data+
# parameter must either be empty, or consist of an even number of
# arguments. See Net::SSH::Buffer.from for a description of their format.
# If a block is given, it is registered as a callback for a pending
# request, and the packet will be flagged so that the server knows a
# reply is required. If no block is given, the server will send no
# response to this request. Responses, where required, will cause the
# callback to be invoked with the channel as the first argument, and
# either true or false as the second, depending on whether the request
# succeeded or not. The meaning of "success" and "failure" in this context
# is dependent on the specific request that was sent.
#
# channel.send_channel_request "shell" do |ch, success|
# if success
# puts "user shell started successfully"
# else
# puts "could not start user shell"
# end
# end
#
# Most channel requests you'll want to send are already wrapped in more
# convenient helper methods (see #exec and #subsystem).
def send_channel_request(request_name, *data, &callback)
info { "sending channel request #{request_name.inspect}" }
fail "Channel open not yet confirmed, please call send_channel_request(or exec) from block of open_channel" unless remote_id
msg = Buffer.from(:byte, CHANNEL_REQUEST,
:long, remote_id, :string, request_name,
:bool, !callback.nil?, *data)
connection.send_message(msg)
pending_requests << callback if callback
end
public # these methods are public, but for Net::SSH internal use only
# Enqueues pending output at the connection as CHANNEL_DATA packets. This
# does nothing if the channel has not yet been confirmed open (see
# #do_open_confirmation). This is called automatically by #process, which
# is called from the event loop (Connection::Session#process). You will
# generally not need to invoke it directly.
def enqueue_pending_output #:nodoc:
return unless remote_id
while output.length > 0
length = output.length
length = remote_window_size if length > remote_window_size
length = remote_maximum_packet_size if length > remote_maximum_packet_size
if length > 0
connection.send_message(Buffer.from(:byte, CHANNEL_DATA, :long, remote_id, :string, output.read(length)))
output.consume!
@remote_window_size -= length
else
break
end
end
end
# Invoked when the server confirms that a channel has been opened.
# The remote_id is the id of the channel as assigned by the remote host,
# and max_window and max_packet are the maximum window and maximum
# packet sizes, respectively. If an open-confirmation callback was
# given when the channel was created, it is invoked at this time with
# the channel itself as the sole argument.
def do_open_confirmation(remote_id, max_window, max_packet) #:nodoc:
@remote_id = remote_id
@remote_window_size = @remote_maximum_window_size = max_window
@remote_maximum_packet_size = max_packet
connection.forward.agent(self) if connection.options[:forward_agent] && type == "session"
forward_local_env(connection.options[:send_env]) if connection.options[:send_env]
@on_confirm_open.call(self) if @on_confirm_open
end
# Invoked when the server failed to open the channel. If an #on_open_failed
# callback was specified, it will be invoked with the channel, reason code,
# and description as arguments. Otherwise, a ChannelOpenFailed exception
# will be raised.
def do_open_failed(reason_code, description)
if @on_open_failed
@on_open_failed.call(self, reason_code, description)
else
raise ChannelOpenFailed.new(reason_code, description)
end
end
# Invoked when the server sends a CHANNEL_WINDOW_ADJUST packet, and
# causes the remote window size to be adjusted upwards by the given
# number of bytes. This has the effect of allowing more data to be sent
# from the local end to the remote end of the channel.
def do_window_adjust(bytes) #:nodoc:
@remote_maximum_window_size += bytes
@remote_window_size += bytes
end
# Invoked when the server sends a channel request. If any #on_request
# callback has been registered for the specific type of this request,
# it is invoked. If +want_reply+ is true, a packet will be sent of
# either CHANNEL_SUCCESS or CHANNEL_FAILURE type. If there was no callback
# to handle the request, CHANNEL_FAILURE will be sent. Otherwise,
# CHANNEL_SUCCESS, unless the callback raised ChannelRequestFailed. The
# callback should accept the channel as the first argument, and the
# request-specific data as the second.
def do_request(request, want_reply, data) #:nodoc:
result = true
begin
callback = @on_request[request] or raise ChannelRequestFailed
callback.call(self, data)
rescue ChannelRequestFailed
result = false
end
if want_reply
msg = Buffer.from(:byte, result ? CHANNEL_SUCCESS : CHANNEL_FAILURE, :long, remote_id)
connection.send_message(msg)
end
end
# Invokes the #on_data callback when the server sends data to the
# channel. This will reduce the available window size on the local end,
# but does not actually throttle requests that come in illegally when
# the window size is too small. The callback is invoked with the channel
# as the first argument, and the data as the second.
def do_data(data) #:nodoc:
update_local_window_size(data.length)
@on_data.call(self, data) if @on_data
end
# Invokes the #on_extended_data callback when the server sends
# extended data to the channel. This will reduce the available window
# size on the local end. The callback is invoked with the channel,
# type, and data.
def do_extended_data(type, data)
update_local_window_size(data.length)
@on_extended_data.call(self, type, data) if @on_extended_data
end
# Invokes the #on_eof callback when the server indicates that no
# further data is forthcoming. The callback is invoked with the channel
# as the argument.
def do_eof
@on_eof.call(self) if @on_eof
end
# Invokes the #on_close callback when the server closes a channel.
# The channel is the only argument.
def do_close
@on_close.call(self) if @on_close
end
# Invokes the next pending request callback with +false+ as the second
# argument.
def do_failure
if callback = pending_requests.shift
callback.call(self, false)
else
error { "channel failure received with no pending request to handle it (bug?)" }
end
end
# Invokes the next pending request callback with +true+ as the second
# argument.
def do_success
if callback = pending_requests.shift
callback.call(self, true)
else
error { "channel success received with no pending request to handle it (bug?)" }
end
end
private
# Runs the SSH event loop until the remote confirmed channel open
# experimental api
def wait_until_open_confirmed
connection.loop { !remote_id }
end
# Updates the local window size by the given amount. If the window
# size drops to less than half of the local maximum (an arbitrary
# threshold), a CHANNEL_WINDOW_ADJUST message will be sent to the
# server telling it that the window size has grown.
def update_local_window_size(size)
@local_window_size -= size
if local_window_size < local_maximum_window_size/2
connection.send_message(Buffer.from(:byte, CHANNEL_WINDOW_ADJUST,
:long, remote_id, :long, 0x20000))
@local_window_size += 0x20000
@local_maximum_window_size += 0x20000
end
end
# Gets an +Array+ of local environment variables in the remote process'
# environment.
# A variable name can either be described by a +Regexp+ or +String+.
#
# channel.forward_local_env [/^GIT_.*$/, "LANG"]
def forward_local_env(env_variable_patterns)
Array(env_variable_patterns).each do |env_variable_pattern|
matched_variables = ENV.find_all do |env_name, _|
case env_variable_pattern
when Regexp then env_name =~ env_variable_pattern
when String then env_name == env_variable_pattern
end
end
matched_variables.each do |env_name, env_value|
self.env(env_name, env_value)
end
end
end
end
end; end; end
net-ssh-4.2.0/lib/net/ssh/connection/constants.rb 0000664 0000000 0000000 00000001413 13153765720 0021737 0 ustar 00root root 0000000 0000000 module Net; module SSH; module Connection
# Definitions of constants that are specific to the connection layer of the
# SSH protocol.
module Constants
#--
# Connection protocol generic messages
#++
GLOBAL_REQUEST = 80
REQUEST_SUCCESS = 81
REQUEST_FAILURE = 82
#--
# Channel related messages
#++
CHANNEL_OPEN = 90
CHANNEL_OPEN_CONFIRMATION = 91
CHANNEL_OPEN_FAILURE = 92
CHANNEL_WINDOW_ADJUST = 93
CHANNEL_DATA = 94
CHANNEL_EXTENDED_DATA = 95
CHANNEL_EOF = 96
CHANNEL_CLOSE = 97
CHANNEL_REQUEST = 98
CHANNEL_SUCCESS = 99
CHANNEL_FAILURE = 100
end
end; end end net-ssh-4.2.0/lib/net/ssh/connection/event_loop.rb 0000664 0000000 0000000 00000006516 13153765720 0022106 0 ustar 00root root 0000000 0000000 require 'net/ssh/loggable'
require 'net/ssh/ruby_compat'
module Net; module SSH; module Connection
# EventLoop can be shared across multiple sessions
#
# one issue is with blocks passed to loop, etc.
# they should get current session as parameter, but in
# case you're using multiple sessions in an event loop it doesnt makes sense
# and we don't pass session.
class EventLoop
include Loggable
def initialize(logger=nil)
self.logger = logger
@sessions = []
end
def register(session)
@sessions << session
end
# process until timeout
# if a block is given a session will be removed from loop
# if block returns false for that session
def process(wait = nil, &block)
return false unless ev_preprocess(&block)
ev_select_and_postprocess(wait)
end
# process the event loop but only for the sepcified session
def process_only(session, wait = nil)
orig_sessions = @sessions
begin
@sessions = [session]
return false unless ev_preprocess
ev_select_and_postprocess(wait)
ensure
@sessions = orig_sessions
end
end
# Call preprocess on each session. If block given and that
# block retuns false then we exit the processing
def ev_preprocess(&block)
return false if block_given? && !yield(self)
@sessions.each(&:ev_preprocess)
return false if block_given? && !yield(self)
return true
end
def ev_select_and_postprocess(wait)
owners = {}
r = []
w = []
minwait = nil
@sessions.each do |session|
sr,sw,actwait = session.ev_do_calculate_rw_wait(wait)
minwait = actwait if actwait && (minwait.nil? || actwait < minwait)
r.push(*sr)
w.push(*sw)
sr.each { |ri| owners[ri] = session }
sw.each { |wi| owners[wi] = session }
end
readers, writers, = Net::SSH::Compat.io_select(r, w, nil, minwait)
fired_sessions = {}
if readers
readers.each do |reader|
session = owners[reader]
(fired_sessions[session] ||= {r: [],w: []})[:r] << reader
end
end
if writers
writers.each do |writer|
session = owners[writer]
(fired_sessions[session] ||= {r: [],w: []})[:w] << writer
end
end
fired_sessions.each do |s,rw|
s.ev_do_handle_events(rw[:r],rw[:w])
end
@sessions.each { |s| s.ev_do_postprocess(fired_sessions.key?(s)) }
true
end
end
# optimized version for a single session
class SingleSessionEventLoop < EventLoop
# Compatibility for original single session event loops:
# we call block with session as argument
def ev_preprocess(&block)
return false if block_given? && !yield(@sessions.first)
@sessions.each(&:ev_preprocess)
return false if block_given? && !yield(@sessions.first)
return true
end
def ev_select_and_postprocess(wait)
raise "Only one session expected" unless @sessions.count == 1
session = @sessions.first
sr,sw,actwait = session.ev_do_calculate_rw_wait(wait)
readers, writers, = Net::SSH::Compat.io_select(sr, sw, nil, actwait)
session.ev_do_handle_events(readers,writers)
session.ev_do_postprocess(!((readers.nil? || readers.empty?) && (writers.nil? || writers.empty?)))
end
end
end; end; end
net-ssh-4.2.0/lib/net/ssh/connection/keepalive.rb 0000664 0000000 0000000 00000002726 13153765720 0021700 0 ustar 00root root 0000000 0000000 require 'net/ssh/loggable'
module Net; module SSH; module Connection
class Keepalive
include Loggable
def initialize(session)
@last_keepalive_sent_at = nil
@unresponded_keepalive_count = 0
@session = session
self.logger = session.logger
end
def options
@session.options
end
def enabled?
options[:keepalive]
end
def interval
options[:keepalive_interval] || Session::DEFAULT_IO_SELECT_TIMEOUT
end
def should_send?
return false unless enabled?
return true unless @last_keepalive_sent_at
Time.now - @last_keepalive_sent_at >= interval
end
def keepalive_maxcount
(options[:keepalive_maxcount] || 3).to_i
end
def send_as_needed(was_events)
return if was_events
return unless should_send?
info { "sending keepalive #{@unresponded_keepalive_count}" }
@unresponded_keepalive_count += 1
@session.send_global_request("keepalive@openssh.com") { |success, response|
debug { "keepalive response successful. Missed #{@unresponded_keepalive_count-1} keepalives" }
@unresponded_keepalive_count = 0
}
@last_keepalive_sent_at = Time.now
if keepalive_maxcount > 0 && @unresponded_keepalive_count > keepalive_maxcount
error { "Timeout, server #{@session.host} not responding. Missed #{@unresponded_keepalive_count-1} timeouts." }
@unresponded_keepalive_count = 0
raise Net::SSH::Timeout, "Timeout, server #{@session.host} not responding."
end
end
end
end; end; end
net-ssh-4.2.0/lib/net/ssh/connection/session.rb 0000664 0000000 0000000 00000063403 13153765720 0021415 0 ustar 00root root 0000000 0000000 require 'net/ssh/loggable'
require 'net/ssh/ruby_compat'
require 'net/ssh/connection/channel'
require 'net/ssh/connection/constants'
require 'net/ssh/service/forward'
require 'net/ssh/connection/keepalive'
require 'net/ssh/connection/event_loop'
module Net; module SSH; module Connection
# A session class representing the connection service running on top of
# the SSH transport layer. It manages the creation of channels (see
# #open_channel), and the dispatching of messages to the various channels.
# It also encapsulates the SSH event loop (via #loop and #process),
# and serves as a central point-of-reference for all SSH-related services (e.g.
# port forwarding, SFTP, SCP, etc.).
#
# You will rarely (if ever) need to instantiate this class directly; rather,
# you'll almost always use Net::SSH.start to initialize a new network
# connection, authenticate a user, and return a new connection session,
# all in one call.
#
# Net::SSH.start("localhost", "user") do |ssh|
# # 'ssh' is an instance of Net::SSH::Connection::Session
# ssh.exec! "/etc/init.d/some_process start"
# end
class Session
include Constants, Loggable
# Default IO.select timeout threshold
DEFAULT_IO_SELECT_TIMEOUT = 300
# The underlying transport layer abstraction (see Net::SSH::Transport::Session).
attr_reader :transport
# The map of options that were used to initialize this instance.
attr_reader :options
# The collection of custom properties for this instance. (See #[] and #[]=).
attr_reader :properties
# The map of channels, each key being the local-id for the channel.
attr_reader :channels #:nodoc:
# The map of listeners that the event loop knows about. See #listen_to.
attr_reader :listeners #:nodoc:
# The map of specialized handlers for opening specific channel types. See
# #on_open_channel.
attr_reader :channel_open_handlers #:nodoc:
# The list of callbacks for pending requests. See #send_global_request.
attr_reader :pending_requests #:nodoc:
class NilChannel
def initialize(session)
@session = session
end
def method_missing(sym, *args)
@session.lwarn { "ignoring request #{sym.inspect} for non-existent (closed?) channel; probably ssh server bug" }
end
end
# Create a new connection service instance atop the given transport
# layer. Initializes the listeners to be only the underlying socket object.
def initialize(transport, options={})
self.logger = transport.logger
@transport = transport
@options = options
@channel_id_counter = -1
@channels = Hash.new(NilChannel.new(self))
@listeners = { transport.socket => nil }
@pending_requests = []
@channel_open_handlers = {}
@on_global_request = {}
@properties = (options[:properties] || {}).dup
@max_pkt_size = (options.key?(:max_pkt_size) ? options[:max_pkt_size] : 0x8000)
@max_win_size = (options.key?(:max_win_size) ? options[:max_win_size] : 0x20000)
@keepalive = Keepalive.new(self)
@event_loop = options[:event_loop] || SingleSessionEventLoop.new
@event_loop.register(self)
end
# Retrieves a custom property from this instance. This can be used to
# store additional state in applications that must manage multiple
# SSH connections.
def [](key)
@properties[key]
end
# Sets a custom property for this instance.
def []=(key, value)
@properties[key] = value
end
# Returns the name of the host that was given to the transport layer to
# connect to.
def host
transport.host
end
# Returns true if the underlying transport has been closed. Note that
# this can be a little misleading, since if the remote server has
# closed the connection, the local end will still think it is open
# until the next operation on the socket. Nevertheless, this method can
# be useful if you just want to know if _you_ have closed the connection.
def closed?
transport.closed?
end
# Closes the session gracefully, blocking until all channels have
# successfully closed, and then closes the underlying transport layer
# connection.
def close
info { "closing remaining channels (#{channels.length} open)" }
channels.each { |id, channel| channel.close }
begin
loop(0.1) { channels.any? }
rescue Net::SSH::Disconnect
raise unless channels.empty?
end
transport.close
end
# Performs a "hard" shutdown of the connection. In general, this should
# never be done, but it might be necessary (in a rescue clause, for instance,
# when the connection needs to close but you don't know the status of the
# underlying protocol's state).
def shutdown!
transport.shutdown!
end
# preserve a reference to Kernel#loop
alias :loop_forever :loop
# Returns +true+ if there are any channels currently active on this
# session. By default, this will not include "invisible" channels
# (such as those created by forwarding ports and such), but if you pass
# a +true+ value for +include_invisible+, then those will be counted.
#
# This can be useful for determining whether the event loop should continue
# to be run.
#
# ssh.loop { ssh.busy? }
def busy?(include_invisible=false)
if include_invisible
channels.any?
else
channels.any? { |id, ch| !ch[:invisible] }
end
end
# The main event loop. Calls #process until #process returns false. If a
# block is given, it is passed to #process, otherwise a default proc is
# used that just returns true if there are any channels active (see #busy?).
# The # +wait+ parameter is also passed through to #process (where it is
# interpreted as the maximum number of seconds to wait for IO.select to return).
#
# # loop for as long as there are any channels active
# ssh.loop
#
# # loop for as long as there are any channels active, but make sure
# # the event loop runs at least once per 0.1 second
# ssh.loop(0.1)
#
# # loop until ctrl-C is pressed
# int_pressed = false
# trap("INT") { int_pressed = true }
# ssh.loop(0.1) { not int_pressed }
def loop(wait=nil, &block)
running = block || Proc.new { busy? }
loop_forever { break unless process(wait, &running) }
begin
process(0)
rescue IOError => e
if e.message =~ /closed/
debug { "stream was closed after loop => shallowing exception so it will be re-raised in next loop" }
else
raise
end
end
end
# The core of the event loop. It processes a single iteration of the event
# loop. If a block is given, it should return false when the processing
# should abort, which causes #process to return false. Otherwise,
# #process returns true. The session itself is yielded to the block as its
# only argument.
#
# If +wait+ is nil (the default), this method will block until any of the
# monitored IO objects are ready to be read from or written to. If you want
# it to not block, you can pass 0, or you can pass any other numeric value
# to indicate that it should block for no more than that many seconds.
# Passing 0 is a good way to poll the connection, but if you do it too
# frequently it can make your CPU quite busy!
#
# This will also cause all active channels to be processed once each (see
# Net::SSH::Connection::Channel#on_process).
#
# TODO revise example
#
# # process multiple Net::SSH connections in parallel
# connections = [
# Net::SSH.start("host1", ...),
# Net::SSH.start("host2", ...)
# ]
#
# connections.each do |ssh|
# ssh.exec "grep something /in/some/files"
# end
#
# condition = Proc.new { |s| s.busy? }
#
# loop do
# connections.delete_if { |ssh| !ssh.process(0.1, &condition) }
# break if connections.empty?
# end
def process(wait=nil, &block)
@event_loop.process(wait, &block)
rescue
force_channel_cleanup_on_close if closed?
raise
end
# This is called internally as part of #process. It dispatches any
# available incoming packets, and then runs Net::SSH::Connection::Channel#process
# for any active channels. If a block is given, it is invoked at the
# start of the method and again at the end, and if the block ever returns
# false, this method returns false. Otherwise, it returns true.
def preprocess(&block)
return false if block_given? && !yield(self)
ev_preprocess(&block)
return false if block_given? && !yield(self)
return true
end
# Called by event loop to process available data before going to
# event multiplexing
def ev_preprocess(&block)
dispatch_incoming_packets(raise_disconnect_errors: false)
each_channel { |id, channel| channel.process unless channel.local_closed? }
end
# Returns the file descriptors the event loop should wait for read/write events,
# we also return the max wait
def ev_do_calculate_rw_wait(wait)
r = listeners.keys
w = r.select { |w2| w2.respond_to?(:pending_write?) && w2.pending_write? }
[r,w,io_select_wait(wait)]
end
# This is called internally as part of #process.
def postprocess(readers, writers)
ev_do_handle_events(readers, writers)
end
# It loops over the given arrays of reader IO's and writer IO's,
# processing them as needed, and
# then calls Net::SSH::Transport::Session#rekey_as_needed to allow the
# transport layer to rekey. Then returns true.
def ev_do_handle_events(readers, writers)
Array(readers).each do |reader|
if listeners[reader]
listeners[reader].call(reader)
else
if reader.fill.zero?
reader.close
stop_listening_to(reader)
end
end
end
Array(writers).each do |writer|
writer.send_pending
end
end
# calls Net::SSH::Transport::Session#rekey_as_needed to allow the
# transport layer to rekey
def ev_do_postprocess(was_events)
@keepalive.send_as_needed(was_events)
transport.rekey_as_needed
true
end
# Send a global request of the given type. The +extra+ parameters must
# be even in number, and conform to the same format as described for
# Net::SSH::Buffer.from. If a callback is not specified, the request will
# not require a response from the server, otherwise the server is required
# to respond and indicate whether the request was successful or not. This
# success or failure is indicated by the callback being invoked, with the
# first parameter being true or false (success, or failure), and the second
# being the packet itself.
#
# Generally, Net::SSH will manage global requests that need to be sent
# (e.g. port forward requests and such are handled in the Net::SSH::Service::Forward
# class, for instance). However, there may be times when you need to
# send a global request that isn't explicitly handled by Net::SSH, and so
# this method is available to you.
#
# ssh.send_global_request("keep-alive@openssh.com")
def send_global_request(type, *extra, &callback)
info { "sending global request #{type}" }
msg = Buffer.from(:byte, GLOBAL_REQUEST, :string, type.to_s, :bool, !callback.nil?, *extra)
send_message(msg)
pending_requests << callback if callback
self
end
# Requests that a new channel be opened. By default, the channel will be
# of type "session", but if you know what you're doing you can select any
# of the channel types supported by the SSH protocol. The +extra+ parameters
# must be even in number and conform to the same format as described for
# Net::SSH::Buffer.from. If a callback is given, it will be invoked when
# the server confirms that the channel opened successfully. The sole parameter
# for the callback is the channel object itself.
#
# In general, you'll use #open_channel without any arguments; the only
# time you'd want to set the channel type or pass additional initialization
# data is if you were implementing an SSH extension.
#
# channel = ssh.open_channel do |ch|
# ch.exec "grep something /some/files" do |ch, success|
# ...
# end
# end
#
# channel.wait
def open_channel(type="session", *extra, &on_confirm)
local_id = get_next_channel_id
channel = Channel.new(self, type, local_id, @max_pkt_size, @max_win_size, &on_confirm)
msg = Buffer.from(:byte, CHANNEL_OPEN, :string, type, :long, local_id,
:long, channel.local_maximum_window_size,
:long, channel.local_maximum_packet_size, *extra)
send_message(msg)
channels[local_id] = channel
end
class StringWithExitstatus < String
def initialize(str, exitstatus)
super(str)
@exitstatus = exitstatus
end
attr_reader :exitstatus
end
# A convenience method for executing a command and interacting with it. If
# no block is given, all output is printed via $stdout and $stderr. Otherwise,
# the block is called for each data and extended data packet, with three
# arguments: the channel object, a symbol indicating the data type
# (:stdout or :stderr), and the data (as a string).
#
# Note that this method returns immediately, and requires an event loop
# (see Session#loop) in order for the command to actually execute.
#
# This is effectively identical to calling #open_channel, and then
# Net::SSH::Connection::Channel#exec, and then setting up the channel
# callbacks. However, for most uses, this will be sufficient.
#
# ssh.exec "grep something /some/files" do |ch, stream, data|
# if stream == :stderr
# puts "ERROR: #{data}"
# else
# puts data
# end
# end
def exec(command, status: nil, &block)
open_channel do |channel|
channel.exec(command) do |ch, success|
raise "could not execute command: #{command.inspect}" unless success
if status
channel.on_request("exit-status") do |ch2,data|
status[:exit_code] = data.read_long
end
channel.on_request("exit-signal") do |ch2, data|
status[:exit_signal] = data.read_long
end
end
channel.on_data do |ch2, data|
if block
block.call(ch2, :stdout, data)
else
$stdout.print(data)
end
end
channel.on_extended_data do |ch2, type, data|
if block
block.call(ch2, :stderr, data)
else
$stderr.print(data)
end
end
end
end
end
# Same as #exec, except this will block until the command finishes. Also,
# if no block is given, this will return all output (stdout and stderr)
# as a single string.
#
# matches = ssh.exec!("grep something /some/files")
#
# the returned string has an exitstatus method to query it's exit satus
def exec!(command, status: nil, &block)
block_or_concat = block || Proc.new do |ch, type, data|
ch[:result] ||= ""
ch[:result] << data
end
status ||= {}
channel = exec(command, status: status, &block_or_concat)
channel.wait
channel[:result] ||= "" unless block
channel[:result] &&= channel[:result].force_encoding("UTF-8") unless block
StringWithExitstatus.new(channel[:result], status[:exit_code]) if channel[:result]
end
# Enqueues a message to be sent to the server as soon as the socket is
# available for writing. Most programs will never need to call this, but
# if you are implementing an extension to the SSH protocol, or if you
# need to send a packet that Net::SSH does not directly support, you can
# use this to send it.
#
# ssh.send_message(Buffer.from(:byte, REQUEST_SUCCESS).to_s)
def send_message(message)
transport.enqueue_message(message)
end
# Adds an IO object for the event loop to listen to. If a callback
# is given, it will be invoked when the io is ready to be read, otherwise,
# the io will merely have its #fill method invoked.
#
# Any +io+ value passed to this method _must_ have mixed into it the
# Net::SSH::BufferedIo functionality, typically by calling #extend on the
# object.
#
# The following example executes a process on the remote server, opens
# a socket to somewhere, and then pipes data from that socket to the
# remote process' stdin stream:
#
# channel = ssh.open_channel do |ch|
# ch.exec "/some/process/that/wants/input" do |ch, success|
# abort "can't execute!" unless success
#
# io = TCPSocket.new(somewhere, port)
# io.extend(Net::SSH::BufferedIo)
# ssh.listen_to(io)
#
# ch.on_process do
# if io.available > 0
# ch.send_data(io.read_available)
# end
# end
#
# ch.on_close do
# ssh.stop_listening_to(io)
# io.close
# end
# end
# end
#
# channel.wait
def listen_to(io, &callback)
listeners[io] = callback
end
# Removes the given io object from the listeners collection, so that the
# event loop will no longer monitor it.
def stop_listening_to(io)
listeners.delete(io)
end
# Returns a reference to the Net::SSH::Service::Forward service, which can
# be used for forwarding ports over SSH.
def forward
@forward ||= Service::Forward.new(self)
end
# Registers a handler to be invoked when the server wants to open a
# channel on the client. The callback receives the connection object,
# the new channel object, and the packet itself as arguments, and should
# raise ChannelOpenFailed if it is unable to open the channel for some
# reason. Otherwise, the channel will be opened and a confirmation message
# sent to the server.
#
# This is used by the Net::SSH::Service::Forward service to open a channel
# when a remote forwarded port receives a connection. However, you are
# welcome to register handlers for other channel types, as needed.
def on_open_channel(type, &block)
channel_open_handlers[type] = block
end
# Registers a handler to be invoked when the server sends a global request
# of the given type. The callback receives the request data as the first
# parameter, and true/false as the second (indicating whether a response
# is required). If the callback sends the response, it should return
# :sent. Otherwise, if it returns true, REQUEST_SUCCESS will be sent, and
# if it returns false, REQUEST_FAILURE will be sent.
def on_global_request(type, &block)
old, @on_global_request[type] = @on_global_request[type], block
old
end
def cleanup_channel(channel)
if channel.local_closed? and channel.remote_closed?
info { "#{host} delete channel #{channel.local_id} which closed locally and remotely" }
channels.delete(channel.local_id)
end
end
# If the #preprocess and #postprocess callbacks for this session need to run
# periodically, this method returns the maximum number of seconds which may
# pass between callbacks.
def max_select_wait_time
@keepalive.interval if @keepalive.enabled?
end
private
# iterate channels with the posibility of callbacks opening new channels during the iteration
def each_channel(&block)
channels.dup.each(&block)
end
# Read all pending packets from the connection and dispatch them as
# appropriate. Returns as soon as there are no more pending packets.
def dispatch_incoming_packets(raise_disconnect_errors: true)
while packet = transport.poll_message
unless MAP.key?(packet.type)
raise Net::SSH::Exception, "unexpected response #{packet.type} (#{packet.inspect})"
end
send(MAP[packet.type], packet)
end
rescue
force_channel_cleanup_on_close if closed?
raise if raise_disconnect_errors || !$!.is_a?(Net::SSH::Disconnect)
end
# Returns the next available channel id to be assigned, and increments
# the counter.
def get_next_channel_id
@channel_id_counter += 1
end
def force_channel_cleanup_on_close
channels.each do |id, channel|
channel_closed(channel)
end
end
def channel_closed(channel)
channel.remote_closed!
channel.close
cleanup_channel(channel)
channel.do_close
end
# Invoked when a global request is received. The registered global
# request callback will be invoked, if one exists, and the necessary
# reply returned.
def global_request(packet)
info { "global request received: #{packet[:request_type]} #{packet[:want_reply]}" }
callback = @on_global_request[packet[:request_type]]
result = callback ? callback.call(packet[:request_data], packet[:want_reply]) : false
if result != :sent && result != true && result != false
raise "expected global request handler for `#{packet[:request_type]}' to return true, false, or :sent, but got #{result.inspect}"
end
if packet[:want_reply] && result != :sent
msg = Buffer.from(:byte, result ? REQUEST_SUCCESS : REQUEST_FAILURE)
send_message(msg)
end
end
# Invokes the next pending request callback with +true+.
def request_success(packet)
info { "global request success" }
callback = pending_requests.shift
callback.call(true, packet) if callback
end
# Invokes the next pending request callback with +false+.
def request_failure(packet)
info { "global request failure" }
callback = pending_requests.shift
callback.call(false, packet) if callback
end
# Called when the server wants to open a channel. If no registered
# channel handler exists for the given channel type, CHANNEL_OPEN_FAILURE
# is returned, otherwise the callback is invoked and everything proceeds
# accordingly.
def channel_open(packet)
info { "channel open #{packet[:channel_type]}" }
local_id = get_next_channel_id
channel = Channel.new(self, packet[:channel_type], local_id, @max_pkt_size, @max_win_size)
channel.do_open_confirmation(packet[:remote_id], packet[:window_size], packet[:packet_size])
callback = channel_open_handlers[packet[:channel_type]]
if callback
begin
callback[self, channel, packet]
rescue ChannelOpenFailed => err
failure = [err.code, err.reason]
else
channels[local_id] = channel
msg = Buffer.from(:byte, CHANNEL_OPEN_CONFIRMATION, :long, channel.remote_id, :long, channel.local_id, :long, channel.local_maximum_window_size, :long, channel.local_maximum_packet_size)
end
else
failure = [3, "unknown channel type #{channel.type}"]
end
if failure
error { failure.inspect }
msg = Buffer.from(:byte, CHANNEL_OPEN_FAILURE, :long, channel.remote_id, :long, failure[0], :string, failure[1], :string, "")
end
send_message(msg)
end
def channel_open_confirmation(packet)
info { "channel_open_confirmation: #{packet[:local_id]} #{packet[:remote_id]} #{packet[:window_size]} #{packet[:packet_size]}" }
channel = channels[packet[:local_id]]
channel.do_open_confirmation(packet[:remote_id], packet[:window_size], packet[:packet_size])
end
def channel_open_failure(packet)
error { "channel_open_failed: #{packet[:local_id]} #{packet[:reason_code]} #{packet[:description]}" }
channel = channels.delete(packet[:local_id])
channel.do_open_failed(packet[:reason_code], packet[:description])
end
def channel_window_adjust(packet)
info { "channel_window_adjust: #{packet[:local_id]} +#{packet[:extra_bytes]}" }
channels[packet[:local_id]].do_window_adjust(packet[:extra_bytes])
end
def channel_request(packet)
info { "channel_request: #{packet[:local_id]} #{packet[:request]} #{packet[:want_reply]}" }
channels[packet[:local_id]].do_request(packet[:request], packet[:want_reply], packet[:request_data])
end
def channel_data(packet)
info { "channel_data: #{packet[:local_id]} #{packet[:data].length}b" }
channels[packet[:local_id]].do_data(packet[:data])
end
def channel_extended_data(packet)
info { "channel_extended_data: #{packet[:local_id]} #{packet[:data_type]} #{packet[:data].length}b" }
channels[packet[:local_id]].do_extended_data(packet[:data_type], packet[:data])
end
def channel_eof(packet)
info { "channel_eof: #{packet[:local_id]}" }
channels[packet[:local_id]].do_eof
end
def channel_close(packet)
info { "channel_close: #{packet[:local_id]}" }
channel = channels[packet[:local_id]]
channel_closed(channel)
end
def channel_success(packet)
info { "channel_success: #{packet[:local_id]}" }
channels[packet[:local_id]].do_success
end
def channel_failure(packet)
info { "channel_failure: #{packet[:local_id]}" }
channels[packet[:local_id]].do_failure
end
def io_select_wait(wait)
[wait, max_select_wait_time].compact.min
end
MAP = Constants.constants.inject({}) do |memo, name|
value = const_get(name)
next unless Integer === value
memo[value] = name.downcase.to_sym
memo
end
end
end; end; end
net-ssh-4.2.0/lib/net/ssh/connection/term.rb 0000664 0000000 0000000 00000007177 13153765720 0020707 0 ustar 00root root 0000000 0000000 module Net; module SSH; module Connection
# These constants are used when requesting a pseudo-terminal (via
# Net::SSH::Connection::Channel#request_pty). The descriptions for each are
# taken directly from RFC 4254 ("The Secure Shell (SSH) Connection Protocol"),
# http://tools.ietf.org/html/rfc4254.
module Term
# Interrupt character; 255 if none. Similarly for the other characters.
# Not all of these characters are supported on all systems.
VINTR = 1
# The quit character (sends SIGQUIT signal on POSIX systems).
VQUIT = 2
# Erase the character to left of the cursor.
VERASE = 3
# Kill the current input line.
VKILL = 4
# End-of-file character (sends EOF from the terminal).
VEOF = 5
# End-of-line character in addition to carriage return and/or linefeed.
VEOL = 6
# Additional end-of-line character.
VEOL2 = 7
# Continues paused output (normally control-Q).
VSTART = 8
# Pauses output (normally control-S).
VSTOP = 9
# Suspends the current program.
VSUSP = 10
# Another suspend character.
VDSUSP = 11
# Reprints the current input line.
VREPRINT = 12
# Erases a word left of cursor.
VWERASE = 13
# Enter the next character typed literally, even if it is a special
# character.
VLNEXT = 14
# Character to flush output.
VFLUSH = 15
# Switch to a different shell layer.
VSWITCH = 16
# Prints system status line (load, command, pid, etc).
VSTATUS = 17
# Toggles the flushing of terminal output.
VDISCARD = 18
# The ignore parity flag. The parameter SHOULD be 0 if this flag is FALSE,
# and 1 if it is TRUE.
IGNPAR = 30
# Mark parity and framing errors.
PARMRK = 31
# Enable checking of parity errors.
INPCK = 32
# Strip 8th bit off characters.
ISTRIP = 33
# Map NL into CR on input.
INCLR = 34
# Ignore CR on input.
IGNCR = 35
# Map CR to NL on input.
ICRNL = 36
# Translate uppercase characters to lowercase.
IUCLC = 37
# Enable output flow control.
IXON = 38
# Any char will restart after stop.
IXANY = 39
# Enable input flow control.
IXOFF = 40
# Ring bell on input queue full.
IMAXBEL = 41
# Enable signals INTR, QUIT, [D]SUSP.
ISIG = 50
# Canonicalize input lines.
ICANON = 51
# Enable input and output of uppercase characters by preceding their
# lowercase equivalents with "\".
XCASE = 52
# Enable echoing.
ECHO = 53
# Visually erase chars.
ECHOE = 54
# Kill character discards current line.
ECHOK = 55
# Echo NL even if ECHO is off.
ECHONL = 56
# Don't flush after interrupt.
NOFLSH = 57
# Stop background jobs from output.
TOSTOP= 58
# Enable extensions.
IEXTEN = 59
# Echo control characters as ^(Char).
ECHOCTL = 60
# Visual erase for line kill.
ECHOKE = 61
# Retype pending input.
PENDIN = 62
# Enable output processing.
OPOST = 70
# Convert lowercase to uppercase.
OLCUC = 71
# Map NL to CR-NL.
ONLCR = 72
# Translate carriage return to newline (output).
OCRNL = 73
# Translate newline to carriage return-newline (output).
ONOCR = 74
# Newline performs a carriage return (output).
ONLRET = 75
# 7 bit mode.
CS7 = 90
# 8 bit mode.
CS8 = 91
# Parity enable.
PARENB = 92
# Odd parity, else even.
PARODD = 93
# Specifies the input baud rate in bits per second.
TTY_OP_ISPEED = 128
# Specifies the output baud rate in bits per second.
TTY_OP_OSPEED = 129
end
end; end; end
net-ssh-4.2.0/lib/net/ssh/errors.rb 0000664 0000000 0000000 00000007635 13153765720 0017114 0 ustar 00root root 0000000 0000000 module Net; module SSH
# A general exception class, to act as the ancestor of all other Net::SSH
# exception classes.
class Exception < ::RuntimeError; end
# This exception is raised when authentication fails (whether it be
# public key authentication, password authentication, or whatever).
class AuthenticationFailed < Net::SSH::Exception; end
# This exception is raised when a connection attempt times out.
class ConnectionTimeout < Net::SSH::Exception; end
# This exception is raised when the remote host has disconnected
# unexpectedly.
class Disconnect < Net::SSH::Exception; end
# This exception is raised when the remote host has disconnected/
# timeouted unexpectedly.
class Timeout < Disconnect; end
# This exception is primarily used internally, but if you have a channel
# request handler (see Net::SSH::Connection::Channel#on_request) that you
# want to fail in such a way that the server knows it failed, you can
# raise this exception in the handler and Net::SSH will translate that into
# a "channel failure" message.
class ChannelRequestFailed < Net::SSH::Exception; end
# This is exception is primarily used internally, but if you have a channel
# open handler (see Net::SSH::Connection::Session#on_open_channel) and you
# want to fail in such a way that the server knows it failed, you can
# raise this exception in the handler and Net::SSH will translate that into
# a "channel open failed" message.
class ChannelOpenFailed < Net::SSH::Exception
attr_reader :code, :reason
def initialize(code, reason)
@code, @reason = code, reason
super "#{reason} (#{code})"
end
end
# Base class for host key exceptions. When rescuing this exception, you can
# inspect the key fingerprint and, if you want to proceed anyway, simply call
# the remember_host! method on the exception, and then retry.
class HostKeyError < Net::SSH::Exception
# the callback to use when #remember_host! is called
attr_writer :callback #:nodoc:
# situation-specific data describing the host (see #host, #port, etc.)
attr_writer :data #:nodoc:
# An accessor for getting at the data that was used to look up the host
# (see also #fingerprint, #host, #port, #ip, and #key).
def [](key)
@data && @data[key]
end
# Returns the fingerprint of the key for the host, which either was not
# found or did not match.
def fingerprint
@data && @data[:fingerprint]
end
# Returns the host name for the remote host, as reported by the socket.
def host
@data && @data[:peer] && @data[:peer][:host]
end
# Returns the port number for the remote host, as reported by the socket.
def port
@data && @data[:peer] && @data[:peer][:port]
end
# Returns the IP address of the remote host, as reported by the socket.
def ip
@data && @data[:peer] && @data[:peer][:ip]
end
# Returns the key itself, as reported by the remote host.
def key
@data && @data[:key]
end
# Tell Net::SSH to record this host and key in the known hosts file, so
# that subsequent connections will remember them.
def remember_host!
@callback.call
end
end
# Raised when the cached key for a particular host does not match the
# key given by the host, which can be indicative of a man-in-the-middle
# attack. When rescuing this exception, you can inspect the key fingerprint
# and, if you want to proceed anyway, simply call the remember_host!
# method on the exception, and then retry.
class HostKeyMismatch < HostKeyError; end
# Raised when there is no cached key for a particular host, which probably
# means that the host has simply not been seen before.
# When rescuing this exception, you can inspect the key fingerprint and, if
# you want to proceed anyway, simply call the remember_host! method on the
# exception, and then retry.
class HostKeyUnknown < HostKeyError; end
end; end
net-ssh-4.2.0/lib/net/ssh/key_factory.rb 0000664 0000000 0000000 00000012737 13153765720 0020116 0 ustar 00root root 0000000 0000000 require 'net/ssh/transport/openssl'
require 'net/ssh/prompt'
require 'net/ssh/authentication/ed25519_loader'
module Net; module SSH
# A factory class for returning new Key classes. It is used for obtaining
# OpenSSL key instances via their SSH names, and for loading both public and
# private keys. It used used primarily by Net::SSH itself, internally, and
# will rarely (if ever) be directly used by consumers of the library.
#
# klass = Net::SSH::KeyFactory.get("rsa")
# assert klass.is_a?(OpenSSL::PKey::RSA)
#
# key = Net::SSH::KeyFactory.load_public_key("~/.ssh/id_dsa.pub")
class KeyFactory
# Specifies the mapping of SSH names to OpenSSL key classes.
MAP = {
"dh" => OpenSSL::PKey::DH,
"rsa" => OpenSSL::PKey::RSA,
"dsa" => OpenSSL::PKey::DSA,
}
if defined?(OpenSSL::PKey::EC)
MAP["ecdsa"] = OpenSSL::PKey::EC
MAP["ed25519"] = Net::SSH::Authentication::ED25519::PrivKey if defined? Net::SSH::Authentication::ED25519
end
class <(key_data, passphrase) { Net::SSH::Authentication::ED25519::PrivKey.read(key_data, passphrase) }, [ArgumentError]
elsif OpenSSL::PKey.respond_to?(:read)
return ->(key_data, passphrase) { OpenSSL::PKey.read(key_data, passphrase) }, [ArgumentError, OpenSSL::PKey::PKeyError]
elsif data.match(/-----BEGIN DSA PRIVATE KEY-----/)
return ->(key_data, passphrase) { OpenSSL::PKey::DSA.new(key_data, passphrase) }, [OpenSSL::PKey::DSAError]
elsif data.match(/-----BEGIN RSA PRIVATE KEY-----/)
return ->(key_data, passphrase) { OpenSSL::PKey::RSA.new(key_data, passphrase) }, [OpenSSL::PKey::RSAError]
elsif data.match(/-----BEGIN EC PRIVATE KEY-----/) && defined?(OpenSSL::PKey::EC)
return ->(key_data, passphrase) { OpenSSL::PKey::EC.new(key_data, passphrase) }, [OpenSSL::PKey::ECError]
elsif data.match(/-----BEGIN (.+) PRIVATE KEY-----/)
raise OpenSSL::PKey::PKeyError, "not a supported key type '#{$1}'"
else
raise OpenSSL::PKey::PKeyError, "not a private key (#{filename})"
end
end
end
end
end; end
net-ssh-4.2.0/lib/net/ssh/known_hosts.rb 0000664 0000000 0000000 00000013636 13153765720 0020152 0 ustar 00root root 0000000 0000000 require 'strscan'
require 'openssl'
require 'base64'
require 'net/ssh/buffer'
module Net; module SSH
# Represents the result of a search in known hosts
# see search_for
class HostKeys
include Enumerable
attr_reader :host
def initialize(host_keys, host, known_hosts, options = {})
@host_keys = host_keys
@host = host
@known_hosts = known_hosts
@options = options
end
def add_host_key(key)
@known_hosts.add(@host, key, @options)
@host_keys.push(key)
end
def each(&block)
@host_keys.each(&block)
end
def empty?
@host_keys.empty?
end
end
# Searches an OpenSSH-style known-host file for a given host, and returns all
# matching keys. This is used to implement host-key verification, as well as
# to determine what key a user prefers to use for a given host.
#
# This is used internally by Net::SSH, and will never need to be used directly
# by consumers of the library.
class KnownHosts
if defined?(OpenSSL::PKey::EC)
SUPPORTED_TYPE = %w(ssh-rsa ssh-dss
ecdsa-sha2-nistp256
ecdsa-sha2-nistp384
ecdsa-sha2-nistp521)
else
SUPPORTED_TYPE = %w(ssh-rsa ssh-dss)
end
class <