winrm 1.3.0.dev.3 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,11 +1,13 @@
1
+ # encoding: UTF-8
2
+ #
1
3
  # Copyright 2014 Shawn Neal <sneal@sneal.net>
2
- #
4
+ #
3
5
  # Licensed under the Apache License, Version 2.0 (the "License");
4
6
  # you may not use this file except in compliance with the License.
5
7
  # You may obtain a copy of the License at
6
- #
8
+ #
7
9
  # http://www.apache.org/licenses/LICENSE-2.0
8
- #
10
+ #
9
11
  # Unless required by applicable law or agreed to in writing, software
10
12
  # distributed under the License is distributed on an "AS IS" BASIS,
11
13
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -18,7 +20,6 @@ module WinRM
18
20
  # Handles the raw WinRM HTTP response. Returns the body as an XML doc
19
21
  # or raises the appropriate WinRM error if the response is an error.
20
22
  class ResponseHandler
21
-
22
23
  # @param [String] The raw unparsed response body, if any
23
24
  # @param [Integer] The HTTP response status code
24
25
  def initialize(response_body, status_code)
@@ -30,53 +31,52 @@ module WinRM
30
31
  # doc or raises an appropriate error.
31
32
  #
32
33
  # @returns [REXML::Document] The parsed response body
33
- def parse_to_xml()
34
- raise_if_error()
34
+ def parse_to_xml
35
+ raise_if_error
35
36
  response_xml
36
37
  end
37
38
 
38
39
  private
39
40
 
40
- def response_xml()
41
+ def response_xml
41
42
  @response_xml ||= REXML::Document.new(@response_body)
42
43
  rescue REXML::ParseException => e
43
- raise WinRMHTTPTransportError.new("Unable to parse WinRM response: #{e.message}", @status_code)
44
+ raise WinRMHTTPTransportError.new(
45
+ "Unable to parse WinRM response: #{e.message}", @status_code)
44
46
  end
45
47
 
46
- def raise_if_error()
47
- return if @status_code == 200
48
- raise_if_auth_error()
49
- raise_if_wsman_fault()
50
- raise_if_wmi_error()
51
- raise_transport_error()
48
+ def raise_if_error
49
+ return if @status_code == 200
50
+ raise_if_auth_error
51
+ raise_if_wsman_fault
52
+ raise_if_wmi_error
53
+ raise_transport_error
52
54
  end
53
55
 
54
- def raise_if_auth_error()
55
- raise WinRMAuthorizationError.new if @status_code == 401
56
+ def raise_if_auth_error
57
+ fail WinRMAuthorizationError if @status_code == 401
56
58
  end
57
59
 
58
- def raise_if_wsman_fault()
60
+ def raise_if_wsman_fault
59
61
  soap_errors = REXML::XPath.match(response_xml, "//#{NS_SOAP_ENV}:Body/#{NS_SOAP_ENV}:Fault/*")
60
- if !soap_errors.empty?
61
- fault = REXML::XPath.first(soap_errors, "//#{NS_WSMAN_FAULT}:WSManFault")
62
- raise WinRMWSManFault.new(fault.to_s, fault.attributes['Code']) unless fault.nil?
63
- end
62
+ return if soap_errors.empty?
63
+ fault = REXML::XPath.first(soap_errors, "//#{NS_WSMAN_FAULT}:WSManFault")
64
+ fail WinRMWSManFault.new(fault.to_s, fault.attributes['Code']) unless fault.nil?
64
65
  end
65
66
 
66
- def raise_if_wmi_error()
67
+ def raise_if_wmi_error
67
68
  soap_errors = REXML::XPath.match(response_xml, "//#{NS_SOAP_ENV}:Body/#{NS_SOAP_ENV}:Fault/*")
68
- if !soap_errors.empty?
69
- error = REXML::XPath.first(soap_errors, "//#{NS_WSMAN_MSFT}:MSFT_WmiError")
70
- if !error.nil?
71
- error_code = REXML::XPath.first(error, "//#{NS_WSMAN_MSFT}:error_Code").text
72
- raise WinRMWMIError.new(error.to_s, error_code)
73
- end
74
- end
75
- end
69
+ return if soap_errors.empty?
76
70
 
