rubyntlm 0.3.4 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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