etcutils 1.0.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.
- checksums.yaml +15 -0
- data/.gitignore +22 -0
- data/.travis.yml +19 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +20 -0
- data/LICENSE +20 -0
- data/README.md +335 -0
- data/Rakefile +16 -0
- data/etcutils.gemspec +27 -0
- data/ext/etcutils/etcutils.c +1398 -0
- data/ext/etcutils/etcutils.h +189 -0
- data/ext/etcutils/extconf.rb +51 -0
- data/ext/etcutils/group.c +192 -0
- data/ext/etcutils/passwd.c +297 -0
- data/lib/etcutils.rb +4 -0
- data/lib/etcutils/version.rb +3 -0
- data/tests/README +141 -0
- data/tests/etcutils_test_helper.rb +8 -0
- data/tests/root/etc_utils.rb +5 -0
- data/tests/root/gshadow_tests.rb +153 -0
- data/tests/root/locking.rb +23 -0
- data/tests/root/shadow_tests.rb +161 -0
- data/tests/test_etc_utils.rb +107 -0
- data/tests/test_eu_locking.rb +15 -0
- data/tests/test_eu_next_uid_next_gid.rb +32 -0
- data/tests/test_eu_sgetpwent.rb +91 -0
- data/tests/test_group_class.rb +128 -0
- data/tests/test_passwd_class.rb +125 -0
- data/tests/user/etc_utils.rb +6 -0
- data/tests/user/locking.rb +7 -0
- metadata +119 -0
data/lib/etcutils.rb
ADDED
data/tests/README
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
EU Tests
|
2
|
+
======
|
3
|
+
|
4
|
+
Trying to clearly define what should be expected and where it is tested.
|
5
|
+
|
6
|
+
|
7
|
+
test_eu_next_uid_next_gid
|
8
|
+
next_uid
|
9
|
+
next_gid
|
10
|
+
next_uid()
|
11
|
+
next_gid()
|
12
|
+
next_uid=
|
13
|
+
next_gid=
|
14
|
+
|
15
|
+
test_etc_utils
|
16
|
+
me
|
17
|
+
getlogin
|
18
|
+
has_passwd?
|
19
|
+
has_shadow?
|
20
|
+
has_group?
|
21
|
+
has_gshadow?
|
22
|
+
setXXent
|
23
|
+
endXXent
|
24
|
+
getpwent
|
25
|
+
getgrent
|
26
|
+
find_pwd
|
27
|
+
setpwent
|
28
|
+
endpwent
|
29
|
+
|
30
|
+
test_eu_sgetpwent
|
31
|
+
sgetpwent
|
32
|
+
find_pwd.to_entry = sgetpwent.to_entry
|
33
|
+
most field changes are allowed
|
34
|
+
- gecos, directory, passwd, shell
|
35
|
+
new entry with available UID/GID
|
36
|
+
new entry with unavailable/conflicting UID/GID
|
37
|
+
nil username should raise exception
|
38
|
+
|
39
|
+
|
40
|
+
test_eu_locking
|
41
|
+
lckpwdf
|
42
|
+
ulckpwdf
|
43
|
+
lock
|
44
|
+
unlock
|
45
|
+
locked?
|
46
|
+
- root/locking
|
47
|
+
lock = locked?
|
48
|
+
unlock != locked?
|
49
|
+
block locking
|
50
|
+
lock exception handling
|
51
|
+
- user/locking
|
52
|
+
lock exception raised
|
53
|
+
|
54
|
+
|
55
|
+
root/etc_utils.rb
|
56
|
+
|- root/shadow_tests
|
57
|
+
module tests
|
58
|
+
getspent
|
59
|
+
find_spwd
|
60
|
+
setspent
|
61
|
+
endspent
|
62
|
+
sgetspent
|
63
|
+
getspnam
|
64
|
+
fgetspent
|
65
|
+
putspent
|
66
|
+
putspent_raises for file/type
|
67
|
+
class tests
|
68
|
+
get
|
69
|
+
each
|
70
|
+
find
|
71
|
+
parse
|
72
|
+
set
|
73
|
+
end
|
74
|
+
|
75
|
+
|- root/gshadow_tests
|
76
|
+
module tests
|
77
|
+
getsgent
|
78
|
+
find_sgrp
|
79
|
+
setsgent
|
80
|
+
endsgent
|
81
|
+
sgetsgent
|
82
|
+
getsgnam
|
83
|
+
fgetsgent
|
84
|
+
putsgent
|
85
|
+
putspent_raises for file/type
|
86
|
+
class tests
|
87
|
+
get
|
88
|
+
each
|
89
|
+
find
|
90
|
+
parse
|
91
|
+
set
|
92
|
+
end
|
93
|
+
members
|
94
|
+
admins
|
95
|
+
|
96
|
+
test_passwd_class
|
97
|
+
module tests
|
98
|
+
getpwent
|
99
|
+
find_pwd
|
100
|
+
setpwent
|
101
|
+
endpwent
|
102
|
+
sgetpwent
|
103
|
+
getpwnam
|
104
|
+
fgetpwent
|
105
|
+
putpwent
|
106
|
+
putspent_raises for file/type
|
107
|
+
class tests
|
108
|
+
get
|
109
|
+
each
|
110
|
+
find
|
111
|
+
parse
|
112
|
+
set
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
test_group_class
|
117
|
+
module tests
|
118
|
+
getgrent
|
119
|
+
find_grp
|
120
|
+
setgrent
|
121
|
+
endgrent
|
122
|
+
sgetgrent
|
123
|
+
getgrnam
|
124
|
+
fgetgrent
|
125
|
+
putgrent
|
126
|
+
putspent_raises for file/type
|
127
|
+
class tests
|
128
|
+
get
|
129
|
+
each
|
130
|
+
find
|
131
|
+
parse
|
132
|
+
set
|
133
|
+
end
|
134
|
+
members
|
135
|
+
|
136
|
+
|
137
|
+
## TODO
|
138
|
+
|
139
|
+
DRYIFY root/etc_utils.rb
|
140
|
+
|
141
|
+
Should raise rb_eSystemCallError if system calls fail
|
@@ -0,0 +1,153 @@
|
|
1
|
+
# This needs to be mentioned during install, but it's just going to
|
2
|
+
# fail a majority of the time until 14.04.
|
3
|
+
#
|
4
|
+
# def test_nsswitch_conf_gshadow
|
5
|
+
# assert_block "\n#{'*' * 75}
|
6
|
+
# nsswitch.conf may be misconfigured. Consider adding the below to /etc/nsswitch.conf.
|
7
|
+
# gshadow:\tfiles
|
8
|
+
# See 'http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=699089' for more.\n" do
|
9
|
+
# setsgent
|
10
|
+
# !!getsgent
|
11
|
+
# end
|
12
|
+
# end
|
13
|
+
|
14
|
+
class GShadowTest < Test::Unit::TestCase
|
15
|
+
|
16
|
+
##
|
17
|
+
# Module Specific Methods
|
18
|
+
#
|
19
|
+
|
20
|
+
def test_set_end_ent
|
21
|
+
assert_nothing_raised do
|
22
|
+
EU.setsgent
|
23
|
+
end
|
24
|
+
|
25
|
+
assert_nothing_raised do
|
26
|
+
EU.endsgent
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_find
|
31
|
+
assert_nil EtcUtils.find_sgrp("testuser"), "EU.find_sgrp should return nil if user does not exist"
|
32
|
+
assert_equal("root", EtcUtils.find_sgrp("root").name, "EU.find_sgrp(str) should return user if it exists")
|
33
|
+
assert_equal("root", EtcUtils.find_sgrp(0).name, "EU.find_sgrp(int) should return user if it exists")
|
34
|
+
assert_nothing_raised do
|
35
|
+
EU.setsgent
|
36
|
+
end
|
37
|
+
assert_equal(getsgnam('root').name, getsgent.name, "EU.getsgnam('root') and EU.getsgent should return the same user")
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_shadow_vs_passwd
|
41
|
+
assert_equal(find_sgrp('root').name, find_grp('root').name, "EU.find_sgrp and EU.find_grp should return the same user")
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_sgetsgent
|
45
|
+
assert sgetsgent(find_sgrp('root').to_entry).name.eql? "root"
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_getsgent_while
|
49
|
+
assert_nothing_raised do
|
50
|
+
EtcUtils.setsgent
|
51
|
+
while ( ent = EtcUtils.getsgent ); nil; end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_fgetsgent_and_putsgent
|
56
|
+
tmp_fn = "/tmp/_fgetsgent_test"
|
57
|
+
assert_nothing_raised do
|
58
|
+
fh = File.open('/etc/gshadow', 'r')
|
59
|
+
File.open(tmp_fn, File::RDWR|File::CREAT, 0600) { |tmp_fh|
|
60
|
+
while ( ent = EtcUtils.fgetsgent(fh) )
|
61
|
+
EU.putsgent(ent, tmp_fh)
|
62
|
+
end
|
63
|
+
}
|
64
|
+
fh.close
|
65
|
+
end
|
66
|
+
assert File.exists?(tmp_fn), "EU.fgetsgent(fh) should write to fh"
|
67
|
+
assert FileUtils.compare_file("/etc/gshadow", tmp_fn) == true,
|
68
|
+
"DIFF FAILED: /etc/gshadow <=> #{tmp_fn}\n" << `diff /etc/gshadow #{tmp_fn}`
|
69
|
+
ensure
|
70
|
+
FileUtils.remove_file(tmp_fn);
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_putsgent_raises
|
74
|
+
FileUtils.touch "/tmp/_gshadow"
|
75
|
+
|
76
|
+
assert_raise IOError do
|
77
|
+
f = File.open("/tmp/_gshadow", 'r')
|
78
|
+
u = EU.find_sgrp('root')
|
79
|
+
u.fputs f
|
80
|
+
end
|
81
|
+
ensure
|
82
|
+
FileUtils.remove_file("/tmp/_gshadow");
|
83
|
+
end
|
84
|
+
|
85
|
+
##
|
86
|
+
# EU::GShadow class methods
|
87
|
+
#
|
88
|
+
def test_class_set_end_ent
|
89
|
+
assert_nothing_raised do
|
90
|
+
EU::GShadow.set
|
91
|
+
end
|
92
|
+
|
93
|
+
assert_nothing_raised do
|
94
|
+
EU::GShadow.end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_class_get
|
99
|
+
assert_not_nil EU::GShadow.get
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_class_each
|
103
|
+
assert_nothing_raised do
|
104
|
+
EU::GShadow.each do |e|
|
105
|
+
assert e.name
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_class_find
|
111
|
+
assert_equal "root", EU::GShadow.find('root').name
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_class_parse
|
115
|
+
assert_nothing_raised do
|
116
|
+
EtcUtils::GShadow.parse("root:x:0:")
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_class_parse_members
|
121
|
+
assert_nothing_raised do
|
122
|
+
assert_equal Array, EtcUtils::GShadow.parse("root:*::").members.class
|
123
|
+
end
|
124
|
+
|
125
|
+
assert_equal "user", EtcUtils::GShadow.parse("root:*:admin:user").members.first
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_class_parse_admins
|
129
|
+
assert_nothing_raised do
|
130
|
+
assert_equal Array, EtcUtils::GShadow.parse("root:*::").admins.class
|
131
|
+
end
|
132
|
+
|
133
|
+
assert_equal "admin", EtcUtils::GShadow.parse("root:*:admin:user").admins.first
|
134
|
+
end
|
135
|
+
|
136
|
+
##
|
137
|
+
# EU::GShadow instance methods
|
138
|
+
#
|
139
|
+
def test_init
|
140
|
+
assert_equal EU::GShadow, EU::GShadow.new.class
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_instance_methods
|
144
|
+
e = EU::GShadow.find('root')
|
145
|
+
assert_equal 'root', e.name
|
146
|
+
assert_not_nil e.passwd
|
147
|
+
assert_equal 'root', EU::GShadow.parse(e.to_entry).name
|
148
|
+
assert_equal String, e.to_entry.class
|
149
|
+
assert_equal Array, e.members.class
|
150
|
+
assert_equal Array, e.admins.class
|
151
|
+
assert e.respond_to?(:fputs)
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class RootLockingTest < EULockingTest
|
2
|
+
def test_locking
|
3
|
+
assert_equal(lock, locked?)
|
4
|
+
assert_not_equal(unlock, locked?)
|
5
|
+
end
|
6
|
+
|
7
|
+
def test_locking_block
|
8
|
+
assert_block "Couldn't run a block inside of lock()" do
|
9
|
+
lock { assert locked? }
|
10
|
+
!locked?
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_locked_after_exception
|
15
|
+
assert_block "Files remained locked when an exception is raised inside of lock()" do
|
16
|
+
begin
|
17
|
+
lock { raise "foobar" }
|
18
|
+
rescue
|
19
|
+
!locked?
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
class ShadowTest < Test::Unit::TestCase
|
2
|
+
require 'stringio'
|
3
|
+
##
|
4
|
+
# Module Specific Methods
|
5
|
+
#
|
6
|
+
|
7
|
+
def test_set_end_ent
|
8
|
+
assert_nothing_raised do
|
9
|
+
EU.setspent
|
10
|
+
end
|
11
|
+
|
12
|
+
assert_nothing_raised do
|
13
|
+
EU.endspent
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_find
|
18
|
+
assert_nil EtcUtils.find_spwd("testuser"), "EU.find_spwd should return nil if user does not exist"
|
19
|
+
assert_equal("root", EtcUtils.find_spwd("root").name, "EU.find_spwd(str) should return user if it exists")
|
20
|
+
assert_equal("root", EtcUtils.find_spwd(0).name, "EU.find_spwd(int) should return user if it exists")
|
21
|
+
assert_nothing_raised do
|
22
|
+
EU.setspent
|
23
|
+
end
|
24
|
+
assert_equal(getspnam('root').name, getspent.name, "EU.getspent and EU.find_spwd(0) should return the same user")
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_shadow_vs_passwd
|
28
|
+
assert_equal(find_spwd('root').name, find_pwd('root').name, "EU.find_spwd and EU.find_pwd should return the same user")
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_sgetspent
|
32
|
+
assert EU.sgetspent(EU.find_spwd('root').to_entry).name.eql? "root"
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_getspent_while
|
36
|
+
assert_nothing_raised do
|
37
|
+
EtcUtils.setspent
|
38
|
+
while ( ent = EtcUtils.getspent ); nil; end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_fgetspent_and_putspent
|
43
|
+
tmp_fn = "/tmp/_fgetsgent_test"
|
44
|
+
assert_nothing_raised do
|
45
|
+
fh = File.open('/etc/shadow', 'r')
|
46
|
+
File.open(tmp_fn, File::RDWR|File::CREAT, 0600) { |tmp_fh|
|
47
|
+
while ( ent = EtcUtils.fgetspent(fh) )
|
48
|
+
EU.putspent(ent, tmp_fh)
|
49
|
+
end
|
50
|
+
}
|
51
|
+
fh.close
|
52
|
+
end
|
53
|
+
assert File.exists?(tmp_fn), "EU.fgetspent(fh) should write to fh"
|
54
|
+
assert FileUtils.compare_file("/etc/shadow", tmp_fn) == true,
|
55
|
+
"DIFF FAILED: /etc/shadow <=> #{tmp_fn}\n" << `diff /etc/shadow #{tmp_fn}`
|
56
|
+
ensure
|
57
|
+
FileUtils.remove_file(tmp_fn);
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_putspent_raises
|
61
|
+
FileUtils.touch "/tmp/_shadow"
|
62
|
+
|
63
|
+
assert_raise IOError do
|
64
|
+
f = File.open("/tmp/_shadow", 'r')
|
65
|
+
u = EU.find_spwd('root')
|
66
|
+
u.fputs f
|
67
|
+
end
|
68
|
+
ensure
|
69
|
+
FileUtils.remove_file("/tmp/_shadow");
|
70
|
+
end
|
71
|
+
|
72
|
+
##
|
73
|
+
# EU::Shadow class methods
|
74
|
+
#
|
75
|
+
def test_class_set_end_ent
|
76
|
+
assert_nothing_raised do
|
77
|
+
EU::Shadow.set
|
78
|
+
end
|
79
|
+
|
80
|
+
assert_nothing_raised do
|
81
|
+
EU::Shadow.end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_class_get
|
86
|
+
assert_not_nil EU::Shadow.get
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_class_each
|
90
|
+
assert_nothing_raised do
|
91
|
+
EU::Shadow.each do |e|
|
92
|
+
assert e.name
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_class_find
|
98
|
+
assert_equal "root", EU::Shadow.find('root').name
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_class_parse
|
102
|
+
assert_nothing_raised do
|
103
|
+
EtcUtils::Shadow.parse("root:!:16122:0:99999:7:::")
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
##
|
108
|
+
# EU::Shadow instance methods
|
109
|
+
#
|
110
|
+
def test_init
|
111
|
+
assert_equal EU::Shadow, EU::Shadow.new.class
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_instance_methods
|
115
|
+
e = EU::Shadow.find('root')
|
116
|
+
assert_equal 'root', e.name
|
117
|
+
assert_not_nil e.passwd
|
118
|
+
assert_not_nil e.last_pw_change
|
119
|
+
assert e.respond_to?(:fputs)
|
120
|
+
assert_equal 'root', EU::Shadow.parse(e.to_entry).name
|
121
|
+
assert_equal String, e.to_entry.class
|
122
|
+
end
|
123
|
+
|
124
|
+
# rb_define_method(rb_cShadow, "passwd=", user_set_pw_change, 1);
|
125
|
+
# rb_define_method(rb_cShadow, "last_pw_change_date", user_get_pw_change, 0);
|
126
|
+
# rb_define_method(rb_cShadow, "expire_date", user_get_expire, 0);
|
127
|
+
# rb_define_method(rb_cShadow, "expire_date=", user_set_expire, 1);
|
128
|
+
def test_last_pwchange
|
129
|
+
e = EU::Shadow.find('root')
|
130
|
+
lstchg = e.last_pw_change
|
131
|
+
e.passwd = "!#{e.passwd}"
|
132
|
+
assert_not_equal e.last_pw_change, lstchg
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_expire
|
136
|
+
e = EU::Shadow.find('root')
|
137
|
+
assert_not_nil e.expire = 500
|
138
|
+
assert_equal Time.at(500 * 86400), e.expire_date
|
139
|
+
n = Time.now
|
140
|
+
assert_not_nil e.expire = n
|
141
|
+
assert_equal n.to_i / 86400, e.expire
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_expire_warning
|
145
|
+
e = EU::Shadow.find('root')
|
146
|
+
assert_equal capture_stderr{ e.expire = 0 }.gsub(/.+warning:\s+|\n/,''), "Setting EtcUtils::Shadow#expire to 0 should not be used as it is interpreted as either an account with no expiration, or as an expiration of Jan 1, 1970."
|
147
|
+
assert_equal 0, e.expire
|
148
|
+
end
|
149
|
+
|
150
|
+
def capture_stderr
|
151
|
+
# The output stream must be an IO-like object. In this case we capture it in
|
152
|
+
# an in-memory IO object so we can return the string value. You can assign any
|
153
|
+
# IO object here.
|
154
|
+
previous_stderr, $stderr = $stderr, StringIO.new
|
155
|
+
yield
|
156
|
+
$stderr.string
|
157
|
+
ensure
|
158
|
+
# Restore the previous value of stderr (typically equal to STDERR).
|
159
|
+
$stderr = previous_stderr
|
160
|
+
end
|
161
|
+
end
|