77
- def raise_transport_error()
78
- raise WinRMHTTPTransportError.new('Bad HTTP response returned from server', @status_code)
71
+ error = REXML::XPath.first(soap_errors, "//#{NS_WSMAN_MSFT}:MSFT_WmiError")
72
+ return if error.nil?
73
+
74
+ error_code = REXML::XPath.first(error, "//#{NS_WSMAN_MSFT}:error_Code").text
75
+ fail WinRMWMIError.new(error.to_s, error_code)
79
76
  end
80
77
 
78
+ def raise_transport_error
79
+ fail WinRMHTTPTransportError.new('Bad HTTP response returned from server', @status_code)
80
+ end
81
81
  end
82
82
  end
@@ -1,11 +1,13 @@
1
+ # encoding: UTF-8
2
+ #
1
3
  # Copyright 2010 Dan Wanek <dan.wanek@gmail.com>
2
- #
4
+ #
3
5
  # Licensed under the Apache License, Version 2.0 (the "License");
4
6
  # you may not use this file except in compliance with the License.
5
7
  # You may obtain a copy of the License at
6
- #
8
+ #
7
9
  # http://www.apache.org/licenses/LICENSE-2.0
8
- #
10
+ #
9
11
  # Unless required by applicable law or agreed to in writing, software
10
12
  # distributed under the License is distributed on an "AS IS" BASIS,
11
13
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -16,20 +18,18 @@ require_relative 'response_handler'
16
18
 
17
19
  module WinRM
18
20
  module HTTP
19
-
20
21
  # A generic HTTP transport that utilized HTTPClient to send messages back and forth.
21
22
  # This backend will maintain state for every WinRMWebService instance that is instantiated so it
22
23
  # is possible to use GSSAPI with Keep-Alive.
23
24
  class HttpTransport
24
-
25
25
  # Set this to an unreasonable amount because WinRM has its own timeouts
26
- DEFAULT_RECEIVE_TIMEOUT = 3600
26
+ DEFAULT_RECEIVE_TIMEOUT = 3600
27
27
 
28
28
  attr_reader :endpoint
29
29
 
30
30
  def initialize(endpoint)
31
31
  @endpoint = endpoint.is_a?(String) ? URI.parse(endpoint) : endpoint
32
- @httpcli = HTTPClient.new(:agent_name => 'Ruby WinRM Client')
32
+ @httpcli = HTTPClient.new(agent_name: 'Ruby WinRM Client')
33
33
  @httpcli.receive_timeout = DEFAULT_RECEIVE_TIMEOUT
34
34
  @logger = Logging.logger[self]
35
35
  end
@@ -41,23 +41,25 @@ module WinRM
41
41
  # @returns [REXML::Document] The parsed response body
42
42
  def send_request(message)
43
43
  log_soap_message(message)
44
- hdr = {'Content-Type' => 'application/soap+xml;charset=UTF-8', 'Content-Length' => message.length}
44
+ hdr = {
45
+ 'Content-Type' => 'application/soap+xml;charset=UTF-8',
46
+ 'Content-Length' => message.length }
45
47
  resp = @httpcli.post(@endpoint, message, hdr)
46
48
  log_soap_message(resp.http_body.content)
47
49
  handler = WinRM::ResponseHandler.new(resp.http_body.content, resp.status)
48
- handler.parse_to_xml()
50
+ handler.parse_to_xml
49
51
  end
50
52
 
51
53
  # We'll need this to force basic authentication if desired
52
54
  def basic_auth_only!
53
55
  auths = @httpcli.www_auth.instance_variable_get('@authenticator')
54
- auths.delete_if {|i| i.scheme !~ /basic/i}
56
+ auths.delete_if { |i| i.scheme !~ /basic/i }
55
57
  end
56
58
 
57
59
  # Disable SSPI Auth
58
60
  def no_sspi_auth!
59
61
  auths = @httpcli.www_auth.instance_variable_get('@authenticator')
60
- auths.delete_if {|i| i.is_a? HTTPClient::SSPINegotiateAuth }
62
+ auths.delete_if { |i| i.is_a? HTTPClient::SSPINegotiateAuth }
61
63
  end
62
64
 
63
65
  # Disable SSL Peer Verification
@@ -71,7 +73,7 @@ module WinRM
71
73
  @httpcli.receive_timeout = sec
72
74
  end
