tpkg 2.3.3 → 2.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +20 -0
  5. data/Portfile +39 -0
  6. data/Portfile.template +39 -0
  7. data/README.md +43 -0
  8. data/Rakefile +468 -18
  9. data/bin/gem2tpkg +2 -2
  10. data/bin/tpkg +18 -13
  11. data/bin/tpkg_uploader +132 -0
  12. data/ca.pem +1 -0
  13. data/control +7 -0
  14. data/depend +3 -0
  15. data/externals-etch/authorized_keys +40 -0
  16. data/externals-etch/group +9 -0
  17. data/externals-etch/iptables +38 -0
  18. data/externals-etch/limits +30 -0
  19. data/externals-etch/nfs +30 -0
  20. data/externals-etch/sudo +30 -0
  21. data/externals-etch/supplemental_groups +8 -0
  22. data/externals-etch/sysctl +30 -0
  23. data/externals-etch/user +41 -0
  24. data/externals/group +39 -0
  25. data/externals/supplemental_groups +48 -0
  26. data/externals/user +39 -0
  27. data/lib/tpkg.rb +260 -991
  28. data/lib/tpkg/os.rb +164 -0
  29. data/lib/tpkg/os/debian.rb +159 -0
  30. data/lib/tpkg/os/freebsd.rb +113 -0
  31. data/lib/tpkg/os/macosx.rb +113 -0
  32. data/lib/tpkg/os/redhat.rb +173 -0
  33. data/lib/tpkg/os/solaris.rb +101 -0
  34. data/lib/tpkg/os/windows.rb +26 -0
  35. data/lib/tpkg/thirdparty/kwalify-0.7.2/lib/kwalify.rb +67 -0
  36. data/lib/tpkg/thirdparty/kwalify-0.7.2/lib/kwalify/errors.rb +127 -0
  37. data/lib/tpkg/thirdparty/kwalify-0.7.2/lib/kwalify/kwalify.schema.yaml +58 -0
  38. data/lib/tpkg/thirdparty/kwalify-0.7.2/lib/kwalify/main.rb +442 -0
  39. data/lib/tpkg/thirdparty/kwalify-0.7.2/lib/kwalify/messages.rb +173 -0
  40. data/lib/tpkg/thirdparty/kwalify-0.7.2/lib/kwalify/meta-validator.rb +275 -0
  41. data/lib/tpkg/thirdparty/kwalify-0.7.2/lib/kwalify/parser/base.rb +127 -0
  42. data/lib/tpkg/thirdparty/kwalify-0.7.2/lib/kwalify/parser/yaml.rb +841 -0
  43. data/lib/tpkg/thirdparty/kwalify-0.7.2/lib/kwalify/rule.rb +559 -0
  44. data/lib/tpkg/thirdparty/kwalify-0.7.2/lib/kwalify/templates/genclass-java.eruby +222 -0
  45. data/lib/tpkg/thirdparty/kwalify-0.7.2/lib/kwalify/templates/genclass-php.eruby +104 -0
  46. data/lib/tpkg/thirdparty/kwalify-0.7.2/lib/kwalify/templates/genclass-ruby.eruby +113 -0
  47. data/lib/tpkg/thirdparty/kwalify-0.7.2/lib/kwalify/types.rb +156 -0
  48. data/lib/tpkg/thirdparty/kwalify-0.7.2/lib/kwalify/util.rb +158 -0
  49. data/lib/tpkg/thirdparty/kwalify-0.7.2/lib/kwalify/util/assert-text-equal.rb +46 -0
  50. data/lib/tpkg/thirdparty/kwalify-0.7.2/lib/kwalify/util/hash-interface.rb +18 -0
  51. data/lib/tpkg/thirdparty/kwalify-0.7.2/lib/kwalify/util/hashlike.rb +51 -0
  52. data/lib/tpkg/thirdparty/kwalify-0.7.2/lib/kwalify/util/option-parser.rb +220 -0
  53. data/lib/tpkg/thirdparty/kwalify-0.7.2/lib/kwalify/util/ordered-hash.rb +57 -0
  54. data/lib/tpkg/thirdparty/kwalify-0.7.2/lib/kwalify/util/testcase-helper.rb +112 -0
  55. data/lib/tpkg/thirdparty/kwalify-0.7.2/lib/kwalify/validator.rb +282 -0
  56. data/lib/tpkg/thirdparty/kwalify-0.7.2/lib/kwalify/yaml-parser.rb +870 -0
  57. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh.rb +219 -0
  58. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/authentication/agent.rb +179 -0
  59. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/authentication/constants.rb +18 -0
  60. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/authentication/key_manager.rb +219 -0
  61. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/authentication/methods/abstract.rb +60 -0
  62. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/authentication/methods/hostbased.rb +71 -0
  63. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/authentication/methods/keyboard_interactive.rb +66 -0
  64. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/authentication/methods/password.rb +39 -0
  65. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/authentication/methods/publickey.rb +92 -0
  66. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/authentication/pageant.rb +183 -0
  67. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/authentication/session.rb +134 -0
  68. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/buffer.rb +340 -0
  69. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/buffered_io.rb +198 -0
  70. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/config.rb +205 -0
  71. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/connection/channel.rb +630 -0
  72. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/connection/constants.rb +33 -0
  73. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/connection/session.rb +597 -0
  74. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/connection/term.rb +178 -0
  75. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/errors.rb +85 -0
  76. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/key_factory.rb +102 -0
  77. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/known_hosts.rb +129 -0
  78. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/loggable.rb +61 -0
  79. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/packet.rb +102 -0
  80. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/prompt.rb +93 -0
  81. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/proxy/command.rb +75 -0
  82. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/proxy/errors.rb +14 -0
  83. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/proxy/http.rb +94 -0
  84. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/proxy/socks4.rb +70 -0
  85. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/proxy/socks5.rb +142 -0
  86. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/ruby_compat.rb +43 -0
  87. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/service/forward.rb +288 -0
  88. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/test.rb +89 -0
  89. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/test/channel.rb +129 -0
  90. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/test/extensions.rb +152 -0
  91. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/test/kex.rb +44 -0
  92. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/test/local_packet.rb +51 -0
  93. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/test/packet.rb +81 -0
  94. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/test/remote_packet.rb +38 -0
  95. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/test/script.rb +157 -0
  96. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/test/socket.rb +64 -0
  97. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/transport/algorithms.rb +384 -0
  98. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/transport/cipher_factory.rb +97 -0
  99. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/transport/constants.rb +30 -0
  100. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/transport/hmac.rb +31 -0
  101. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/transport/hmac/abstract.rb +79 -0
  102. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/transport/hmac/md5.rb +12 -0
  103. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/transport/hmac/md5_96.rb +11 -0
  104. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/transport/hmac/none.rb +15 -0
  105. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/transport/hmac/sha1.rb +13 -0
  106. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/transport/hmac/sha1_96.rb +11 -0
  107. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/transport/identity_cipher.rb +55 -0
  108. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/transport/kex.rb +13 -0
  109. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +208 -0
  110. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +77 -0
  111. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/transport/openssl.rb +127 -0
  112. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/transport/packet_stream.rb +235 -0
  113. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/transport/server_version.rb +71 -0
  114. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/transport/session.rb +276 -0
  115. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/transport/state.rb +206 -0
  116. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/verifiers/lenient.rb +30 -0
  117. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/verifiers/null.rb +12 -0
  118. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/verifiers/strict.rb +53 -0
  119. data/lib/tpkg/thirdparty/net-ssh-2.1.0/lib/net/ssh/version.rb +62 -0
  120. data/lib/tpkg/version.rb +3 -0
  121. data/man/man1/cpan2tpkg.1 +82 -0
  122. data/man/man1/gem2tpkg.1 +120 -0
  123. data/man/man1/tpkg.1 +411 -0
  124. data/pkginfo +8 -0
  125. data/postinstall.solaris +11 -0
  126. data/postremove.solaris +16 -0
  127. data/schema/schema-1.0.5.yml +0 -0
  128. data/schema/schema-1.0.6.yml +0 -0
  129. data/schema/schema-1.0.7.yml +0 -0
  130. data/schema/schema-1.0.8.yml +0 -0
  131. data/schema/schema-1.0.9.yml +0 -0
  132. data/schema/schema.yml +0 -0
  133. data/schema/tpkg-1.0.0.dtd +0 -0
  134. data/schema/tpkg-1.0.1.dtd +0 -0
  135. data/schema/tpkg-1.0.2.dtd +0 -0
  136. data/schema/tpkg-1.0.3.dtd +0 -0
  137. data/schema/tpkg-1.0.4.dtd +0 -0
  138. data/schema/tpkg-1.0.5.dtd +0 -0
  139. data/schema/tpkg-1.0.6.dtd +0 -0
  140. data/schema/tpkg-1.0.7.dtd +0 -0
  141. data/schema/tpkg-1.0.8.dtd +0 -0
  142. data/schema/tpkg-1.0.9.dtd +0 -0
  143. data/schema/tpkg.dtd +0 -0
  144. data/test/TODO +30 -0
  145. data/test/premadetestpkg/pkg_without_file_metadata-1.0-1.tpkg +0 -0
  146. data/test/test_checksum.rb +53 -0
  147. data/test/test_compress.rb +55 -0
  148. data/test/test_conflict.rb +41 -0
  149. data/test/test_crontabs.rb +398 -0
  150. data/test/test_dependency.rb +1113 -0
  151. data/test/test_downgrade.rb +80 -0
  152. data/test/test_download.rb +95 -0
  153. data/test/test_encrypt.rb +136 -0
  154. data/test/test_filemetadata.rb +131 -0
  155. data/test/test_initscript.rb +93 -0
  156. data/test/test_install.rb +186 -0
  157. data/test/test_lock.rb +82 -0
  158. data/test/test_make.rb +410 -0
  159. data/test/test_metadata.rb +805 -0
  160. data/test/test_misc.rb +379 -0
  161. data/test/test_options.rb +1711 -0
  162. data/test/test_os.rb +193 -0
  163. data/test/test_os_debian.rb +99 -0
  164. data/test/test_os_freebsd.rb +89 -0
  165. data/test/test_os_macosx.rb +79 -0
  166. data/test/test_os_redhat.rb +124 -0
  167. data/test/test_os_solaris.rb +85 -0
  168. data/test/test_os_windows.rb +26 -0
  169. data/test/test_query.rb +134 -0
  170. data/test/test_remove.rb +539 -0
  171. data/test/test_tar.rb +99 -0
  172. data/test/test_unpack.rb +977 -0
  173. data/test/test_upgrade.rb +398 -0
  174. data/test/test_version.rb +54 -0
  175. data/test/testcmds/crontab +14 -0
  176. data/test/testcmds/debian/apt-cache +145 -0
  177. data/test/testcmds/debian/dpkg-query +16 -0
  178. data/test/testcmds/freebsd/pkg_info +13 -0
  179. data/test/testcmds/macosx/port +35 -0
  180. data/test/testcmds/redhat/rpmbuild +6 -0
  181. data/test/testcmds/redhat/yum +90 -0
  182. data/test/testcmds/solaris/pkginfo +25 -0
  183. data/test/testcmds/solaris/pkgutil +36 -0
  184. data/test/testpkg/reloc/encfile +2 -0
  185. data/test/testpkg/reloc/file +2 -0
  186. data/test/testpkg/reloc/precryptfile +1 -0
  187. data/test/testpkg/reloc/precryptfile.plaintext +3 -0
  188. data/test/testpkg/tpkg-bad-ownergroup.xml +25 -0
  189. data/test/testpkg/tpkg-bad-ownergroup.yml +18 -0
  190. data/test/testpkg/tpkg-default-perms.xml +28 -0
  191. data/test/testpkg/tpkg-default-perms.yml +20 -0
  192. data/test/testpkg/tpkg-good-ownergroup.xml +25 -0
  193. data/test/testpkg/tpkg-good-ownergroup.yml +18 -0
  194. data/test/testpkg/tpkg-nativedeps.yml +13 -0
  195. data/test/testpkg/tpkg-nofiles.xml +14 -0
  196. data/test/testpkg/tpkg-nofiles.yml +9 -0
  197. data/test/testpkg/tpkg.xml +35 -0
  198. data/test/testpkg/tpkg.yml +25 -0
  199. data/test/tpkgtest.rb +300 -0
  200. data/tpkg.conf +16 -0
  201. data/tpkg.gemspec +24 -0
  202. data/tpkg.spec +28 -0
  203. data/tpkg.xml +17 -0
  204. data/tpkg_profile.sh +32 -0
  205. metadata +306 -31
