rubyntlm 0.3.4 → 0.4.0

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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +3 -0
  3. data/.travis.yml +0 -1
  4. data/LICENSE +20 -0
  5. data/Rakefile +8 -15
  6. data/lib/net/ntlm.rb +22 -654
  7. data/lib/net/ntlm/blob.rb +17 -0
  8. data/lib/net/ntlm/encode_util.rb +49 -0
  9. data/lib/net/ntlm/field.rb +35 -0
  10. data/lib/net/ntlm/field_set.rb +125 -0
  11. data/lib/net/ntlm/int16_le.rb +26 -0
  12. data/lib/net/ntlm/int32_le.rb +25 -0
  13. data/lib/net/ntlm/int64_le.rb +26 -0
  14. data/lib/net/ntlm/message.rb +115 -0
  15. data/lib/net/ntlm/message/type0.rb +16 -0
  16. data/lib/net/ntlm/message/type1.rb +43 -0
  17. data/lib/net/ntlm/message/type2.rb +126 -0
  18. data/lib/net/ntlm/message/type3.rb +68 -0
  19. data/lib/net/ntlm/security_buffer.rb +48 -0
  20. data/lib/net/ntlm/string.rb +35 -0
  21. data/lib/net/ntlm/version.rb +11 -0
  22. data/rubyntlm.gemspec +4 -1
  23. data/spec/lib/net/ntlm/blob_spec.rb +16 -0
  24. data/spec/lib/net/ntlm/encode_util_spec.rb +16 -0
  25. data/spec/lib/net/ntlm/field_set_spec.rb +33 -0
  26. data/spec/lib/net/ntlm/field_spec.rb +34 -0
  27. data/spec/lib/net/ntlm/int16_le_spec.rb +18 -0
  28. data/spec/lib/net/ntlm/int32_le_spec.rb +19 -0
  29. data/spec/lib/net/ntlm/int64_le_spec.rb +19 -0
  30. data/spec/lib/net/ntlm/message/type0_spec.rb +21 -0
  31. data/spec/lib/net/ntlm/message/type1_spec.rb +42 -0
  32. data/spec/lib/net/ntlm/message/type2_spec.rb +88 -0
  33. data/spec/lib/net/ntlm/message/type3_spec.rb +20 -0
  34. data/spec/lib/net/ntlm/message_spec.rb +17 -0
  35. data/spec/lib/net/ntlm/security_buffer_spec.rb +64 -0
  36. data/spec/lib/net/ntlm/string_spec.rb +72 -0
  37. data/spec/lib/net/ntlm/version_spec.rb +26 -0
  38. data/spec/lib/net/ntlm_spec.rb +121 -0
  39. data/spec/spec_helper.rb +21 -0
  40. data/spec/support/shared/examples/net/ntlm/field_shared.rb +25 -0
  41. data/spec/support/shared/examples/net/ntlm/fieldset_shared.rb +239 -0
  42. data/spec/support/shared/examples/net/ntlm/int_shared.rb +43 -0
  43. data/spec/support/shared/examples/net/ntlm/message_shared.rb +35 -0
  44. metadata +77 -5
  45. data/spec/unit/ntlm_spec.rb +0 -183
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f67034afa794d7dba21acc1fc3c6e648903e4759
4
- data.tar.gz: c126a8798dec751e72d7c0d387be9827834fe9c7
3
+ metadata.gz: 92fe9fbd41088f3bb6dd585c16c9b105a91820bc
4
+ data.tar.gz: 7cb29dfd82e71ff8075f143889da01ca406d41d1
5
5
  SHA512:
6
- metadata.gz: eaeb50694bf7176cb6b0122ce51229c170856b55ef0f4553c291e182af3a35e220fba1ba9928f642247350457968b9ed910f8a9e526802582def8e4df07bbff8
7
- data.tar.gz: cbf7a9fcc4de87f5126d7af461451fd357af08d1874946e0794c28f41d5f41fa0e9ddfbd28a603824fb7e35646df3fe80cdf71a16ee953cd6bf079a69404c700
6
+ metadata.gz: 6fd7a286d8a55f4ff6aeb7b0bc24d8dd1c37b4daaaa73e6f1ac747de520690085ea026eeec4e3d0c7b1c3225189c5b8591de0361c5e12b32ff54a30ec9da569a
7
+ data.tar.gz: d4ab713acacb9e2450d66e8bcdb814a9cdadabcd65b29b6743889434cfec3e77aa30ef475ec4871c34b5b2de81488503433b716c316954a30e1b8df2da69cc75
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format nested
2
+ --colour
3
+ --drb
@@ -6,6 +6,5 @@ rvm:
6
6
  - 2.0.0