73
75
 
74
- def receive_timeout()
76
+ def receive_timeout
75
77
  @httpcli.receive_timeout
76
78
  end
77
79
 
@@ -79,7 +81,7 @@ module WinRM
79
81
 
80
82
  def log_soap_message(message)
81
83
  return unless @logger.debug?
82
-
84
+
83
85
  xml_msg = REXML::Document.new(message)
84
86
  formatter = REXML::Formatters::Pretty.new(2)
85
87
  formatter.compact = true
@@ -90,7 +92,7 @@ module WinRM
90
92
  end
91
93
  end
92
94
 
93
-
95
+ # Plain text, insecure, HTTP transport
94
96
  class HttpPlaintext < HttpTransport
95
97
  def initialize(endpoint, user, pass, opts)
96
98
  super(endpoint)
@@ -114,12 +116,15 @@ module WinRM
114
116
  end
115
117
 
116
118
  # Uses Kerberos/GSSAPI to authenticate and encrypt messages
119
+ # rubocop:disable Metrics/ClassLength
117
120
  class HttpGSSAPI < HttpTransport
118
121
  # @param [String,URI] endpoint the WinRM webservice endpoint
119
122
  # @param [String] realm the Kerberos realm we are authenticating to
120
123
  # @param [String<optional>] service the service name, default is HTTP
121
124
  # @param [String<optional>] keytab the path to a keytab file if you are using one
125
+ # rubocop:disable Lint/UnusedMethodArgument
122
126
  def initialize(endpoint, realm, service = nil, keytab = nil, opts)
127
+ # rubocop:enable Lint/UnusedMethodArgument
123
128
  super(endpoint)
124
129
  # Remove the GSSAPI auth from HTTPClient because we are doing our own thing
125
130
  no_sspi_auth!
@@ -137,18 +142,20 @@ module WinRM
137
142
  resp = send_kerberos_request(message)
138
143
 
139
144
  if resp.status == 401
140
- @logger.debug "Got 401 - reinitializing Kerberos and retrying one more time"
145
+ @logger.debug 'Got 401 - reinitializing Kerberos and retrying one more time'
141
146
  init_krb
142
147
  resp = send_kerberos_request(message)
143
148
  end
144
149
 
145
150
  handler = WinRM::ResponseHandler.new(winrm_decrypt(resp.http_body.content), resp.status)
146
- handler.parse_to_xml()
151
+ handler.parse_to_xml
147
152
  end
148
153
 
149
-
150
154
  private
151
155
 
156
+ # rubocop:disable Metrics/MethodLength
157
+ # rubocop:disable Metrics/AbcSize
158
+
152
159
  # Sends the SOAP payload to the WinRM service and returns the service's
153
160
  # HTTP response.
154
161
  #
@@ -159,8 +166,11 @@ module WinRM
159
166
  original_length = message.length
160
167
  pad_len, emsg = winrm_encrypt(message)
161
168
  hdr = {
162
- "Connection" => "Keep-Alive",
163
- "Content-Type" => "multipart/encrypted;protocol=\"application/HTTP-Kerberos-session-encrypted\";boundary=\"Encrypted Boundary\""
169
+ 'Connection' => 'Keep-Alive',
170
+ 'Content-Type' =>
171
+ 'multipart/encrypted;' \
172
+ 'protocol="application/HTTP-Kerberos-session-encrypted";' \
173
+ 'boundary="Encrypted Boundary"'
164
174
  }
165
175
 
166
176
  body = <<-EOF
@@ -183,13 +193,14 @@ Content-Type: application/octet-stream\r
183
193
  token = @gsscli.init_context
184
194
  auth = Base64.strict_encode64 token
185
195
 
