sys-admin 1.8.1 → 1.8.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,7 +4,9 @@ require 'win32/security'
4
4
  require 'win32/registry'
5
5
  require 'socket'
6
6
 
7
+ # The Sys module serves as a namespace only.
7
8
  module Sys
9
+ # The Admin class provides a unified, cross platform replacement for the Etc module.
8
10
  class Admin
9
11
  extend FFI::Library
10
12
 
@@ -13,6 +15,7 @@ module Sys
13
15
  #
14
16
  class Error < StandardError; end
15
17
 
18
+ # rubocop:disable Naming/ConstantName
16
19
  SidTypeUser = 1
17
20
  SidTypeGroup = 2
18
21
  SidTypeDomain = 3
@@ -22,8 +25,9 @@ module Sys
22
25
  SidTypeInvalid = 7
23
26
  SidTypeUnknown = 8
24
27
  SidTypeComputer = 9
28
+ # rubocop:enable Naming/ConstantName
25
29
 
26
- HKEY = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\"
30
+ HKEY = 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\'.freeze
27
31
  private_constant :HKEY
28
32
 
29
33
  # Retrieves the user's home directory. For local accounts query the
@@ -59,10 +63,10 @@ module Sys
59
63
  def self.munge_options(opts)
60
64
  rhash = {}
61
65
 
62
- opts.each{ |k, v|
66
+ opts.each do |k, v|
63
67
  k = k.to_s.downcase.to_sym
64
68
  rhash[k] = v
65
- }
69
+ end
66
70
 
67
71
  rhash
68
72
  end
@@ -96,7 +100,7 @@ module Sys
96
100
 
97
101
  # Used by the get_login method
98
102
  ffi_lib :advapi32
99
- attach_function :GetUserNameW, [:pointer, :pointer], :bool
103
+ attach_function :GetUserNameW, %i[pointer pointer], :bool
100
104
  private_class_method :GetUserNameW
101
105
 
102
106
  # Creates the given +user+. If no domain option is specified,
@@ -146,13 +150,13 @@ module Sys
146
150
  adsi = WIN32OLE.connect(moniker)
147
151
  user = adsi.create('user', name)
148
152
 
149
- options.each{ |option, value|
153
+ options.each do |option, value|
150
154
  if option.to_s == 'password'
151
155
  user.setpassword(value)
152
156
  else
153
157
  user.put(option.to_s, value)
154
158
  end
155
- }
159
+ end
156
160
 
157
161
  user.setinfo
158
162
  rescue WIN32OLERuntimeError => err
@@ -199,13 +203,13 @@ module Sys
199
203
  begin
200
204
  adsi = WIN32OLE.connect("WinNT://#{domain}/#{name},user")
201
205
 
202
- options.each{ |option, value|
206
+ options.each do |option, value|
203
207
  if option.to_s == 'password'
204
208
  adsi.setpassword(value)
205
209
  else
206
210
  adsi.put(option.to_s, value)
207
211
  end
208
- }
212
+ end
209
213
 
210
214
  adsi.setinfo
211
215
  rescue WIN32OLERuntimeError => err
@@ -277,7 +281,7 @@ module Sys
277
281
  # Adds +user+ to +group+ on the specified +domain+, or the localhost
278
282
  # if no domain is specified.
279
283
  #
280
- def self.add_group_member(user, group, domain=nil)
284
+ def self.add_group_member(user, group, domain = nil)
281
285
  domain ||= Socket.gethostname
282
286
  adsi = WIN32OLE.connect("WinNT://#{domain}/#{group},group")
283
287
  adsi.Add("WinNT://#{domain}/#{user}")
@@ -288,7 +292,7 @@ module Sys
288
292
  # Removes +user+ from +group+ on the specified +domain+, or the localhost
289
293
  # if no domain is specified.
290
294
  #
291
- def self.remove_group_member(user, group, domain=nil)
295
+ def self.remove_group_member(user, group, domain = nil)
292
296
  domain ||= Socket.gethostname
293
297
  adsi = WIN32OLE.connect("WinNT://#{domain}/#{group},group")
294
298
  adsi.Remove("WinNT://#{domain}/#{user}")
@@ -397,7 +401,7 @@ module Sys
397
401
  options = munge_options(options)
398
402
 
399
403
  host = options.delete(:host) || Socket.gethostname