7
7
  - rbx-19mode
8
8
  - rbx-18mode
9
- - ruby-head
10
9
  - jruby-19mode
11
10
 
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2013 Paul Morton, Matt Zukowski, Kohei Kajimoto
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile CHANGED
@@ -1,21 +1,14 @@
1
1
  require "bundler/gem_tasks"
2
2
 
3
- task :default => [:spec]
4
-
5
3
 
6
4
  require 'rspec/core/rake_task'
7
-
8
- desc 'Default: run specs.'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
9
7
  task :default => :spec
10
-
11
- desc "Run specs unit tests"
12
- RSpec::Core::RakeTask.new do |t|
13
- t.pattern = "./spec/unit/*_spec.rb"
14
- end
15
-
8
+
16
9
  desc "Generate code coverage"
17
- RSpec::Core::RakeTask.new(:coverage) do |t|
18
- t.pattern = "./spec/unit/*_spec.rb" # don't need this, it's default.
19
- t.rcov = true
20
- t.rcov_opts = ['--exclude', 'spec']
21
- end
10
+ task :coverage do
11
+ ENV['COVERAGE'] = 'true'
12
+ Rake::Task["spec"].execute
13
+ end
14
+
@@ -10,9 +10,6 @@
10
10
  # -------------------------------------------------------------
11
11
  # Copyright (c) 2005,2006 yrock
12
12
  #
13
- # This program is free software.
14
- # You can distribute/modify this program under the terms of the
15
- # Ruby License.
16
13
  #
17
14
  # 2006-02-11 refactored by Minero Aoki
18
15
  # -------------------------------------------------------------
@@ -25,10 +22,6 @@
25
22
  # -------------------------------------------------------------
26
23
  # Copyright (c) 2003 Eric Glass
27
24
  #
28
- # Permission to use, copy, modify, and distribute this document
29
- # for any purpose and without any fee is hereby granted,
30
- # provided that the above copyright notice and this list of
31
- # conditions appear in all copies.
32
25
  # -------------------------------------------------------------
33
26
  #
34
27
  # The author also looked Mozilla-Firefox-1.0.7 source code,
@@ -48,95 +41,35 @@ require 'openssl'
48
41
  require 'openssl/digest'
49
42
  require 'socket'
50
43
 
44
+ # Load Order is important here
45
+ require 'net/ntlm/field'
46
+ require 'net/ntlm/int16_le'
47
+ require 'net/ntlm/int32_le'
48
+ require 'net/ntlm/int64_le'
49
+ require 'net/ntlm/string'
50
+
51
+ require 'net/ntlm/field_set'
52
+ require 'net/ntlm/blob'
53
+ require 'net/ntlm/security_buffer'
54
+ require 'net/ntlm/message'
55
+ require 'net/ntlm/message/type0'
56
+ require 'net/ntlm/message/type1'
57
+ require 'net/ntlm/message/type2'
58
+ require 'net/ntlm/message/type3'
59
+
60
+
61
+ require 'net/ntlm/encode_util'
62
+
63
+
64
+
65
+
51
66
  module Net
52
67
  module NTLM
53
- # @private
54
- module VERSION
55
- MAJOR = 0
56
- MINOR = 3
57
- TINY = 4
58
- STRING = [MAJOR, MINOR, TINY].join('.')
59
- end
60
68
 
61
- SSP_SIGN = "NTLMSSP\0"
62
- BLOB_SIGN = 0x00000101
63
69
  LM_MAGIC = "KGS!@\#$%"
64
70
  TIME_OFFSET = 11644473600
65
71
  MAX64 = 0xffffffffffffffff
66
72
 