@@ -0,0 +1,219 @@
1
+ # Make sure HOME is set, regardless of OS, so that File.expand_path works
2
+ # as expected with tilde characters.
3
+ ENV['HOME'] ||= ENV['HOMEPATH'] ? "#{ENV['HOMEDRIVE']}#{ENV['HOMEPATH']}" : "."
4
+
5
+ require 'logger'
6
+
7
+ require 'net/ssh/config'
8
+ require 'net/ssh/errors'
9
+ require 'net/ssh/loggable'
10
+ require 'net/ssh/transport/session'
11
+ require 'net/ssh/authentication/session'
12
+ require 'net/ssh/connection/session'
13
+
14
+ module Net
15
+
16
+ # Net::SSH is a library for interacting, programmatically, with remote
17
+ # processes via the SSH2 protocol. Sessions are always initiated via
18
+ # Net::SSH.start. From there, a program interacts with the new SSH session
19
+ # via the convenience methods on Net::SSH::Connection::Session, by opening
20
+ # and interacting with new channels (Net::SSH::Connection:Session#open_channel
21
+ # and Net::SSH::Connection::Channel), or by forwarding local and/or
22
+ # remote ports through the connection (Net::SSH::Service::Forward).
23
+ #
24
+ # The SSH protocol is very event-oriented. Requests are sent from the client
25
+ # to the server, and are answered asynchronously. This gives great flexibility
26
+ # (since clients can have multiple requests pending at a time), but it also
27
+ # adds complexity. Net::SSH tries to manage this complexity by providing
28
+ # some simpler methods of synchronous communication (see Net::SSH::Connection::Session#exec!).
29
+ #
30
+ # In general, though, and if you want to do anything more complicated than
31
+ # simply executing commands and capturing their output, you'll need to use
32
+ # channels (Net::SSH::Connection::Channel) to build state machines that are
33
+ # executed while the event loop runs (Net::SSH::Connection::Session#loop).
34
+ #
35
+ # Net::SSH::Connection::Session and Net::SSH::Connection::Channel have more
36
+ # information about this technique.
37
+ #
38
+ # = "Um, all I want to do is X, just show me how!"
39
+ #
40
+ # == X == "execute a command and capture the output"
41
+ #
42
+ # Net::SSH.start("host", "user", :password => "password") do |ssh|
43
+ # result = ssh.exec!("ls -l")
44
+ # puts result
45
+ # end
46
+ #
47
+ # == X == "forward connections on a local port to a remote host"
48
+ #
49
+ # Net::SSH.start("host", "user", :password => "password") do |ssh|
50
+ # ssh.forward.local(1234, "www.google.com", 80)
51
+ # ssh.loop { true }
52
+ # end
53
+ #
54
+ # == X == "forward connections on a remote port to the local host"
55
+ #
56
+ # Net::SSH.start("host", "user", :password => "password") do |ssh|
57
+ # ssh.forward.remote(80, "www.google.com", 1234)
58
+ # ssh.loop { true }
59
+ # end
60
+ module SSH
61
+ # This is the set of options that Net::SSH.start recognizes. See
62
+ # Net::SSH.start for a description of each option.
63
+ VALID_OPTIONS = [
64
+ :auth_methods, :compression, :compression_level, :config, :encryption,
65
+ :forward_agent, :hmac, :host_key, :kex, :keys, :key_data, :languages,
66
+ :logger, :paranoid, :password, :port, :proxy, :rekey_blocks_limit,
67
+ :rekey_limit, :rekey_packet_limit, :timeout, :verbose,
68
+ :global_known_hosts_file, :user_known_hosts_file, :host_key_alias,
69
+ :host_name, :user, :properties, :passphrase, :keys_only
70
+ ]
71
+
72
+ # The standard means of starting a new SSH connection. When used with a
73
+ # block, the connection will be closed when the block terminates, otherwise
74
+ # the connection will just be returned. The yielded (or returned) value
75
+ # will be an instance of Net::SSH::Connection::Session (q.v.). (See also
76
+ # Net::SSH::Connection::Channel and Net::SSH::Service::Forward.)
77
+ #
78
+ # Net::SSH.start("host", "user") do |ssh|
79
+ # ssh.exec! "cp /some/file /another/location"
80
+ # hostname = ssh.exec!("hostname")
81
+ #
82
+ # ssh.open_channel do |ch|
83
+ # ch.exec "sudo -p 'sudo password: ' ls" do |ch, success|
84
+ # abort "could not execute sudo ls" unless success
85
+ #
86
+ # ch.on_data do |ch, data|
87
+ # print data
88
+ # if data =~ /sudo password: /
89
+ # ch.send_data("password\n")
90
+ # end
91
+ # end
92
+ # end
93
+ # end
94
+ #
95
+ # ssh.loop
96
+ # end
97
+ #
98
+ # This method accepts the following options (all are optional):
99
+ #
100
+ # * :auth_methods => an array of authentication methods to try
101
+ # * :compression => the compression algorithm to use, or +true+ to use
102
+ # whatever is supported.
103
+ # * :compression_level => the compression level to use when sending data
104
+ # * :config => set to +true+ to load the default OpenSSH config files
105
+ # (~/.ssh/config, /etc/ssh_config), or to +false+ to not load them, or to
106
+ # a file-name (or array of file-names) to load those specific configuration
107
+ # files. Defaults to +true+.
108
+ # * :encryption => the encryption cipher (or ciphers) to use
109
+ # * :forward_agent => set to true if you want the SSH agent connection to
110
+ # be forwarded
111
+ # * :global_known_hosts_file => the location of the global known hosts
112
+ # file. Set to an array if you want to specify multiple global known
113
+ # hosts files. Defaults to %w(/etc/ssh/known_hosts /etc/ssh/known_hosts2).
114
+ # * :hmac => the hmac algorithm (or algorithms) to use
115
+ # * :host_key => the host key algorithm (or algorithms) to use
116
+ # * :host_key_alias => the host name to use when looking up or adding a
117
+ # host to a known_hosts dictionary file
118
+ # * :host_name => the real host name or IP to log into. This is used
119
+ # instead of the +host+ parameter, and is primarily only useful when
120
+ # specified in an SSH configuration file. It lets you specify an
121
+ # "alias", similarly to adding an entry in /etc/hosts but without needing
122
+ # to modify /etc/hosts.
123
+ # * :kex => the key exchange algorithm (or algorithms) to use
124
+ # * :keys => an array of file names of private keys to use for publickey
125
+ # and hostbased authentication
126
+ # * :key_data => an array of strings, with each element of the array being
127
+ # a raw private key in PEM format.
128
+ # * :keys_only => set to +true+ to use only private keys from +keys+ and
129
+ # +key_data+ parameters, even if ssh-agent offers more identities. This
130
+ # option is intended for situations where ssh-agent offers many different
131
+ # identites.
132
+ # * :logger => the logger instance to use when logging
133
+ # * :paranoid => either true, false, or :very, specifying how strict
134
+ # host-key verification should be
135
+ # * :passphrase => the passphrase to use when loading a private key (default
136
+ # is +nil+, for no passphrase)
137
+ # * :password => the password to use to login
138
+ # * :port => the port to use when connecting to the remote host
139
+ # * :properties => a hash of key/value pairs to add to the new connection's
140
+ # properties (see Net::SSH::Connection::Session#properties)
141
+ # * :proxy => a proxy instance (see Proxy) to use when connecting
142
+ # * :rekey_blocks_limit => the max number of blocks to process before rekeying
143
+ # * :rekey_limit => the max number of bytes to process before rekeying
144
+ # * :rekey_packet_limit => the max number of packets to process before rekeying
145
+ # * :timeout => how long to wait for the initial connection to be made
146
+ # * :user => the user name to log in as; this overrides the +user+
147
+ # parameter, and is primarily only useful when provided via an SSH
148
+ # configuration file.
149
+ # * :user_known_hosts_file => the location of the user known hosts file.
150
+ # Set to an array to specify multiple user known hosts files.
151
+ # Defaults to %w(~/.ssh/known_hosts ~/.ssh/known_hosts2).
152
+ # * :verbose => how verbose to be (Logger verbosity constants, Logger::DEBUG
153
+ # is very verbose, Logger::FATAL is all but silent). Logger::FATAL is the
154
+ # default. The symbols :debug, :info, :warn, :error, and :fatal are also
155
+ # supported and are translated to the corresponding Logger constant.
156
+ def self.start(host, user, options={}, &block)
157
+ invalid_options = options.keys - VALID_OPTIONS
158
+ if invalid_options.any?
159
+ raise ArgumentError, "invalid option(s): #{invalid_options.join(', ')}"
160
+ end
161
+
162
+ options[:user] = user if user
163
+ options = configuration_for(host, options.fetch(:config, true)).merge(options)
164
+ host = options.fetch(:host_name, host)
165
+
166
+ if !options.key?(:logger)
167
+ options[:logger] = Logger.new(STDERR)
168
+ options[:logger].level = Logger::FATAL
169
+ end
170
+
171
+ if options[:verbose]
172
+ options[:logger].level = case options[:verbose]
173
+ when Fixnum then options[:verbose]
174
+ when :debug then Logger::DEBUG
175
+ when :info then Logger::INFO
176
+ when :warn then Logger::WARN
177
+ when :error then Logger::ERROR
178
+ when :fatal then Logger::FATAL
179
+ else raise ArgumentError, "can't convert #{options[:verbose].inspect} to any of the Logger level constants"
180
+ end
181
+ end
182
+
183
+ transport = Transport::Session.new(host, options)
184
+ auth = Authentication::Session.new(transport, options)
185
+
186
+ user = options.fetch(:user, user)
187
+ if auth.authenticate("ssh-connection", user, options[:password])
188
+ connection = Connection::Session.new(transport, options)
189
+ if block_given?
190
+ yield connection
191
+ connection.close
192
+ else
193
+ return connection
194
+ end
195
+ else
196
+ raise AuthenticationFailed, user
197
+ end
198
+ end
199
+
200
+ # Returns a hash of the configuration options for the given host, as read
201
+ # from the SSH configuration file(s). If +use_ssh_config+ is true (the
202
+ # default), this will load configuration from both ~/.ssh/config and
203
+ # /etc/ssh_config. If +use_ssh_config+ is nil or false, nothing will be
204
+ # loaded (and an empty hash returned). Otherwise, +use_ssh_config+ may
205
+ # be a file name (or array of file names) of SSH configuration file(s)
206
+ # to read.
207
+ #
208
+ # See Net::SSH::Config for the full description of all supported options.
209
+ def self.configuration_for(host, use_ssh_config=true)
210
+ files = case use_ssh_config
211
+ when true then Net::SSH::Config.default_files
212
+ when false, nil then return {}
213
+ else Array(use_ssh_config)
214
+ end
215
+
216
+ Net::SSH::Config.for(host, files)
217
+ end
218
+ end
219
+ end
@@ -0,0 +1,179 @@
1
+ require 'net/ssh/buffer'
2
+ require 'net/ssh/errors'
3
+ require 'net/ssh/loggable'
4
+ require 'net/ssh/transport/server_version'
5
+
6
+ # Only load pageant on Windows, Ruby 1.8.x
7
+ if File::ALT_SEPARATOR && !(RUBY_PLATFORM =~ /java/) && RUBY_VERSION < "1.9"
8
+ require 'net/ssh/authentication/pageant'
9
+ end
10
+
11
+ module Net; module SSH; module Authentication
12
+
13
+ # A trivial exception class for representing agent-specific errors.
14
+ class AgentError < Net::SSH::Exception; end
15
+
16
+ # An exception for indicating that the SSH agent is not available.
17
+ class AgentNotAvailable < AgentError; end
18
+
19
+ # This class implements a simple client for the ssh-agent protocol. It
20
+ # does not implement any specific protocol, but instead copies the
21
+ # behavior of the ssh-agent functions in the OpenSSH library (3.8).
22
+ #
23
+ # This means that although it behaves like a SSH1 client, it also has
24
+ # some SSH2 functionality (like signing data).
25
+ class Agent
26
+ include Loggable
27
+
28
+ # A simple module for extending keys, to allow comments to be specified
29
+ # for them.
30
+ module Comment
31
+ attr_accessor :comment
32
+ end
33
+
34
+ SSH2_AGENT_REQUEST_VERSION = 1
35
+ SSH2_AGENT_REQUEST_IDENTITIES = 11
36
+ SSH2_AGENT_IDENTITIES_ANSWER = 12
37
+ SSH2_AGENT_SIGN_REQUEST = 13
38
+ SSH2_AGENT_SIGN_RESPONSE = 14
39
+ SSH2_AGENT_FAILURE = 30
40
+ SSH2_AGENT_VERSION_RESPONSE = 103
41
+
42
+ SSH_COM_AGENT2_FAILURE = 102
43
+
44
+ SSH_AGENT_REQUEST_RSA_IDENTITIES = 1
45
+ SSH_AGENT_RSA_IDENTITIES_ANSWER1 = 2
46
+ SSH_AGENT_RSA_IDENTITIES_ANSWER2 = 5
47
+ SSH_AGENT_FAILURE = 5
48
+
49
+ # The underlying socket being used to communicate with the SSH agent.
50
+ attr_reader :socket
51
+
52
+ # Instantiates a new agent object, connects to a running SSH agent,
53
+ # negotiates the agent protocol version, and returns the agent object.
54
+ def self.connect(logger=nil)
55
+ agent = new(logger)
56
+ agent.connect!
57
+ agent.negotiate!
58
+ agent
59
+ end
60
+
61
+ # Creates a new Agent object, using the optional logger instance to
62
+ # report status.
63
+ def initialize(logger=nil)
64
+ self.logger = logger
65
+ end
66
+
67
+ # Connect to the agent process using the socket factory and socket name
68
+ # given by the attribute writers. If the agent on the other end of the
69
+ # socket reports that it is an SSH2-compatible agent, this will fail
70
+ # (it only supports the ssh-agent distributed by OpenSSH).
71
+ def connect!
72
+ begin
73
+ debug { "connecting to ssh-agent" }
74
+ @socket = agent_socket_factory.open(ENV['SSH_AUTH_SOCK'])
75
+ rescue
76
+ error { "could not connect to ssh-agent" }
77
+ raise AgentNotAvailable, $!.message
78
+ end
79
+ end
80
+
81
+ # Attempts to negotiate the SSH agent protocol version. Raises an error
82
+ # if the version could not be negotiated successfully.
83
+ def negotiate!
84
+ # determine what type of agent we're communicating with
85
+ type, body = send_and_wait(SSH2_AGENT_REQUEST_VERSION, :string, Transport::ServerVersion::PROTO_VERSION)
86
+
87
+ if type == SSH2_AGENT_VERSION_RESPONSE
88
+ raise NotImplementedError, "SSH2 agents are not yet supported"
89
+ elsif type != SSH_AGENT_RSA_IDENTITIES_ANSWER1 && type != SSH_AGENT_RSA_IDENTITIES_ANSWER2
90
+ raise AgentError, "unknown response from agent: #{type}, #{body.to_s.inspect}"
91
+ end
92
+ end
93
+
94
+ # Return an array of all identities (public keys) known to the agent.
95
+ # Each key returned is augmented with a +comment+ property which is set
96
+ # to the comment returned by the agent for that key.
97
+ def identities
98
+ type, body = send_and_wait(SSH2_AGENT_REQUEST_IDENTITIES)
99
+ raise AgentError, "could not get identity count" if agent_failed(type)
100
+ raise AgentError, "bad authentication reply: #{type}" if type != SSH2_AGENT_IDENTITIES_ANSWER
101
+
102
+ identities = []
103
+ body.read_long.times do
104
+ key = Buffer.new(body.read_string).read_key
105
+ key.extend(Comment)
106
+ key.comment = body.read_string
107
+ identities.push key
108
+ end
109
+
110
+ return identities
111
+ end
112
+
113
+ # Closes this socket. This agent reference is no longer able to
114
+ # query the agent.
115
+ def close
116
+ @socket.close
117
+ end
118
+
119
+ # Using the agent and the given public key, sign the given data. The
120
+ # signature is returned in SSH2 format.
121
+ def sign(key, data)
122
+ type, reply = send_and_wait(SSH2_AGENT_SIGN_REQUEST, :string, Buffer.from(:key, key), :string, data, :long, 0)
123
+
124
+ if agent_failed(type)
125
+ raise AgentError, "agent could not sign data with requested identity"
126
+ elsif type != SSH2_AGENT_SIGN_RESPONSE
127
+ raise AgentError, "bad authentication response #{type}"
128
+ end
129
+
130
+ return reply.read_string
131
+ end
132
+
133
+ private
134
+
135
+ # Returns the agent socket factory to use.
136
+ def agent_socket_factory
137
+ if File::ALT_SEPARATOR
138
+ Pageant::Socket
139
+ else
140
+ UNIXSocket
141
+ end
142
+ end
143
+
144
+ # Send a new packet of the given type, with the associated data.
145
+ def send_packet(type, *args)
146
+ buffer = Buffer.from(*args)
147
+ data = [buffer.length + 1, type.to_i, buffer.to_s].pack("NCA*")
148
+ debug { "sending agent request #{type} len #{buffer.length}" }
149
+ @socket.send data, 0
150
+ end
151
+
152
+ # Read the next packet from the agent. This will return a two-part
153
+ # tuple consisting of the packet type, and the packet's body (which
154
+ # is returned as a Net::SSH::Buffer).
155
+ def read_packet
156
+ buffer = Net::SSH::Buffer.new(@socket.read(4))
157
+ buffer.append(@socket.read(buffer.read_long))
158
+ type = buffer.read_byte
159
+ debug { "received agent packet #{type} len #{buffer.length-4}" }
160
+ return type, buffer
161
+ end
162
+
163
+ # Send the given packet and return the subsequent reply from the agent.
164
+ # (See #send_packet and #read_packet).
165
+ def send_and_wait(type, *args)
166
+ send_packet(type, *args)
167
+ read_packet
168
+ end
169
+
170
+ # Returns +true+ if the parameter indicates a "failure" response from
171
+ # the agent, and +false+ otherwise.
172
+ def agent_failed(type)
173
+ type == SSH_AGENT_FAILURE ||
174
+ type == SSH2_AGENT_FAILURE ||
175
+ type == SSH_COM_AGENT2_FAILURE
176
+ end
177
+ end
178
+
179
+ end; end; end
@@ -0,0 +1,18 @@
1
+ module Net; module SSH; module Authentication
2
+
3
+ # Describes the constants used by the Net::SSH::Authentication components
4
+ # of the Net::SSH library. Individual authentication method implemenations
5
+ # may define yet more constants that are specific to their implementation.
6
+ module Constants
7
+ USERAUTH_REQUEST = 50
8
+ USERAUTH_FAILURE = 51
9
+ USERAUTH_SUCCESS = 52
10
+ USERAUTH_BANNER = 53
11
+
12
+ USERAUTH_PASSWD_CHANGEREQ = 60
13
+ USERAUTH_PK_OK = 60
14
+
15
+ USERAUTH_METHOD_RANGE = 60..79
16
+ end
17
+
18
+ end; end; end
@@ -0,0 +1,219 @@
1
+ require 'net/ssh/errors'
2
+ require 'net/ssh/key_factory'
3
+ require 'net/ssh/loggable'
4
+ require 'net/ssh/authentication/agent'
5
+
6
+ module Net
7
+ module SSH
8
+ module Authentication
9
+
10
+ # A trivial exception class used to report errors in the key manager.
11
+ class KeyManagerError < Net::SSH::Exception; end
12
+
13
+ # This class encapsulates all operations done by clients on a user's
14
+ # private keys. In practice, the client should never need a reference
15
+ # to a private key; instead, they grab a list of "identities" (public
16
+ # keys) that are available from the KeyManager, and then use
17
+ # the KeyManager to do various private key operations using those
18
+ # identities.
19
+ #
20
+ # The KeyManager also uses the Agent class to encapsulate the
21
+ # ssh-agent. Thus, from a client's perspective it is completely
22
+ # hidden whether an identity comes from the ssh-agent or from a file
23
+ # on disk.
24
+ class KeyManager
25
+ include Loggable
26
+
27
+ # The list of user key files that will be examined
28
+ attr_reader :key_files
29
+
30
+ # The list of user key data that will be examined
31
+ attr_reader :key_data
32
+
33
+ # The map of loaded identities
34
+ attr_reader :known_identities
35
+
36
+ # The map of options that were passed to the key-manager
37
+ attr_reader :options
38
+
39
+ # Create a new KeyManager. By default, the manager will
40
+ # use the ssh-agent (if it is running).
41
+ def initialize(logger, options={})
42
+ self.logger = logger
43
+ @key_files = []
44
+ @key_data = []
45
+ @use_agent = true
46
+ @known_identities = {}
47
+ @agent = nil
48
+ @options = options
49
+ end
50
+
51
+ # Clear all knowledge of any loaded user keys. This also clears the list
52
+ # of default identity files that are to be loaded, thus making it
53
+ # appropriate to use if a client wishes to NOT use the default identity
54
+ # files.
55
+ def clear!
56
+ key_files.clear
57
+ key_data.clear
58
+ known_identities.clear
59
+ self
60
+ end
61
+
62
+ # Add the given key_file to the list of key files that will be used.
63
+ def add(key_file)
64
+ key_files.push(File.expand_path(key_file)).uniq!
65
+ self
66
+ end
67
+
68
+ # Add the given key_file to the list of keys that will be used.
69
+ def add_key_data(key_data_)
70
+ key_data.push(key_data_).uniq!
71
+ self
72
+ end
73
+
74
+ # This is used as a hint to the KeyManager indicating that the agent
75
+ # connection is no longer needed. Any other open resources may be closed
76
+ # at this time.
77
+ #
78
+ # Calling this does NOT indicate that the KeyManager will no longer
79
+ # be used. Identities may still be requested and operations done on
80
+ # loaded identities, in which case, the agent will be automatically
81
+ # reconnected. This method simply allows the client connection to be
82
+ # closed when it will not be used in the immediate future.
83
+ def finish
84
+ @agent.close if @agent
85
+ @agent = nil
86
+ end
87
+
88
+ # Iterates over all available identities (public keys) known to this
89
+ # manager. As it finds one, it will then yield it to the caller.
90
+ # The origin of the identities may be from files on disk or from an
91
+ # ssh-agent. Note that identities from an ssh-agent are always listed
92
+ # first in the array, with other identities coming after.
93
+ #
94
+ # If key manager was created with :keys_only option, any identity
95
+ # from ssh-agent will be ignored unless it present in key_files or
96
+ # key_data.
97
+ def each_identity
98
+ user_identities = load_identities_from_files + load_identities_from_data
99
+
100
+ if agent
101
+ agent.identities.each do |key|
102
+ corresponding_user_identity = user_identities.detect { |identity|
103
+ identity[:public_key].to_pem == key.to_pem
104
+ }
105
+ user_identities.delete(corresponding_user_identity) if corresponding_user_identity
106
+
107
+ if !options[:keys_only] || corresponding_user_identity
108
+ known_identities[key] = { :from => :agent }
109
+ yield key
110
+ end
111
+ end
112
+ end
113
+
114
+ user_identities.each do |identity|
115
+ key = identity.delete(:public_key)
116
+ known_identities[key] = identity
117
+ yield key
118
+ end
119
+
120
+ self
121
+ end
122
+
123
+ # Sign the given data, using the corresponding private key of the given
124
+ # identity. If the identity was originally obtained from an ssh-agent,
125
+ # then the ssh-agent will be used to sign the data, otherwise the
126
+ # private key for the identity will be loaded from disk (if it hasn't
127
+ # been loaded already) and will then be used to sign the data.
128
+ #
129
+ # Regardless of the identity's origin or who does the signing, this
130
+ # will always return the signature in an SSH2-specified "signature
131
+ # blob" format.
132
+ def sign(identity, data)
133
+ info = known_identities[identity] or raise KeyManagerError, "the given identity is unknown to the key manager"
134
+
135
+ if info[:key].nil? && info[:from] == :file
136
+ begin
137
+ info[:key] = KeyFactory.load_private_key(info[:file], options[:passphrase])
138
+ rescue Exception => e
139
+ raise KeyManagerError, "the given identity is known, but the private key could not be loaded: #{e.class} (#{e.message})"
140
+ end
141
+ end
142
+
143
+ if info[:key]
144
+ return Net::SSH::Buffer.from(:string, identity.ssh_type,
145
+ :string, info[:key].ssh_do_sign(data.to_s)).to_s
146
+ end
147
+
148
+ if info[:from] == :agent
149
+ raise KeyManagerError, "the agent is no longer available" unless agent
150
+ return agent.sign(identity, data.to_s)
151
+ end
152
+
153
+ raise KeyManagerError, "[BUG] can't determine identity origin (#{info.inspect})"
154
+ end
155
+
156
+ # Identifies whether the ssh-agent will be used or not.
157
+ def use_agent?
158
+ @use_agent
159
+ end
160
+
161
+ # Toggles whether the ssh-agent will be used or not. If true, an
162
+ # attempt will be made to use the ssh-agent. If false, any existing
163
+ # connection to an agent is closed and the agent will not be used.
164
+ def use_agent=(use_agent)
165
+ finish if !use_agent
166
+ @use_agent = use_agent
167
+ end
168
+
169
+ # Returns an Agent instance to use for communicating with an SSH
170
+ # agent process. Returns nil if use of an SSH agent has been disabled,
171
+ # or if the agent is otherwise not available.
172
+ def agent
173
+ return unless use_agent?
174
+ @agent ||= Agent.connect(logger)
175
+ rescue AgentNotAvailable
176
+ @use_agent = false
177
+ nil
178
+ end
179
+
180
+ private
181
+
182
+ # Extracts identities from user key_files, preserving their order and sources.
183
+ def load_identities_from_files
184
+ key_files.map do |file|
185
+ public_key_file = file + ".pub"
186
+ if File.readable?(public_key_file)
187
+ begin
188
+ key = KeyFactory.load_public_key(public_key_file)
189
+ { :public_key => key, :from => :file, :file => file }
190
+ rescue Exception => e
191
+ error { "could not load public key file `#{public_key_file}': #{e.class} (#{e.message})" }
192
+ nil
193
+ end
194
+ elsif File.readable?(file)
195
+ begin
196
+ private_key = KeyFactory.load_private_key(file, options[:passphrase])
197
+ key = private_key.send(:public_key)
198
+ { :public_key => key, :from => :file, :file => file, :key => private_key }
199
+ rescue Exception => e
200
+ error { "could not load private key file `#{file}': #{e.class} (#{e.message})" }
201
+ nil
202
+ end
203
+ end
204
+ end.compact
205
+ end
206
+
207
+ # Extraccts identities from user key_data, preserving their order and sources.
208
+ def load_identities_from_data
209
+ key_data.map do |data|
210
+ private_key = KeyFactory.load_data_private_key(data)
211
+ key = private_key.send(:public_key)
212
+ { :public_key => key, :from => :key_data, :data => data, :key => private_key }
213
+ end
214
+ end
215
+
216
+ end
217
+ end
218
+ end
219
+ end