400
- cs = "winmgmts:{impersonationLevel=impersonate}!"
404
+ cs = 'winmgmts:{impersonationLevel=impersonate}!'
401
405
  cs << "//#{host}/root/cimv2"
402
406
 
403
407
  begin
@@ -406,20 +410,20 @@ module Sys
406
410
  raise Error, err
407
411
  end
408
412
 
409
- query = "select * from win32_useraccount"
413
+ query = 'select * from win32_useraccount'
410
414
 
411
415
  i = 0
412
416
 
413
- options.each{ |opt, val|
417
+ options.each do |opt, val|
414
418
  if i == 0
415
419
  query << " where #{opt} = '#{val}'"
416
420
  i += 1
417
421
  else
418
422
  query << " and #{opt} = '#{val}'"
419
423
  end
420
- }
424
+ end
421
425
 
422
- if usr.kind_of?(Numeric)
426
+ if usr.is_a?(Numeric)
423
427
  if i == 0
424
428
  query << " where sid like '%-#{usr}'"
425
429
  else
@@ -435,14 +439,12 @@ module Sys
435
439
 
436
440
  domain = options[:domain] || host
437
441
 
438
- wmi.execquery(query).each{ |user|
442
+ # rubocop:disable Metrics/BlockLength
443
+ wmi.execquery(query).each do |user|
439
444
  uid = user.sid.split('-').last.to_i
440
445
 
441
- # Because our 'like' query isn't fulproof, let's parse
442
- # the SID again to make sure
443
- if usr.kind_of?(Numeric)
444
- next if usr != uid
445
- end
446
+ # Because our 'like' query isn't fulproof, let's parse the SID again to make sure
447
+ next if usr.is_a?(Numeric) && usr != uid
446
448
 
447
449
  groups, primary_group = *get_groups(domain, user.name)
448
450
 
@@ -470,7 +472,8 @@ module Sys
470
472
  end
471
473
 
472
474
  return user_object
473
- }
475
+ end
476
+ # rubocop:enable Metrics/BlockLength
474
477
 
475
478
  # If we're here, it means it wasn't found.
476
479
  raise Error, "no user found for '#{usr}'"
@@ -499,32 +502,32 @@ module Sys
499
502
  options = munge_options(options)
500
503
 
501
504
  host = options.delete(:host) || Socket.gethostname
502
- cs = "winmgmts:{impersonationLevel=impersonate}!"
505
+ cs = 'winmgmts:{impersonationLevel=impersonate}!'
503
506
  cs << "//#{host}/root/cimv2"
504
507
 
505
508
  begin
506
509
  wmi = WIN32OLE.connect(cs)
507
- rescue WIN32OLERuntimeError => e
508
- raise Error, e
510
+ rescue WIN32OLERuntimeError => err
511
+ raise Error, err
509
512
  end
510
513
 
511
- query = "select * from win32_useraccount"
514
+ query = 'select * from win32_useraccount'
512
515
 
513
516
  i = 0
514
517
 
515
- options.each{ |opt, val|
518
+ options.each do |opt, val|
516
519
  if i == 0
517
520
  query << " where #{opt} = '#{val}'"
518
521
  i += 1
519
522
  else
520
523
  query << " and #{opt} = '#{val}'"
521
524
  end
522
- }
525
+ end
523
526
 
524
527
  array = []
525
528
  domain = options[:domain] || host
526
529
 
527
- wmi.execquery(query).each{ |user|
530
+ wmi.execquery(query).each do |user|
528
531
  uid = user.sid.split('-').last.to_i
529
532
 
530
533
  usr = User.new do |u|
@@ -550,7 +553,7 @@ module Sys
550
553
  end
551
554
 
552
555
  array.push(usr)
553
- }
556
+ end
554
557
 
555
558
  array
556
559
  end
@@ -586,7 +589,7 @@ module Sys
586
589
  options = munge_options(options)
587
590
 
588
591
  host = options.delete(:host) || Socket.gethostname
589
- cs = "winmgmts:{impersonationLevel=impersonate}!"
592
+ cs = 'winmgmts:{impersonationLevel=impersonate}!'
590
593
  cs << "//#{host}/root/cimv2"
591
594
 
592
595
  begin
@@ -595,20 +598,20 @@ module Sys
595
598
  raise Error, err
596
599
  end
597
600
 