67
- FLAGS = {
68
- :UNICODE => 0x00000001,
69
- :OEM => 0x00000002,
70
- :REQUEST_TARGET => 0x00000004,
71
- :MBZ9 => 0x00000008,
72
- :SIGN => 0x00000010,
73
- :SEAL => 0x00000020,
74
- :NEG_DATAGRAM => 0x00000040,
75
- :NETWARE => 0x00000100,
76
- :NTLM => 0x00000200,
77
- :NEG_NT_ONLY => 0x00000400,
78
- :MBZ7 => 0x00000800,
79
- :DOMAIN_SUPPLIED => 0x00001000,
80
- :WORKSTATION_SUPPLIED => 0x00002000,
81
- :LOCAL_CALL => 0x00004000,
82
- :ALWAYS_SIGN => 0x00008000,
83
- :TARGET_TYPE_DOMAIN => 0x00010000,
84
- :TARGET_INFO => 0x00800000,
85
- :NTLM2_KEY => 0x00080000,
86
- :KEY128 => 0x20000000,
87
- :KEY56 => 0x80000000
88
- }.freeze
89
-
90
- FLAG_KEYS = FLAGS.keys.sort{|a, b| FLAGS[a] <=> FLAGS[b] }
91
-
92
- DEFAULT_FLAGS = {
93
- :TYPE1 => FLAGS[:UNICODE] | FLAGS[:OEM] | FLAGS[:REQUEST_TARGET] | FLAGS[:NTLM] | FLAGS[:ALWAYS_SIGN] | FLAGS[:NTLM2_KEY],
94
- :TYPE2 => FLAGS[:UNICODE],
95
- :TYPE3 => FLAGS[:UNICODE] | FLAGS[:REQUEST_TARGET] | FLAGS[:NTLM] | FLAGS[:ALWAYS_SIGN] | FLAGS[:NTLM2_KEY]
96
- }
97
-
98
- class EncodeUtil
99
- if RUBY_VERSION == "1.8.7"
100
- require "kconv"
101
-
102
- # Decode a UTF16 string to a ASCII string
103
- # @param [String] str The string to convert
104
- def self.decode_utf16le(str)
105
- Kconv.kconv(swap16(str), Kconv::ASCII, Kconv::UTF16)
106
- end
107
-
108
- # Encodes a ASCII string to a UTF16 string
109
- # @param [String] str The string to convert
110
- def self.encode_utf16le(str)
111
- swap16(Kconv.kconv(str, Kconv::UTF16, Kconv::ASCII))
112
- end
113
-
114
- # Taggle the strings endianness between big/little and little/big
115
- # @param [String] str The string to swap the endianness on
116
- def self.swap16(str)
117
- str.unpack("v*").pack("n*")
118
- end
119
- else # Use native 1.9 string encoding functions
120
-
121
- # Decode a UTF16 string to a ASCII string
122
- # @param [String] str The string to convert
123
- def self.decode_utf16le(str)
124
- str.encode(Encoding::UTF_8, Encoding::UTF_16LE).force_encoding('UTF-8')
125
- end
126
-
127
- # Encodes a ASCII string to a UTF16 string
128
- # @param [String] str The string to convert
129
- # @note This implementation may seem stupid but the problem is that UTF16-LE and UTF-8 are incompatiable
130
- # encodings. This library uses string contatination to build the packet bytes. The end result is that
131
- # you can either marshal the encodings elsewhere of simply know that each time you call encode_utf16le
132
- # the function will convert the string bytes to UTF-16LE and note the encoding as UTF-8 so that byte
133
- # concatination works seamlessly.
134
- def self.encode_utf16le(str)
135
- str = str.force_encoding('UTF-8') if [::Encoding::ASCII_8BIT,::Encoding::US_ASCII].include?(str.encoding)
136
- str.dup.force_encoding('UTF-8').encode(Encoding::UTF_16LE, Encoding::UTF_8).force_encoding('UTF-8')
137
- end
138
- end
139
- end
140
73
 
141
74
  class << self
142
75
 
@@ -300,570 +233,5 @@ module Net
300
233
  end
301
234
  end
302
235
 
