tiebreaker 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,789 @@
1
+ #============================================================#
2
+ # #
3
+ # $ID:$ #
4
+ # #
5
+ # NaServer.rb #
6
+ # #
7
+ # Client-side interface to ONTAP and DataFabric Manager APIs.#
8
+ # #
9
+ # Copyright (c) 2011 NetApp, Inc. All rights reserved. #
10
+ # Specifications subject to change without notice. #
11
+ # #
12
+ #============================================================#
13
+
14
+ require 'net/http'
15
+ require 'net/https'
16
+ require 'rexml/document'
17
+ require 'rexml/streamlistener'
18
+ include REXML
19
+ require 'stringio'
20
+ include StreamListener
21
+ require 'NaElement'
22
+ require 'pathname'
23
+
24
+ # Official NMSDK release version
25
+ $NMSDK_VERSION = '5.4'
26
+
27
+ # This method return the platform information of unix systems.
28
+ # This method is used internally for NMSDK/API Usage Tracking.
29
+ # NOTE: DO NOT REMOVE/MODIFY THIS METHOD.
30
+ # NOTE: DO NOT USE THIS METHOD EXTERNALLY.
31
+ def get_unix_info()
32
+ v = $VERBOSE
33
+ $VERBOSE = nil
34
+ sysname = `uname -s`
35
+ $VERBOSE = v
36
+ sysname = sysname.chomp
37
+
38
+ if(sysname.include?("Linux")) # for linux (rhel, suse, oel)
39
+ # check if it is SUSE
40
+ filepath = Pathname.new("/etc/SuSE-release")
41
+ if(filepath.exist?())
42
+ release_file = '/etc/SuSE-release'
43
+ else # for RHEL, OEL, etc.
44
+ release_file = '/etc/issue'
45
+ end
46
+
47
+ $VERBOSE = nil
48
+ flavor = `head -n 1 #{release_file}`
49
+ $VERBOSE = v
50
+ # Remove the string within parentheses
51
+ sysname = flavor.sub(/\(\w+\)/, '').chomp
52
+ sysname = sysname.sub(/\s+\Z/, "")
53
+
54
+ else # for other unix platforms (solaris, aix, hpux)
55
+ $VERBOSE = nil
56
+ if(sysname.eql?("AIX"))
57
+ version = `oslevel`
58
+ else
59
+ version = `uname -r`
60
+ end
61
+ $VERBOSE = v
62
+ sysname = sysname + " " + version.chomp
63
+ end
64
+
65
+ $VERBOSE = nil
66
+ if(sysname.eql?("HP-UX"))
67
+ processor = `uname -m`
68
+ else
69
+ processor = `uname -p`
70
+ end
71
+
72
+ if(sysname.include?("SunOS"))
73
+ isainfo = `isainfo -b`
74
+ isainfo = isainfo.chomp
75
+ bitinfo = " " + isainfo + "-bit"
76
+ else
77
+ bitinfo = ""
78
+ end
79
+ $VERBOSE = v
80
+
81
+ os_info = sysname + " " + processor.chomp + bitinfo
82
+ return os_info
83
+ end
84
+
85
+
86
+ # This method return the platform information of windows systems.
87
+ # This method is used internally for NMSDK/API Usage Tracking.
88
+ # NOTE: DO NOT REMOVE/MODIFY THIS METHOD.
89
+ # NOTE: DO NOT USE THIS METHOD EXTERNALLY.
90
+ def get_windows_info()
91
+ sysname = ""
92
+ processor = ""
93
+ os_info = ""
94
+
95
+ require 'win32/registry'
96
+
97
+ Win32::Registry::HKEY_LOCAL_MACHINE.open('SOFTWARE\Microsoft\Windows NT\CurrentVersion') do |reg|
98
+ type, sysname = reg.read('ProductName')
99
+ end
100
+
101
+ Win32::Registry::HKEY_LOCAL_MACHINE.open('SYSTEM\ControlSet001\Control\Session Manager\Environment') do |reg|
102
+ type, processor = reg.read('PROCESSOR_ARCHITECTURE')
103
+ end
104
+
105
+ os_info = sysname + " " + processor
106
+ return os_info
107
+ end
108
+
109
+ # The client platform information string.
110
+ # NOTE: DO NOT REMOVE/MODIFY THIS VARIABLE.
111
+ $NMSDK_PLATFORM = ""
112
+ platform = RUBY_PLATFORM
113
+ if (platform.include?("mingw") )
114
+ $NMSDK_PLATFORM = get_windows_info()
115
+ else
116
+ $NMSDK_PLATFORM = get_unix_info()
117
+ end
118
+
119
+
120
+ # Class for managing Network Appliance(r) Storage System
121
+ # using ONTAPI(tm) and DataFabric Manager API(tm).
122
+ #
123
+ # An NaServer encapsulates an administrative connection to
124
+ # a NetApp Storage Systems running Data ONTAP 6.4 or later.
125
+ # NaServer can also be used to establish connection with
126
+ # OnCommand Unified Manager (OCUM). You construct NaElement objects
127
+ # that represent queries or commands, and use invoke_elem()
128
+ # to send them to the storage systems or OCUM server. Also,
129
+ # a convenience routine called invoke() can be used to bypass
130
+ # the element construction step. The return from the call is
131
+ # another NaElement which either has children containing the
132
+ # command results, or an error indication.
133
+ #
134
+ # The following routines are available for setting up
135
+ # administrative connections to a storage system or OCUM server.
136
+ #
137
+
138
+ $ZAPI_stack = []
139
+ $ZAPI_atts = {}
140
+ $tag_element_stack = []
141
+
142
+ class NaServer
143
+
144
+ #dtd files
145
+ FILER_dtd = 'file:/etc/netapp_filer.dtd'
146
+ DFM_dtd = 'file:/etc/netapp_dfm.dtd'
147
+ AGENT_dtd = 'file:/etc/netapp_agent.dtd'
148
+
149
+ #URLs
150
+ AGENT_URL = '/apis/XMLrequest'
151
+ FILER_URL = '/servlets/netapp.servlets.admin.XMLrequest_filer'
152
+ NETCACHE_URL = '/servlets/netapp.servlets.admin.XMLrequest'
153
+ DFM_URL = '/apis/XMLrequest'
154
+
155
+ ZAPI_xmlns = 'http://www.netapp.com/filer/admin'
156
+
157
+ # Create a new connection to server 'server'. Before use,
158
+ # you either need to set the style to "hosts.equiv" or set
159
+ # the username (always "root" at present) and password with
160
+ # set_admin_user().
161
+
162
+ def initialize(server, major_version, minor_version)
163
+ @server = server
164
+ @major_version = major_version
165
+ @minor_version = minor_version
166
+ @transport_type = "HTTP"
167
+ @port = 80
168
+ @user = "root"
169
+ @password = ""
170
+ @style = "LOGIN"
171
+ @timeout = 0
172
+ @vfiler = ""
173
+ @server_type = "FILER"
174
+ @debug_style = ""
175
+ @xml = ""
176
+ @originator_id = ""
177
+ @enable_server_cert_verification = false
178
+ @enable_hostname_verification = false
179
+ @cert_file = nil
180
+ @key_file = nil
181
+ @key_passwd = nil
182
+ @ca_file = nil
183
+ @url = FILER_URL
184
+ @dtd = FILER_dtd
185
+
186
+ # Following parameters are used for NMSDK/API Usage Tracking.
187
+ # NOTE: DO NOT REMOVE/MODIFY THESE VARIABLES.
188
+ @nmsdk_version = $NMSDK_VERSION
189
+ @nmsdk_platform = $NMSDK_PLATFORM
190
+ @nmsdk_language = "Ruby"
191
+ @nmsdk_app = ""
192
+ end
193
+
194
+
195
+ # Set the client application name.
196
+ def set_application_name(app_name)
197
+ @nmsdk_app = app_name
198
+ end
199
+
200
+
201
+ # Get the client application name.
202
+ def get_application_name()
203
+ return @nmsdk_app
204
+ end
205
+
206
+
207
+ # Pass in 'LOGIN' to cause the server to use HTTP simple
208
+ # authentication with a username and password. Pass in 'HOSTS'
209
+ # to use the hosts.equiv file on the filer to determine access
210
+ # rights (the username must be root in that case). Pass in
211
+ # 'CERTIFICATE' to use certificate based authentication with the
212
+ # DataFabric Manager server.
213
+ #
214
+ # If $style = CERTIFICATE, you can use certificates to authenticate
215
+ # clients who attempt to connect to a server without the need of
216
+ # username and password. This style will internally set the transport
217
+ # type to HTTPS. Verification of the server's certificate is required
218
+ # in order to properly authenticate the identity of the server.
219
+ # Server certificate verification will be enabled by default using this
220
+ # style and Server certificate verification will always enable hostname
221
+ # verification. You can disable server certificate (with hostname)
222
+ # verification using set_server_cert_verification().
223
+
224
+ def set_style(style)
225
+ if(!style.eql?("HOSTS") and !style.eql?("LOGIN") and !style.eql?("CERTIFICATE"))
226
+ return fail_response(13001, "NaServer::set_style: bad style \"" + style + "\"")
227
+ end
228
+ if (style.eql?("CERTIFICATE"))
229
+ ret = set_transport_type("HTTPS")
230
+ if (ret)
231
+ return ret
232
+ end
233
+ @enable_server_cert_verification = true
234
+ @enable_hostname_verification = true
235
+ else
236
+ @enable_server_cert_verification = false
237
+ @enable_hostname_verification = false
238
+ end
239
+ @style = style
240
+ return nil
241
+ end
242
+
243
+
244
+ # Get the authentication style
245
+
246
+ def get_style()
247
+ return @style
248
+ end
249
+
250
+
251
+ # Set the admin username and password. At present 'user' must always be 'root'.
252
+
253
+ def set_admin_user(user, password)
254
+ @user = user
255
+ @password = password
256
+ end
257
+
258
+
259
+
260
+ # Pass in one of these keywords: 'FILER' or 'DFM' or 'OCUM' to indicate
261
+ # whether the server is a storage system (filer) or a OCUM server.
262
+ #
263
+ # If you also use set_port(), call set_port() AFTER calling this routine.
264
+ #
265
+ # The default is 'FILER'.
266
+
267
+ def set_server_type(server_type)
268
+ if (server_type.casecmp('filer') == 0)
269
+ @url = FILER_URL
270
+ @dtd = FILER_dtd
271
+ elsif (server_type.casecmp('netcache') == 0)
272
+ @url = NETCACHE_URL
273
+ @port = 80
274
+ elsif (server_type.casecmp('agent') == 0)
275
+ @url = AGENT_URL
276
+ @port = 4092
277
+ @dtd = AGENT_dtd
278
+ elsif (server_type.casecmp('dfm') == 0)
279
+ @url = DFM_URL
280
+ @port = 8088
281
+ @dtd = DFM_dtd
282
+ if(@transport_type == "HTTPS")
283
+ @port = 8488
284
+ end
285
+ elsif (server_type.casecmp('ocum') == 0)
286
+ @url = DFM_URL
287
+ @port = 443
288
+ @transport_type = "HTTPS"
289
+ @dtd = DFM_dtd
290
+ else
291
+ return fail_response(13001, "NaServer::set_server_type: bad type \"" + server_type + "\"")
292
+ end
293
+ @server_type = server_type
294
+ return nil
295
+ end
296
+
297
+
298
+ # Get the type of server this server connection applies to.
299
+
300
+ def get_server_type()
301
+ return @server_type
302
+ end
303
+
304
+
305
+ # Override the default transport type. The valid transport
306
+ # type are currently 'HTTP' and 'HTTPS'.
307
+
308
+ def set_transport_type(scheme)
309
+ if(!scheme.eql?("HTTP") and !scheme.eql?("HTTPS"))
310
+ return fail_response(13001, "NaServer::set_transport_type: bad type \" " + scheme + "\"")
311
+ end
312
+ if(scheme.eql?("HTTP"))
313
+ if(@server_type.eql?("OCUM"))
314
+ return fail_response(13001, "Server type '" + @server_type + "' does not support '" + scheme + "' transport type")
315
+ end
316
+
317
+ @transport_type = "HTTP"
318
+ if(@server_type.eql?("DFM"))
319
+ @port = 8088
320
+ else
321
+ @port = 80
322
+ end
323
+ elsif(scheme.eql?("HTTPS"))
324
+ @transport_type = "HTTPS"
325
+ if(@server_type.eql?("DFM"))
326
+ @port = 8488
327
+ else
328
+ @port = 443
329
+ end
330
+ end
331
+ return nil
332
+ end
333
+
334
+
335
+ # Retrieve the transport used for this connection.
336
+
337
+ def get_transport_type()
338
+ return @transport_type
339
+ end
340
+
341
+
342
+ # Set the style of debug.
343
+
344
+ def set_debug_style(debug_style)
345
+ if(!debug_style.eql?("NA_PRINT_DONT_PARSE"))
346
+ return fail_response(13001, "NaServer::set_debug_style: bad style \"" + debug_style + "\"")
347
+ else
348
+ @debug_style = debug_style
349
+ end
350
+ end
351
+
352
+
353
+ # Override the default port for this server. If you
354
+ # also call set_server_type(), you must call it before
355
+ # calling set_port().
356
+
357
+ def set_port(port)
358
+ @port = port
359
+ end
360
+
361
+
362
+ # Retrieve the port used for the remote server.
363
+
364
+ def get_port()
365
+ return @port
366
+ end
367
+
368
+
369
+ # Check the type of debug style and return the
370
+ # value for different needs. Return true if debug style
371
+ # is NA_PRINT_DONT_PARSE, else return false.
372
+
373
+ def is_debugging()
374
+ if(@debug_style.eql?("NA_PRINT_DONT_PARSE"))
375
+ return true
376
+ else
377
+ return false
378
+ end
379
+ end
380
+
381
+
382
+ # Return the raw XML output.
383
+
384
+ def get_raw_xml_output()
385
+ return @xml
386
+ end
387
+
388
+
389
+ # Save the raw XML output.
390
+
391
+ def set_raw_xml_output(xml)
392
+ @xml = xml
393
+ end
394
+
395
+
396
+ # Determines whether https is enabled.
397
+
398
+ def use_https()
399
+ if(@transport_type.eql?("HTTPS"))
400
+ return true
401
+ else
402
+ return false
403
+ end
404
+ end
405
+
406
+
407
+ def parse_raw_xml(xmlresponse)
408
+ xml_response = StringIO.new(xmlresponse)
409
+ Document.parse_stream(xml_response, MyListener.new)
410
+ if($tag_element_stack.length > 0)
411
+ print("\nError : No corresponding end tag for the element \"" + $tag_element_stack.pop() + "\"\n")
412
+ exit
413
+ end
414
+ stack_len = $ZAPI_stack.length
415
+ if(stack_len <= 0)
416
+ return fail_response(13001, "Zapi::parse_xml-no elements on stack")
417
+ end
418
+ r = $ZAPI_stack.pop()
419
+ return r
420
+ end
421
+
422
+
423
+
424
+ def parse_xml(xmlresponse)
425
+ xml_response = StringIO.new(xmlresponse)
426
+ Document.parse_stream(xml_response, MyListener.new)
427
+ if($tag_element_stack.length > 0)
428
+ print("\nError : No corresponding end tag for the element \"" + $tag_element_stack.pop() + "\"\n")
429
+ exit
430
+ end
431
+ stack_len = $ZAPI_stack.length
432
+ if(stack_len <= 0)
433
+ return fail_response(13001, "Zapi::parse_xml-no elements on stack")
434
+ end
435
+ r = $ZAPI_stack.pop()
436
+ if (r.name != "netapp")
437
+ return fail_response(13001, "Zapi::parse_xml - Expected <netapp> element but got" + r.name)
438
+ end
439
+ results = r.child_get("results")
440
+ unless(results)
441
+ return fail_response(13001, "Zapi::parse_xml - No results element in output!")
442
+ end
443
+ return results
444
+ end
445
+
446
+
447
+ # Submit an XML request already encapsulated as
448
+ # an NaElement and return the result in another
449
+ # NaElement.
450
+
451
+ def invoke_elem(req)
452
+ xmlrequest = req.toEncodedString()
453
+ vfiler_req = ""
454
+ originator_id_req = ""
455
+ if(!@vfiler.eql?(""))
456
+ vfiler_req = " vfiler=\"" + @vfiler + "\""
457
+ end
458
+ if(!@originator_id.eql?(""))
459
+ originator_id_req = " originator_id=\"" + @originator_id + "\""
460
+ end
461
+
462
+ app_name_req = ""
463
+ if(!@nmsdk_app.eql?(""))
464
+ app_name_req = " nmsdk_app='" + @nmsdk_app + "'"
465
+ end
466
+
467
+ content = "<?xml version=\'1.0\' encoding=\'utf-8\'?>" +
468
+ "\n" +
469
+ "<!DOCTYPE netapp SYSTEM \'" + @dtd + "\'>" +
470
+ "\n" +
471
+ "<netapp" +
472
+ vfiler_req +
473
+ originator_id_req +
474
+ " version='" + @major_version.to_s() + "." + @minor_version.to_s() + "' xmlns='" + ZAPI_xmlns + "'" +
475
+ " nmsdk_version='" + @nmsdk_version + "'" +
476
+ " nmsdk_platform='" + @nmsdk_platform + "'" +
477
+ " nmsdk_language='" + @nmsdk_language + "'" +
478
+ app_name_req +
479
+ ">" +
480
+ xmlrequest +
481
+ "</netapp>"
482
+
483
+ if(@debug_style.eql?("NA_PRINT_DONT_PARSE"))
484
+ print("INPUT \n " + content)
485
+ end
486
+
487
+ begin
488
+ http = Net::HTTP.new(@server, @port)
489
+ if(@transport_type.eql?("HTTPS"))
490
+ http.use_ssl = true
491
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
492
+ # Server Certificate Verification
493
+ if(@enable_server_cert_verification.eql?(true))
494
+ http.ca_file = @ca_file
495
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
496
+ unless(@enable_hostname_verification)
497
+ OpenSSL::SSL.module_eval do
498
+ verify_method = method(:verify_certificate_identity)
499
+ metaclass = class << OpenSSL::SSL; self; end
500
+ metaclass.send :define_method, :verify_certificate_identity do |cert, hostname|
501
+ true
502
+ end
503
+ end
504
+ end
505
+ end
506
+ # Client Certificate Verification
507
+ if(@cert_file != nil)
508
+ pem = File.read(@cert_file)
509
+ http.cert = OpenSSL::X509::Certificate.new(pem)
510
+ # @key_file is nil when the certificate and key are in the same file (@cert_file)
511
+ if(@key_file == nil)
512
+ http.key = OpenSSL::PKey::RSA.new(pem)
513
+ else
514
+ key = File.read(@key_file)
515
+ http.key = OpenSSL::PKey::RSA.new(key, @key_passwd)
516
+ end
517
+ end
518
+ end
519
+ if(@timeout > 0)
520
+ http.open_timeout = @timeout
521
+ http.read_timeout = @timeout
522
+ end
523
+ request = Net::HTTP::Post.new(@url)
524
+ if(!@style.eql?("HOSTS"))
525
+ request.basic_auth @user, @password
526
+ end
527
+ request.content_type = "text/xml; charset=\"UTF-8\""
528
+ request.body = content
529
+ response = http.start {|http| http.request(request)}
530
+ rescue Timeout::Error => msg
531
+ print("\nError : ")
532
+ return fail_response(13001, msg)
533
+ rescue Errno::ECONNREFUSED => msg
534
+ print("\nError : ")
535
+ return fail_response(111, msg)
536
+ rescue OpenSSL::SSL::SSLError => msg
537
+ return fail_response(13001, msg)
538
+ rescue => msg
539
+ print("\nError : ")
540
+ return fail_response(13001, msg)
541
+ end
542
+
543
+ if(!response)
544
+ return fail_response(13001,"No response received")
545
+ end
546
+ if(response.code.eql?("401"))
547
+ return fail_response(13002,"Authorization failed")
548
+ end
549
+ return parse_xml(response.body)
550
+ end
551
+
552
+
553
+ #A convenience routine which wraps invoke_elem().
554
+ #It constructs an NaElement with name $api, and for
555
+ #each argument name/value pair, adds a child element
556
+ #to it. It's an error to have an even number of
557
+ #arguments to this function.
558
+ #Example: myserver->invoke('snapshot-create',
559
+ # 'snapshot', 'mysnapshot',
560
+ # 'volume', 'vol0');
561
+ #
562
+
563
+ def invoke(api, *args)
564
+ num_parms = args.length
565
+ if ((num_parms & 1) != 0)
566
+ return self.fail_response(13001, "in Zapi::invoke, invalid number of parameters")
567
+ end
568
+ xi = NaElement.new(api)
569
+ i = 0
570
+ while(i < num_parms)
571
+ key = args[i]
572
+ i = i + 1
573
+ value = args[i]
574
+ i = i + 1
575
+ xi.child_add(NaElement.new(key, value))
576
+ end
577
+ return invoke_elem(xi)
578
+ end
579
+
580
+
581
+ #Sets the vfiler name. This function is used for vfiler-tunneling.
582
+
583
+ def set_vfiler(vfiler_name)
584
+ if(@major_version >= 1 and @minor_version >= 7)
585
+ @vfiler = vfiler_name
586
+ return 1
587
+ end
588
+ return 0
589
+ end
590
+
591
+
592
+ # Sets the vserver name. This function is used for vfiler-tunneling.
593
+ # However, vserver tunneling actually uses vfiler-tunneling.
594
+ # Hence this function internally sets the vfiler name.
595
+
596
+ def set_vserver(vserver_name)
597
+ if(@major_version >= 1 and @minor_version >= 15)
598
+ @vfiler = vserver_name
599
+ return 1
600
+ end
601
+ print("\nONTAPI version must be at least 1.15 to send API to a vserver\n")
602
+ return 0
603
+ end
604
+
605
+
606
+ # Gets the vserver name. This function is added for vserver-tunneling.
607
+ # However, vserver tunneling actually uses vfiler-tunneling. Hence this
608
+ # function actually returns the vfiler name.
609
+
610
+ def get_vserver()
611
+ return @vfiler
612
+ end
613
+
614
+
615
+ # Function to set the originator_id before executing any ONTAP API.
616
+
617
+ def set_originator_id(originator_id)
618
+ @originator_id = originator_id
619
+ return 1
620
+ end
621
+
622
+
623
+ # Gets the originator_id for the given server context on which the
624
+ # ONTAP API commands get invoked.
625
+
626
+ def get_originator_id()
627
+ return @originator_id
628
+ end
629
+
630
+ #Sets the connection timeout value, in seconds,for the given server context.
631
+
632
+ def set_timeout(timeout)
633
+ @timeout = timeout
634
+ end
635
+
636
+
637
+ #Retrieves the connection timeout value (in seconds) for the given server context.
638
+
639
+ def get_timeout()
640
+ return @timeout
641
+ end
642
+
643
+
644
+ # Enables or disables server certificate verification by the client.
645
+ # Server certificate verification is enabled by default when style
646
+ # is set to CERTIFICATE. Hostname (CN) verification is always enabled
647
+ # during server certificate verification.
648
+
649
+ def set_server_cert_verification(enable)
650
+ unless(enable.eql?(true) or enable.eql?(false))
651
+ return fail_response(13001, "NaServer::set_server_cert_verification: invalid argument " + enable + "specified");
652
+ end
653
+ unless (use_https())
654
+ return fail_response(13001, "NaServer::set_server_cert_verification: server certificate verification can only be enabled or disabled for HTTPS transport")
655
+ end
656
+ @enable_server_cert_verification = enable
657
+ @enable_hostname_verification = enable
658
+ return nil
659
+ end
660
+
661
+
662
+ # Determines whether server certificate verification is enabled or not.
663
+ # Returns true if it is enabled, else returns false.
664
+
665
+
666
+ def is_server_cert_verification_enabled()
667
+ return @enable_server_cert_verification
668
+ end
669
+
670
+
671
+ # Sets the client certificate and key files that are required for client authentication
672
+ # by the server using certificates. If key file is not defined, then the certificate file
673
+ # will be used as the key file.
674
+
675
+
676
+ def set_client_cert_and_key (cert_file, key_file = nil, key_passwd = nil)
677
+ unless(cert_file)
678
+ return fail_response(13001, "NaServer::set_client_cert_and_key: certificate file not specified")
679
+ end
680
+ @cert_file = cert_file
681
+ @key_file = key_file
682
+ if(key_passwd == nil)
683
+ @key_passwd = ""
684
+ else
685
+ @key_passwd = key_passwd
686
+ end
687
+
688
+ return nil
689
+ end
690
+
691
+
692
+ # Specifies the certificates of the Certificate Authorities (CAs) that are
693
+ # trusted by this application and that will be used to verify the server certificate.
694
+
695
+
696
+ def set_ca_certs (ca_file)
697
+ if(ca_file == nil)
698
+ return fail_response(13001, "NaServer::set_ca_certs: missing CA certificate file")
699
+ end
700
+ @ca_file = ca_file
701
+
702
+ return nil
703
+ end
704
+
705
+
706
+ # Enables or disables hostname verification by the client during server certificate the
707
+ # server certificate.
708
+
709
+
710
+ def set_hostname_verification (enable)
711
+ unless(enable.eql?(true) or enable.eql?(false))
712
+ return fail_response(13001, "NaServer::set_hostname_verification: invalid argument " + enable + "specified");
713
+ end
714
+ unless (@enable_server_cert_verification)
715
+ return fail_response(13001, "NaServer::set_hostname_verification: server certificate verification is not enabled")
716
+ end
717
+ @enable_hostname_verification = enable
718
+ return nil
719
+ end
720
+
721
+
722
+ # Determines whether hostname verification is enabled or not.
723
+ # Returns true if it is enabled, else returns false
724
+
725
+
726
+ def is_hostname_verification_enabled ()
727
+ return @enable_hostname_verification
728
+ end
729
+
730
+
731
+
732
+
733
+
734
+
735
+ # "private" subroutines for use by the public routines
736
+ # This is a private function, not to be called from outside NaServer
737
+ # This is used when the transmission path fails, and we don't actually
738
+ # get back any XML from the server.
739
+
740
+ def fail_response(errno, reason)
741
+ n = NaElement.new("results")
742
+ n.attr_set("status", "failed")
743
+ n.attr_set("reason", reason)
744
+ n.attr_set("errno", errno)
745
+ return n
746
+ end
747
+ end
748
+
749
+
750
+ class MyListener
751
+
752
+ def tag_start(element, attributes)
753
+ n = NaElement.new(element)
754
+ $tag_element_stack.push(element)
755
+ $ZAPI_stack.push(n)
756
+ attributes.each { |key, value| $ZAPI_atts[key] = value ; n.attr_set(key, value) }
757
+ end
758
+
759
+ def tag_end(element)
760
+ stack_len = $ZAPI_stack.length
761
+ if($tag_element_stack.length <= 0)
762
+ print("\nError : Missing start tag for " + element + "\n")
763
+ exit
764
+ end
765
+ tag_element = $tag_element_stack.pop()
766
+ if(not tag_element.eql?(element))
767
+ print("\nError : Missing start tag for " + element + "\n")
768
+ exit
769
+ end
770
+ if(stack_len > 1)
771
+ n = $ZAPI_stack.pop()
772
+ i = $ZAPI_stack.length
773
+ if(i != stack_len - 1)
774
+ print("pop did not work!!!!\n")
775
+ end
776
+ $ZAPI_stack[i-1].child_add(n)
777
+ end
778
+ end
779
+
780
+ def text(text)
781
+ text = text.chomp
782
+ i = $ZAPI_stack.length
783
+ if(text.length > 0 and i > 0)
784
+ text = NaElement.escapeHTML(text)
785
+ $ZAPI_stack[i-1].add_content(text)
786
+ end
787
+ end
788
+ end
789
+