598
- query = "select * from win32_group"
601
+ query = 'select * from win32_group'
599
602
 
600
603
  i = 0
601
604
 
602
- options.each{ |opt, val|
605
+ options.each do |opt, val|
603
606
  if i == 0
604
607
  query << " where #{opt} = '#{val}'"
605
608
  i += 1
606
609
  else
607
610
  query << " and #{opt} = '#{val}'"
608
611
  end
609
- }
612
+ end
610
613
 
611
- if grp.kind_of?(Integer)
614
+ if grp.is_a?(Integer)
612
615
  if i == 0
613
616
  query << " where sid like '%-#{grp}'"
614
617
  else
@@ -624,14 +627,11 @@ module Sys
624
627
 
625
628
  domain = options[:domain] || host
626
629
 
627
- wmi.execquery(query).each{ |group|
628
- gid = group.sid.split("-").last.to_i
630
+ wmi.execquery(query).each do |group|
631
+ gid = group.sid.split('-').last.to_i
629
632
 
630
- # Because our 'like' query isn't fulproof, let's parse
631
- # the SID again to make sure
632
- if grp.kind_of?(Integer)
633
- next if grp != gid
634
- end
633
+ # Because our 'like' query isn't fulproof, let's parse the SID again to make sure
634
+ next if grp.is_a?(Integer) && grp != gid
635
635
 
636
636
  group_object = Group.new do |g|
637
637
  g.caption = group.caption
@@ -648,7 +648,7 @@ module Sys
648
648
  end
649
649
 
650
650
  return group_object
651
- }
651
+ end
652
652
 
653
653
  # If we're here, it means it wasn't found.
654
654
  raise Error, "no group found for '#{grp}'"
@@ -678,7 +678,7 @@ module Sys
678
678
  options = munge_options(options)
679
679
 
680
680
  host = options.delete(:host) || Socket.gethostname
681
- cs = "winmgmts:{impersonationLevel=impersonate}!"
681
+ cs = 'winmgmts:{impersonationLevel=impersonate}!'
682
682
  cs << "//#{host}/root/cimv2"
683
683
 
684
684
  begin
@@ -687,28 +687,28 @@ module Sys
687
687
  raise Error, err
688
688
  end
689
689
 
690
- query = "select * from win32_group"
690
+ query = 'select * from win32_group'
691
691
 
692
692
  i = 0
693
693
 
694
- options.each{ |opt, val|
694
+ options.each do |opt, val|
695
695
  if i == 0
696
696
  query << " where #{opt} = '#{val}'"
697
697
  i += 1
698
698
  else
699
699
  query << " and #{opt} = '#{val}'"
700
700
  end
701
- }
701
+ end
702
702
 
703
703
  array = []
704
704
  domain = options[:domain] || host
705
705
 
706
- wmi.execquery(query).each{ |group|
706
+ wmi.execquery(query).each do |group|
707
707
  grp = Group.new do |g|
708
708
  g.caption = group.caption
709
709
  g.description = group.description
710
710
  g.domain = group.domain
711
- g.gid = group.sid.split("-").last.to_i
711
+ g.gid = group.sid.split('-').last.to_i
712
712
  g.install_date = group.installdate
713
713
  g.local = group.localaccount
714
714
  g.name = group.name
@@ -719,11 +719,12 @@ module Sys
719
719
  end
720
720
 
721
721
  array.push(grp)
722
- }
722
+ end
723
723
 
724
724
  array
725
725
  end
726
726
 
727
+ # The User class encapsulates the information typically found within an /etc/passwd entry.
727
728
  class User
728
729
  # An account for users whose primary account is in another domain.
729
730
  TEMP_DUPLICATE = 0x0100
@@ -839,9 +840,7 @@ module Sys
839
840
 
840
841
  # Returns the SID type as a human readable string.
841
842
  #
842
- def sid_type
843
- @sid_type
844
- end
843
+ attr_reader :sid_type
845
844
 
846
845
  # Sets the SID (Security Identifier) type to +stype+, which can be
847
846
  # one of the following constant values:
@@ -877,7 +876,7 @@ module Sys
877
876
  when Admin::SidTypeComputer
878
877
  @sid_type = 'computer'
879
878
  else
880
- @sid_type = 'unknown'
879
+ @sid_type = 'not_found'
881
880
  end
882
881
  end
883
882
 