303
-
304
- # base classes for primitives
305
- # @private
306
- class Field
307
- attr_accessor :active, :value
308
-
309
- def initialize(opts)
310
- @value = opts[:value]
311
- @active = opts[:active].nil? ? true : opts[:active]
312
- end
313
-
314
- def size
315
- @active ? @size : 0
316
- end
317
- end
318
-
319
- class String < Field
320
- def initialize(opts)
321
- super(opts)
322
- @size = opts[:size]
323
- end
324
-
325
- def parse(str, offset=0)
326
- if @active and str.size >= offset + @size
327
- @value = str[offset, @size]
328
- @size
329
- else
330
- 0
331
- end
332
- end
333
-
334
- def serialize
335
- if @active
336
- @value
337
- else
338
- ""
339
- end
340
- end
341
-
342
- def value=(val)
343
- @value = val
344
- @size = @value.nil? ? 0 : @value.size
345
- @active = (@size > 0)
346
- end
347
- end
348
-
349
- class Int16LE < Field
350
- def initialize(opt)
351
- super(opt)
352
- @size = 2
353
- end
354
- def parse(str, offset=0)
355
- if @active and str.size >= offset + @size
356
- @value = str[offset, @size].unpack("v")[0]
357
- @size
358
- else
359
- 0
360
- end
361
- end
362
-
363
- def serialize
364
- [@value].pack("v")
365
- end
366
- end
367
-
368
- class Int32LE < Field
369
- def initialize(opt)
370
- super(opt)
371
- @size = 4
372
- end
373
-
374
- def parse(str, offset=0)
375
- if @active and str.size >= offset + @size
376
- @value = str.slice(offset, @size).unpack("V")[0]
377
- @size
378
- else
379
- 0
380
- end
381
- end
382
-
383
- def serialize
384
- [@value].pack("V") if @active
385
- end
386
- end
387
-
388
- class Int64LE < Field
389
- def initialize(opt)
390
- super(opt)
391
- @size = 8
392
- end
393
-
394
- def parse(str, offset=0)
395
- if @active and str.size >= offset + @size
396
- d, u = str.slice(offset, @size).unpack("V2")
397
- @value = (u * 0x100000000 + d)
398
- @size
399
- else
400
- 0
401
- end
402
- end
403
-
404
- def serialize
405
- [@value & 0x00000000ffffffff, @value >> 32].pack("V2") if @active
406
- end
407
- end
408
-
409
- # base class of data structure
410
- class FieldSet
411
- class << FieldSet
412
-
413
-
414
- # @macro string_security_buffer
415
- # @method $1
416
- # @method $1=
417
- # @return [String]
418
- def string(name, opts)
419
- add_field(name, String, opts)
420
- end
421
-
422
- # @macro int16le_security_buffer
423
- # @method $1
424
- # @method $1=
425
- # @return [Int16LE]
426
- def int16LE(name, opts)
427
- add_field(name, Int16LE, opts)
428
- end
429
-
430
- # @macro int32le_security_buffer
431
- # @method $1
432
- # @method $1=
433
- # @return [Int32LE]
434
- def int32LE(name, opts)
435
- add_field(name, Int32LE, opts)
436
- end
437
-
438
- # @macro int64le_security_buffer
439
- # @method $1
440
- # @method $1=
441
- # @return [Int64]
442
- def int64LE(name, opts)
443
- add_field(name, Int64LE, opts)
444
- end
445
-
446
- # @macro security_buffer
447
- # @method $1
448
- # @method $1=
449
- # @return [SecurityBuffer]
450
- def security_buffer(name, opts)
451
- add_field(name, SecurityBuffer, opts)
452
- end
453
-
454
- def prototypes
455
- @proto
456
- end
457
-
458
- def names
459
- @proto.map{|n, t, o| n}
460
- end
461
-
462
- def types
463
- @proto.map{|n, t, o| t}
464
- end
465
-
466
- def opts
467
- @proto.map{|n, t, o| o}
468
- end
469
-
470
- private
471
-
472
- def add_field(name, type, opts)
473
- (@proto ||= []).push [name, type, opts]
474
- define_accessor name
475
- end
476
-
477
- def define_accessor(name)
478
- module_eval(<<-End, __FILE__, __LINE__ + 1)
479
- def #{name}
480
- self['#{name}'].value
481
- end
482
-
483
- def #{name}=(val)
484
- self['#{name}'].value = val
485
- end
486
- End
487
- end
488
- end
489
-
490
- def initialize
491
- @alist = self.class.prototypes.map{ |n, t, o| [n, t.new(o)] }
492
- end
493
-
494
- def serialize
495
- @alist.map{|n, f| f.serialize }.join
496
- end
497
-
498
- def parse(str, offset=0)
499
- @alist.inject(offset){|cur, a| cur += a[1].parse(str, cur)}
500
- end
501
-
502
- def size
503
- @alist.inject(0){|sum, a| sum += a[1].size}
504
- end
505
-
506
- def [](name)
507
- a = @alist.assoc(name.to_s.intern)
508
- raise ArgumentError, "no such field: #{name}" unless a
509
- a[1]
510
- end
511
-
512
- def []=(name, val)
513
- a = @alist.assoc(name.to_s.intern)
514
- raise ArgumentError, "no such field: #{name}" unless a
515
- a[1] = val
516
- end
517
-
518
- def enable(name)
519
- self[name].active = true
520
- end
521
-
522
- def disable(name)
523
- self[name].active = false
524
- end
525
- end
526
-
527
- class Blob < FieldSet
528
- int32LE :blob_signature, {:value => BLOB_SIGN}
529
- int32LE :reserved, {:value => 0}
530
- int64LE :timestamp, {:value => 0}
531
- string :challenge, {:value => "", :size => 8}
532
- int32LE :unknown1, {:value => 0}
533
- string :target_info, {:value => "", :size => 0}
534
- int32LE :unknown2, {:value => 0}
535
- end
536
-
537
- class SecurityBuffer < FieldSet
538
-
539
- int16LE :length, {:value => 0}
540
- int16LE :allocated, {:value => 0}
541
- int32LE :offset, {:value => 0}
542
-
543
- attr_accessor :active
544
- def initialize(opts)
545
- super()
546
- @value = opts[:value]
547
- @active = opts[:active].nil? ? true : opts[:active]
548
- @size = 8
549
- end
550
-
551
- def parse(str, offset=0)
552
- if @active and str.size >= offset + @size
553
- super(str, offset)
554
- @value = str[self.offset, self.length]
555
- @size
556
- else
557
- 0
558
- end
559
- end
560
-
561
- def serialize
562
- super if @active
563
- end
564
-
565
- def value
566
- @value
567
- end
568
-
569
- def value=(val)
570
- @value = val
571
- self.length = self.allocated = val.size
572
- end
573
-
574
- def data_size
575
- @active ? @value.size : 0
576
- end
577
- end
578
-
579
- # @private false
580
- class Message < FieldSet
581
- class << Message
582
- def parse(str)
583
- m = Type0.new
584
- m.parse(str)
585
- case m.type
586
- when 1
587
- t = Type1.parse(str)
588
- when 2
589
- t = Type2.parse(str)
590
- when 3
591
- t = Type3.parse(str)
592
- else
593
- raise ArgumentError, "unknown type: #{m.type}"
594
- end
595
- t
596
- end
597
-
598
- def decode64(str)
599
- parse(Base64.decode64(str))
600
- end
601
- end
602
-
603
- def has_flag?(flag)
604
- (self[:flag].value & FLAGS[flag]) == FLAGS[flag]
605
- end
606
-
607
- def set_flag(flag)
608
- self[:flag].value |= FLAGS[flag]
609
- end
610
-
611
- def dump_flags
612
- FLAG_KEYS.each{ |k| print(k, "=", flag?(k), "\n") }
613
- end
614
-
615
- def serialize
616
- deflag
617
- super + security_buffers.map{|n, f| f.value}.join
618
- end
619
-
620
- def encode64
621
- Base64.encode64(serialize).gsub(/\n/, '')
622
- end
623
-
624
- def decode64(str)
625
- parse(Base64.decode64(str))
626
- end
627
-
628
- alias head_size size
629
-
630
- def data_size
631
- security_buffers.inject(0){|sum, a| sum += a[1].data_size}
632
- end
633
-
634
- def size
635
- head_size + data_size
636
- end
637
-
638
-
639
- def security_buffers
640
- @alist.find_all{|n, f| f.instance_of?(SecurityBuffer)}
641
- end
642
-
643
- def deflag
644
- security_buffers.inject(head_size){|cur, a|
645
- a[1].offset = cur
646
- cur += a[1].data_size
647
- }
648
- end
649
-
650
- def data_edge
651
- security_buffers.map{ |n, f| f.active ? f.offset : size}.min
652
- end
653
-
654
- # sub class definitions
655
- class Type0 < Message
656
- string :sign, {:size => 8, :value => SSP_SIGN}
657
- int32LE :type, {:value => 0}
658
- end
659
-
660
- # @private false
661
- class Type1 < Message
662
-
663
- string :sign, {:size => 8, :value => SSP_SIGN}
664
- int32LE :type, {:value => 1}
665
- int32LE :flag, {:value => DEFAULT_FLAGS[:TYPE1] }
666
- security_buffer :domain, {:value => ""}
667
- security_buffer :workstation, {:value => Socket.gethostname }
668
- string :padding, {:size => 0, :value => "", :active => false }
669
-
670
- class << Type1
671
- # Parses a Type 1 Message
672
- # @param [String] str A string containing Type 1 data
673
- # @return [Type1] The parsed Type 1 message
674
- def parse(str)
675
- t = new
676
- t.parse(str)
677
- t
678
- end
679
- end
680
-
681
- # @!visibility private
682
- def parse(str)
683
- super(str)
684
- enable(:domain) if has_flag?(:DOMAIN_SUPPLIED)
685
- enable(:workstation) if has_flag?(:WORKSTATION_SUPPLIED)
686
- super(str)
687
- if ( (len = data_edge - head_size) > 0)
688
- self.padding = "\0" * len
689
- super(str)
690
- end
691
- end
692
- end
693
-
694
-
695
- # @private false
696
- class Type2 < Message
697
-
698
- string :sign, {:size => 8, :value => SSP_SIGN}
699
- int32LE :type, {:value => 2}
700
- security_buffer :target_name, {:size => 0, :value => ""}
701
- int32LE :flag, {:value => DEFAULT_FLAGS[:TYPE2]}
702
- int64LE :challenge, {:value => 0}
703
- int64LE :context, {:value => 0, :active => false}
704
- security_buffer :target_info, {:value => "", :active => false}
705
- string :padding, {:size => 0, :value => "", :active => false }
706
-
707
- class << Type2
708
- # Parse a Type 2 packet
709
- # @param [String] str A string containing Type 2 data
710
- # @return [Type2]
711
- def parse(str)
712
- t = new
713
- t.parse(str)
714
- t
715
- end
716
- end
717
-
718
- # @!visibility private
719
- def parse(str)
720
- super(str)
721
- if has_flag?(:TARGET_INFO)
722
- enable(:context)
723
- enable(:target_info)
724
- super(str)
725
- end
726
- if ( (len = data_edge - head_size) > 0)
727
- self.padding = "\0" * len
728
- super(str)
729
- end
730
- end
731
-
732
- # Generates a Type 3 response based on the Type 2 Information
733
- # @return [Type3]
734
- # @option arg [String] :username The username to authenticate with
735
- # @option arg [String] :password The user's password
736
- # @option arg [String] :domain ('') The domain to authenticate to
737
- # @option opt [String] :workstation (Socket.gethostname) The name of the calling workstation
738
- # @option opt [Boolean] :use_default_target (False) Use the domain supplied by the server in the Type 2 packet
739
- # @note An empty :domain option authenticates to the local machine.
740
- # @note The :use_default_target has presidence over the :domain option
741
- def response(arg, opt = {})
742
- usr = arg[:user]
743
- pwd = arg[:password]
744
- domain = arg[:domain] ? arg[:domain] : ""
745
- if usr.nil? or pwd.nil?
746
- raise ArgumentError, "user and password have to be supplied"
747
- end
748
-
749
- if opt[:workstation]
750
- ws = opt[:workstation]
751
- else
752
- ws = Socket.gethostname
753
- end
754
-
755
- if opt[:client_challenge]
756
- cc = opt[:client_challenge]
757
- else
758
- cc = rand(MAX64)
759
- end
760
- cc = NTLM::pack_int64le(cc) if cc.is_a?(Integer)
761
- opt[:client_challenge] = cc
762
-
763
- if has_flag?(:OEM) and opt[:unicode]
764
- usr = NTLM::EncodeUtil.decode_utf16le(usr)
765
- pwd = NTLM::EncodeUtil.decode_utf16le(pwd)
766
- ws = NTLM::EncodeUtil.decode_utf16le(ws)
767
- domain = NTLM::EncodeUtil.decode_utf16le(domain)
768
- opt[:unicode] = false
769
- end
770
-
771
- if has_flag?(:UNICODE) and !opt[:unicode]
772
- usr = NTLM::EncodeUtil.encode_utf16le(usr)
773
- pwd = NTLM::EncodeUtil.encode_utf16le(pwd)
774
- ws = NTLM::EncodeUtil.encode_utf16le(ws)
775
- domain = NTLM::EncodeUtil.encode_utf16le(domain)
776
- opt[:unicode] = true
777
- end
778
-
779
- if opt[:use_default_target]
780
- domain = self.target_name
781
- end
782
-
783
- ti = self.target_info
784
-
785
- chal = self[:challenge].serialize
786
-
787
- if opt[:ntlmv2]
788
- ar = {:ntlmv2_hash => NTLM::ntlmv2_hash(usr, pwd, domain, opt), :challenge => chal, :target_info => ti}
789
- lm_res = NTLM::lmv2_response(ar, opt)
790
- ntlm_res = NTLM::ntlmv2_response(ar, opt)
791
- elsif has_flag?(:NTLM2_KEY)
792
- ar = {:ntlm_hash => NTLM::ntlm_hash(pwd, opt), :challenge => chal}
793
- lm_res, ntlm_res = NTLM::ntlm2_session(ar, opt)
794
- else
795
- lm_res = NTLM::lm_response(pwd, chal)
796
- ntlm_res = NTLM::ntlm_response(pwd, chal)
797
- end
798
-
799
- Type3.create({
800
- :lm_response => lm_res,
801
- :ntlm_response => ntlm_res,
802
- :domain => domain,
803
- :user => usr,
804
- :workstation => ws,
805
- :flag => self.flag
806
- })
807
- end
808
- end
809
-
810
- # @private false
811
- class Type3 < Message
812
-
813
- string :sign, {:size => 8, :value => SSP_SIGN}
814
- int32LE :type, {:value => 3}
815
- security_buffer :lm_response, {:value => ""}
816
- security_buffer :ntlm_response, {:value => ""}
817
- security_buffer :domain, {:value => ""}
818
- security_buffer :user, {:value => ""}
819
- security_buffer :workstation, {:value => ""}
820
- security_buffer :session_key, {:value => "", :active => false }
821
- int64LE :flag, {:value => 0, :active => false }
822
-
823
- class << Type3
824
- # Parse a Type 3 packet
825
- # @param [String] str A string containing Type 3 data
826
- # @return [Type2]
827
- def parse(str)
828
- t = new
829
- t.parse(str)
830
- t
831
- end
832
-
833
- # Builds a Type 3 packet
834
- # @note All options must be properly encoded with either unicode or oem encoding
835
- # @return [Type3]
836
- # @option arg [String] :lm_response The LM hash
837
- # @option arg [String] :ntlm_response The NTLM hash
838
- # @option arg [String] :domain The domain to authenticate to
839
- # @option arg [String] :workstation The name of the calling workstation
840
- # @option arg [String] :session_key The session key
841
- # @option arg [Integer] :flag Flags for the packet
842
- def create(arg, opt ={})
843
- t = new
844
- t.lm_response = arg[:lm_response]
845
- t.ntlm_response = arg[:ntlm_response]
846
- t.domain = arg[:domain]
847
- t.user = arg[:user]
848
-
849
- if arg[:workstation]
850
- t.workstation = arg[:workstation]
851
- end
852
-
853
- if arg[:session_key]
854
- t.enable(:session_key)
855
- t.session_key = arg[session_key]
856
- end
857
-
858
- if arg[:flag]
859
- t.enable(:session_key)
860
- t.enable(:flag)
861
- t.flag = arg[:flag]
862
- end
863
- t
864
- end
865
- end
866
- end
867
- end
868
236
  end
869
237
  end