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