@@ -918,6 +917,7 @@ module Sys
918
917
  end
919
918
  end
920
919
 
920
+ # The Group class encapsulates the information typically found within an /etc/group entry.
921
921
  class Group
922
922
  # Short description of the object.
923
923
  attr_accessor :caption
@@ -961,14 +961,12 @@ module Sys
961
961
  # Returns whether or not the group is a local group.
962
962
  #
963
963
  def local?
964
- @local
964
+ @local
965
965
  end
966
966
 
967
967
  # Returns the type of SID (Security Identifier) as a stringified value.
968
968
  #
969
- def sid_type
970
- @sid_type
971
- end
969
+ attr_reader :sid_type
972
970
 
973
971
  # Sets the SID (Security Identifier) type to +stype+, which can be
974
972
  # one of the following constant values:
@@ -984,34 +982,32 @@ module Sys
984
982
  # * Admin::SidTypeComputer
985
983
  #
986
984
  def sid_type=(stype)
987
- if stype.kind_of?(String)
985
+ if stype.is_a?(String)
988
986
  @sid_type = stype.downcase
989
987
  else
990
988
  case stype
991
- when Admin::SidTypeUser
992
- @sid_type = "user"
993
- when Admin::SidTypeGroup
994
- @sid_type = "group"
995
- when Admin::SidTypeDomain
996
- @sid_type = "domain"
997
- when Admin::SidTypeAlias
998
- @sid_type = "alias"
999
- when Admin::SidTypeWellKnownGroup
1000
- @sid_type = "well_known_group"
1001
- when Admin::SidTypeDeletedAccount
1002
- @sid_type = "deleted_account"
1003
- when Admin::SidTypeInvalid
1004
- @sid_type = "invalid"
1005
- when Admin::SidTypeUnknown
1006
- @sid_type = "unknown"
1007
- when Admin::SidTypeComputer
1008
- @sid_type = "computer"
1009
- else
1010
- @sid_type = "unknown"
989
+ when Admin::SidTypeUser
990
+ @sid_type = 'user'
991
+ when Admin::SidTypeGroup
992
+ @sid_type = 'group'
993
+ when Admin::SidTypeDomain
994
+ @sid_type = 'domain'
995
+ when Admin::SidTypeAlias
996
+ @sid_type = 'alias'
997
+ when Admin::SidTypeWellKnownGroup
998
+ @sid_type = 'well_known_group'
999
+ when Admin::SidTypeDeletedAccount
1000
+ @sid_type = 'deleted_account'
1001
+ when Admin::SidTypeInvalid
1002
+ @sid_type = 'invalid'
1003
+ when Admin::SidTypeUnknown
1004
+ @sid_type = 'unknown'
1005
+ when Admin::SidTypeComputer
1006
+ @sid_type = 'computer'
1007
+ else
1008
+ @sid_type = 'not_found'
1011
1009
  end
1012
1010
  end
1013
-
1014
- @sid_type
1015
1011
  end
1016
1012
  end
1017
1013
  end
data/spec/spec_helper.rb CHANGED
@@ -1,13 +1,22 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rspec'
2
4
  require 'sys-admin'
5
+ require 'sys_admin_shared'
3
6
 
4
7
  RSpec.configure do |config|
8
+ config.include_context(Sys::Admin)
5
9
  config.filter_run_excluding(:darwin) if Gem::Platform.local.os != 'darwin'
6
10
  config.filter_run_excluding(:windows) unless Gem.win_platform?
7
11
 
8
12
  if Gem.win_platform?
9
- config.filter_run_excluding(:unix)
10
13
  require 'win32-security'
11
14
  require 'socket'
15
+
16
+ config.filter_run_excluding(:unix)
17
+
18
+ config.before(:each, :requires_elevated => true) do
19
+ skip 'skipped unless administrator privileges' unless Win32::Security.elevated_security?
20
+ end
12
21
  end
13
22
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.shared_examples Sys::Admin do
4
+ example 'version is set to expected value' do
5
+ expect(described_class::VERSION).to eq('1.8.3')
6
+ end
7
+
8
+ example 'version constant is frozen' do
9
+ expect(described_class::VERSION).to be_frozen
10
+ end
11
+
12
+ example 'constructor is private' do
13
+ expect{ described_class.new }.to raise_error(NoMethodError)
14
+ end
15
+ end