186
- hdr = {"Authorization" => "Kerberos #{auth}",
187
- "Connection" => "Keep-Alive",
188
- "Content-Type" => "application/soap+xml;charset=UTF-8"
196
+ hdr = {
197
+ 'Authorization' => "Kerberos #{auth}",
198
+ 'Connection' => 'Keep-Alive',
199
+ 'Content-Type' => 'application/soap+xml;charset=UTF-8'
189
200
  }
190
- @logger.debug "Sending HTTP POST for Kerberos Authentication"
201
+ @logger.debug 'Sending HTTP POST for Kerberos Authentication'
191
202
  r = @httpcli.post(@endpoint, '', hdr)
192
- itok = r.header["WWW-Authenticate"].pop
203
+ itok = r.header['WWW-Authenticate'].pop
193
204
  itok = itok.split.last
194
205
  itok = Base64.strict_decode64(itok)
195
206
  @gsscli.init_context(itok)
@@ -202,19 +213,30 @@ Content-Type: application/octet-stream\r
202
213
  iov = FFI::MemoryPointer.new(GSSAPI::LibGSSAPI::GssIOVBufferDesc.size * iov_cnt)
203
214
 
204
215
  iov0 = GSSAPI::LibGSSAPI::GssIOVBufferDesc.new(FFI::Pointer.new(iov.address))
205
- iov0[:type] = (GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_TYPE_HEADER | GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_FLAG_ALLOCATE)
216
+ iov0[:type] = (GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_TYPE_HEADER | \
217
+ GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_FLAG_ALLOCATE)
206
218
 
207
- iov1 = GSSAPI::LibGSSAPI::GssIOVBufferDesc.new(FFI::Pointer.new(iov.address + (GSSAPI::LibGSSAPI::GssIOVBufferDesc.size * 1)))
219
+ iov1 = GSSAPI::LibGSSAPI::GssIOVBufferDesc.new(
220
+ FFI::Pointer.new(iov.address + (GSSAPI::LibGSSAPI::GssIOVBufferDesc.size * 1)))
208
221
  iov1[:type] = (GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_TYPE_DATA)
209
222
  iov1[:buffer].value = str
210
223
 
211
- iov2 = GSSAPI::LibGSSAPI::GssIOVBufferDesc.new(FFI::Pointer.new(iov.address + (GSSAPI::LibGSSAPI::GssIOVBufferDesc.size * 2)))
212
- iov2[:type] = (GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_TYPE_PADDING | GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_FLAG_ALLOCATE)
224
+ iov2 = GSSAPI::LibGSSAPI::GssIOVBufferDesc.new(
225
+ FFI::Pointer.new(iov.address + (GSSAPI::LibGSSAPI::GssIOVBufferDesc.size * 2)))
226
+ iov2[:type] = (GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_TYPE_PADDING | \
227
+ GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_FLAG_ALLOCATE)
213
228
 
214
229
  conf_state = FFI::MemoryPointer.new :uint32
215
230
  min_stat = FFI::MemoryPointer.new :uint32
216
231
 
217
- maj_stat = GSSAPI::LibGSSAPI.gss_wrap_iov(min_stat, @gsscli.context, 1, GSSAPI::LibGSSAPI::GSS_C_QOP_DEFAULT, conf_state, iov, iov_cnt)
232
+ GSSAPI::LibGSSAPI.gss_wrap_iov(
233
+ min_stat,
234
+ @gsscli.context,
235
+ 1,
236
+ GSSAPI::LibGSSAPI::GSS_C_QOP_DEFAULT,
237
+ conf_state,
238
+ iov,
239
+ iov_cnt)
218
240
 
219
241
  token = [iov0[:buffer].length].pack('L')
220
242
  token += iov0[:buffer].value
@@ -224,7 +246,6 @@ Content-Type: application/octet-stream\r
224
246
  [pad_len, token]
225
247
  end
226
248
 
227
-
228
249
  # @return [String] the unencrypted response string
229
250
  def winrm_decrypt(str)
230
251
  @logger.debug "Decrypting SOAP message:\n#{str}"
@@ -232,18 +253,21 @@ Content-Type: application/octet-stream\r
232
253
  iov = FFI::MemoryPointer.new(GSSAPI::LibGSSAPI::GssIOVBufferDesc.size * iov_cnt)
233
254
 
234
255
  iov0 = GSSAPI::LibGSSAPI::GssIOVBufferDesc.new(FFI::Pointer.new(iov.address))
235
- iov0[:type] = (GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_TYPE_HEADER | GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_FLAG_ALLOCATE)
256
+ iov0[:type] = (GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_TYPE_HEADER | \
257
+ GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_FLAG_ALLOCATE)
236
258
 
237
- iov1 = GSSAPI::LibGSSAPI::GssIOVBufferDesc.new(FFI::Pointer.new(iov.address + (GSSAPI::LibGSSAPI::GssIOVBufferDesc.size * 1)))
259
+ iov1 = GSSAPI::LibGSSAPI::GssIOVBufferDesc.new(
260
+ FFI::Pointer.new(iov.address + (GSSAPI::LibGSSAPI::GssIOVBufferDesc.size * 1)))
238
261
  iov1[:type] = (GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_TYPE_DATA)
239
262
 
240
- iov2 = GSSAPI::LibGSSAPI::GssIOVBufferDesc.new(FFI::Pointer.new(iov.address + (GSSAPI::LibGSSAPI::GssIOVBufferDesc.size * 2)))
263
+ iov2 = GSSAPI::LibGSSAPI::GssIOVBufferDesc.new(
264
+ FFI::Pointer.new(iov.address + (GSSAPI::LibGSSAPI::GssIOVBufferDesc.size * 2)))
241
265
  iov2[:type] = (GSSAPI::LibGSSAPI::GSS_IOV_BUFFER_TYPE_DATA)
242
266
 
243
267
  str.force_encoding('BINARY')
244
268
  str.sub!(/^.*Content-Type: application\/octet-stream\r\n(.*)--Encrypted.*$/m, '\1')
245
269
 
246
- len = str.unpack("L").first
270
+ len = str.unpack('L').first
247
271
  iov_data = str.unpack("LA#{len}A*")
248
272
  iov0[:buffer].value = iov_data[1]
249
273
  iov1[:buffer].value = iov_data[2]
@@ -254,13 +278,17 @@ Content-Type: application/octet-stream\r
254
278
  qop_state = FFI::MemoryPointer.new :uint32
255
279
  qop_state.write_int(0)
256
280
 
257
- maj_stat = GSSAPI::LibGSSAPI.gss_unwrap_iov(min_stat, @gsscli.context, conf_state, qop_state, iov, iov_cnt)
281
+ maj_stat = GSSAPI::LibGSSAPI.gss_unwrap_iov(
282
+ min_stat, @gsscli.context, conf_state, qop_state, iov, iov_cnt)
258
283
 
259
- @logger.debug "SOAP message decrypted (MAJ: #{maj_stat}, MIN: #{min_stat.read_int}):\n#{iov1[:buffer].value}"
284
+ @logger.debug "SOAP message decrypted (MAJ: #{maj_stat}, " \
285
+ "MIN: #{min_stat.read_int}):\n#{iov1[:buffer].value}"
260
286
 
261
287
  iov1[:buffer].value
262
288
  end
263
-
289
+ # rubocop:enable Metrics/MethodLength
290
+ # rubocop:enable Metrics/AbcSize
264
291
  end
292
+ # rubocop:enable Metrics/ClassLength
265
293
  end
266
294
  end # WinRM
data/lib/winrm/output.rb CHANGED
@@ -1,3 +1,19 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Copyright 2014 Max Lincoln <max@devopsy.com>
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
1
17
  module WinRM
2
18
  # This class holds raw output as a hash, and has convenience methods to parse.
3
19
  class Output < Hash
@@ -1,11 +1,13 @@
1
+ # encoding: UTF-8
2
+ #
1
3
  # Copyright 2010 Dan Wanek <dan.wanek@gmail.com>
2
- #
4
+ #
3
5
  # Licensed under the Apache License, Version 2.0 (the "License");
4
6
  # you may not use this file except in compliance with the License.
5
7
  # You may obtain a copy of the License at
6
- #
8
+ #
7
9
  # http://www.apache.org/licenses/LICENSE-2.0
8
- #
10
+ #
9
11
  # Unless required by applicable law or agreed to in writing, software
10
12
  # distributed under the License is distributed on an "AS IS" BASIS,
11
13
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -18,18 +20,19 @@ require 'gyoku'
18
20
  require 'uuidtools'
19
21
  require 'base64'
20
22
 
23
+ # SOAP constants for WinRM
21
24
  module WinRM
22
- NS_SOAP_ENV ='s' # http://www.w3.org/2003/05/soap-envelope
23
- NS_ADDRESSING ='a' # http://schemas.xmlsoap.org/ws/2004/08/addressing
24
- NS_CIMBINDING ='b' # http://schemas.dmtf.org/wbem/wsman/1/cimbinding.xsd
25
- NS_ENUM ='n' # http://schemas.xmlsoap.org/ws/2004/09/enumeration
26
- NS_TRANSFER ='x' # http://schemas.xmlsoap.org/ws/2004/09/transfer
27
- NS_WSMAN_DMTF ='w' # http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd
28
- NS_WSMAN_MSFT ='p' # http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd
29
- NS_SCHEMA_INST ='xsi' # http://www.w3.org/2001/XMLSchema-instance
30
- NS_WIN_SHELL ='rsp' # http://schemas.microsoft.com/wbem/wsman/1/windows/shell
31
- NS_WSMAN_FAULT = 'f' # http://schemas.microsoft.com/wbem/wsman/1/wsmanfault
32
- NS_WSMAN_CONF = 'cfg'# http://schemas.microsoft.com/wbem/wsman/1/config
25
+ NS_SOAP_ENV = 's' # http://www.w3.org/2003/05/soap-envelope
26
+ NS_ADDRESSING = 'a' # http://schemas.xmlsoap.org/ws/2004/08/addressing
27
+ NS_CIMBINDING = 'b' # http://schemas.dmtf.org/wbem/wsman/1/cimbinding.xsd
28
+ NS_ENUM = 'n' # http://schemas.xmlsoap.org/ws/2004/09/enumeration
29
+ NS_TRANSFER = 'x' # http://schemas.xmlsoap.org/ws/2004/09/transfer
30
+ NS_WSMAN_DMTF = 'w' # http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd
31
+ NS_WSMAN_MSFT = 'p' # http://schemas.microsoft.com/wbem/wsman/1/wsman.xsd
32
+ NS_SCHEMA_INST = 'xsi' # http://www.w3.org/2001/XMLSchema-instance
33
+ NS_WIN_SHELL = 'rsp' # http://schemas.microsoft.com/wbem/wsman/1/windows/shell
34
+ NS_WSMAN_FAULT = 'f' # http://schemas.microsoft.com/wbem/wsman/1/wsmanfault
35
+ NS_WSMAN_CONF = 'cfg' # http://schemas.microsoft.com/wbem/wsman/1/config
33
36
  end
34
37
 
35
38
  require 'winrm/exceptions/exceptions'
@@ -1,11 +1,13 @@
1
+ # encoding: UTF-8
2
+ #
1
3
  # Copyright 2010 Dan Wanek <dan.wanek@gmail.com>
2
- #
4
+ #
3
5
  # Licensed under the Apache License, Version 2.0 (the "License");
4
6
  # you may not use this file except in compliance with the License.
5
7
  # You may obtain a copy of the License at
6
- #
8
+ #
7
9
  # http://www.apache.org/licenses/LICENSE-2.0
8
- #
10
+ #
9
11
  # Unless required by applicable law or agreed to in writing, software
10
12
  # distributed under the License is distributed on an "AS IS" BASIS,
11
13
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -17,10 +19,9 @@ require 'rexml/document'
17
19
  require_relative 'helpers/powershell_script'
18
20
 
19
21
  module WinRM
20
- # This is the main class that does the SOAP request/response logic. There are a few helper classes, but pretty
21
- # much everything comes through here first.
22
+ # This is the main class that does the SOAP request/response logic. There are a few helper
23
+ # classes, but pretty much everything comes through here first.
22
24
  class WinRMWebService
23
-
24
25
  DEFAULT_TIMEOUT = 'PT60S'
25
26
  DEFAULT_MAX_ENV_SIZE = 153600
26
27
  DEFAULT_LOCALE = 'en-US'
@@ -249,6 +250,13 @@ module WinRM
249
250
  output[:exitcode] = REXML::XPath.first(resp_doc, "//#{NS_WIN_SHELL}:ExitCode").text.to_i
250
251
  end
251
252
  output
253
+ rescue WinRMWSManFault => e
254
+ # If no output is available before the wsman:OperationTimeout expires,
255
+ # the server MUST return a WSManFault with the Code attribute equal to
256
+ # 2150858793. When the client receives this fault, it SHOULD issue
257
+ # another Receive request.
258
+ # http://msdn.microsoft.com/en-us/library/cc251676.aspx
259
+ retry if e.fault_code == '2150858793'
252
260
  end
253
261
 
254
262
  # Clean-up after a command.