sys-admin 1.5.6 → 1.6.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.
data/CHANGES CHANGED
@@ -1,3 +1,11 @@
1
+ == 1.6.0 - 5-Jan-2013
2
+ * Converted code to use FFI. This mostly only affects the unix flavors.
3
+ * The Admin.users and Admin.groups methods no longer accept a block.
4
+ * Some test suite updates.
5
+ * Because all code is now pure Ruby, there is longer any need for two
6
+ separate gems. There is now a single, unified gem that works on all
7
+ supported platforms.
8
+
1
9
  == 1.5.6 - 30-Jul-2011
2
10
  * Fixed issue for non-gnu platforms where it would use the wrong function
3
11
  prototype because the Ruby core team took it upon themselves to explicitly
data/MANIFEST CHANGED
@@ -5,10 +5,13 @@
5
5
  * README
6
6
  * examples/groups.rb
7
7
  * examples/users.rb
8
- * ext/admin.c
9
- * ext/admin.h
10
- * ext/extconf.rb
11
8
  * lib/sys/admin.rb
9
+ * lib/darwin/sys/admin.rb
10
+ * lib/linux/sys/admin.rb
11
+ * lib/bsd/sys/admin.rb
12
+ * lib/sunos/sys/admin.rb
13
+ * lib/sys/admin/common.rb
14
+ * lib/sys/admin/custom.rb
12
15
  * test/test_sys_admin.rb
13
16
  * test/test_sys_admin_unix.rb
14
17
  * test/test_sys_admin_windows.rb
data/README CHANGED
@@ -8,19 +8,9 @@
8
8
  require 'sys/admin'
9
9
  include Sys
10
10
 
11
- # Yields a User object for each user
12
- Admin.users{ |user|
13
- p user
14
- }
15
-
16
11
  # Returns an Array of User objects
17
12
  a = Admin.users
18
13
 
19
- # Yields a Group object for each group
20
- Admin.groups{ |group|
21
- p group
22
- }
23
-
24
14
  # Returns an Array of Group objects
25
15
  g = Admin.groups
26
16
 
@@ -47,17 +37,13 @@ Admin.get_group(gid, options = {})
47
37
  options you provide, e.g. 'domain' or 'localaccount'.
48
38
 
49
39
  Admin.groups(options = {})
50
- Admin.groups(options = {}){ |group| ... }
51
- In block form, yields a Group object for each user on the system. In
52
- non-block form, returns an Array of Group objects.
40
+ Returns an Array of Group objects.
53
41
 
54
42
  The +options+ hash is for MS Windows only, and allows you to restrict the
55
43
  search based on the options you provide, e.g. 'domain' or 'localaccount'.
56
44
 
57
45
  Admin.users(options = {})
58
- Admin.users(options = {}){ |user| ... }
59
- In block form, yields a User object for each user on the system. In
60
- non-block form, returns an Array of User objects.
46
+ Returns an Array of User objects.
61
47
 
62
48
  The +options+ hash is for MS Windows only, and allows you to restrict the
63
49
  search based on the options you provide, e.g. 'domain' or 'localaccount'.
@@ -149,7 +135,7 @@ Admin::Error < StandardError
149
135
  Artistic 2.0
150
136
 
151
137
  == Copyright
152
- (C) 2005-2010, Daniel J. Berger
138
+ (C) 2005-2013, Daniel J. Berger
153
139
  All Rights Reserved
154
140
 
155
141
  == Author
data/Rakefile CHANGED
@@ -2,73 +2,44 @@ require 'rake'
2
2
  require 'rake/clean'
3
3
  require 'rake/testtask'
4
4
  require 'rbconfig'
5
- include Config
6
5
 
7
- WINDOWS = CONFIG['host_os'] =~ /msdos|mswin|win32|mingw|cygwin|windows/i
8
-
9
- CLEAN.include(
10
- '**/*.gem', # Gem files
11
- '**/*.rbc', # Rubinius
12
- '**/*.o', # C object file
13
- '**/*.log', # Ruby extension build log
14
- '**/Makefile', # C Makefile
15
- '**/conftest.dSYM', # OS X build directory
16
- "**/*.#{CONFIG['DLEXT']}" # C shared object
17
- )
18
-
19
- desc "Build the sys-admin library on UNIX systems (but don't install it)"
20
- task :build => [:clean] do
21
- unless WINDOWS
22
- Dir.chdir('ext') do
23
- ruby 'extconf.rb'
24
- sh 'make'
25
- build_file = 'admin.' + Config::CONFIG['DLEXT']
26
- FileUtils.cp(build_file, 'sys')
27
- end
28
- end
29
- end
6
+ CLEAN.include("**/*.gem", "**/*.rbx", "**/*.rbc")
30
7
 
31
8
  namespace :gem do
32
- desc "Create a sys-admin gem file."
9
+ desc "Create the sys-uname gem"
33
10
  task :create => [:clean] do
34
11
  spec = eval(IO.read('sys-admin.gemspec'))
35
-
36
- if WINDOWS
37
- spec.platform = Gem::Platform::CURRENT
38
- spec.platform.cpu = 'universal'
39
- spec.files = spec.files.reject{ |f| f.include?('ext') }
40
- spec.add_dependency('win32-security', '>= 0.1.2')
41
- else
42
- spec.files = spec.files.reject{ |f| f.include?('lib') }
43
- spec.extensions = ['ext/extconf.rb']
44
- spec.extra_rdoc_files << 'ext/sys/admin.c'
45
- end
46
-
47
12
  Gem::Builder.new(spec).build
48
13
  end
49
14
 
50
- desc "Install the sys-admin gem."
51
- task :install => [:create] do
52
- gem = Dir['*.gem'].first
53
- sh "gem install #{gem}"
15
+ desc "Install the sys-uname gem"
16
+ task :install => [:build] do
17
+ file = Dir["*.gem"].first
18
+ sh "gem install #{file}"
54
19
  end
55
20
  end
56
21
 
57
- desc "Run the test suite"
58
22
  Rake::TestTask.new('test') do |t|
59
- if WINDOWS
60
- t.libs << 'lib'
23
+ case RbConfig::CONFIG['host_os']
24
+ when /darwin|osx/i
25
+ t.libs << 'lib/darwin'
26
+ when /linux/i
27
+ t.libs << 'lib/linux'
28
+ when /sunos|solaris/i
29
+ t.libs << 'lib/sunos'
30
+ when /bsd/i
31
+ t.libs << 'lib/bsd'
32
+ when /windows|win32|mingw|cygwin|dos/i
33
+ t.libs << 'lib/windows'
61
34
  else
62
- task :test => :build
63
- t.libs << 'ext'
64
- t.libs.delete('lib')
35
+ t.libs << 'lib/unix'
65
36
  end
37
+
38
+ t.warning = true
39
+ t.verbose = true
40
+
66
41
  t.libs << 'test'
67
42
  t.test_files = FileList['test/test_sys_admin.rb']
68
43
  end
69
44
 
70
- task :test do
71
- Rake.application[:clean].execute
72
- end
73
-
74
45
  task :default => :test
@@ -0,0 +1,27 @@
1
+ ###########################################################################
2
+ # groups.rb
3
+ #
4
+ # Sample script to demonstrate some of the various group methods. Alter
5
+ # as you see fit.
6
+ ###########################################################################
7
+ require "pp"
8
+ require "sys/admin"
9
+ include Sys
10
+
11
+ if File::ALT_SEPARATOR
12
+ pp Admin.get_group("guests")
13
+ pp Admin.get_group(513)
14
+ else
15
+ pp Admin.get_group("admin")
16
+ pp Admin.get_group(7)
17
+ end
18
+
19
+ sleep 3
20
+
21
+ Admin.groups.each{ |g|
22
+ pp g
23
+ puts
24
+ }
25
+
26
+ # This should raise an error
27
+ Admin.get_group("fofofofof")
@@ -0,0 +1,41 @@
1
+ ###########################################################################
2
+ # users.rb
3
+ #
4
+ # Sample script to demonstrate some of the various user methods. Alter
5
+ # as you see fit.
6
+ ###########################################################################
7
+ require "pp"
8
+ require "sys/admin"
9
+ include Sys
10
+
11
+ =begin
12
+ user = User.new do |u|
13
+ u.name = "Foo"
14
+ u.description = "Test account"
15
+ u.password = "changeme"
16
+ #u.lockout = false
17
+ u.disabled = true
18
+ #u.password_required = true
19
+ end
20
+
21
+ Admin.delete_user(u.name) rescue nil
22
+ Admin.add_user(user)
23
+
24
+ pp Admin.get_user("Foo")
25
+
26
+ Admin.delete_user("Foo")
27
+ =end
28
+
29
+ user = Admin.get_login
30
+
31
+ puts "User: #{user}"
32
+
33
+ sleep 3
34
+
35
+ Admin.users.each{ |u|
36
+ pp u
37
+ puts
38
+ }
39
+
40
+ pp Admin.get_user(user)
41
+ pp Admin.get_user(501)
@@ -0,0 +1,239 @@
1
+ require 'sys/admin/custom'
2
+ require 'sys/admin/common'
3
+
4
+ # The BSD specific code.
5
+
6
+ module Sys
7
+ class Admin
8
+ private
9
+
10
+ # I'm making some aliases here to prevent potential conflicts
11
+ attach_function :open_c, :open, [:string, :int], :int
12
+ attach_function :pread_c, :pread, [:int, :pointer, :size_t, :off_t], :size_t
13
+ attach_function :close_c, :close, [:int], :int
14
+
15
+ attach_function :getlogin_r, [:pointer, :int], :int
16
+ attach_function :getpwnam_r, [:string, :pointer, :pointer, :size_t, :pointer], :int
17
+ attach_function :getpwuid_r, [:long, :pointer, :pointer, :size_t, :pointer], :int
18
+ attach_function :getgrnam_r, [:string, :pointer, :pointer, :size_t, :pointer], :int
19
+ attach_function :getgrgid_r, [:long, :pointer, :pointer, :size_t, :pointer], :int
20
+
21
+ private_class_method :getlogin_r, :getpwnam_r, :getpwuid_r, :getgrnam_r
22
+ private_class_method :getgrgid_r
23
+ private_class_method :open_c, :pread_c, :close_c
24
+
25
+ # struct passwd from /usr/include/pwd.h
26
+ class PasswdStruct < FFI::Struct
27
+ layout(
28
+ :pw_name, :string,
29
+ :pw_passwd, :string,
30
+ :pw_uid, :uint,
31
+ :pw_gid, :uint,
32
+ :pw_change, :ulong,
33
+ :pw_class, :string,
34
+ :pw_gecos, :string,
35
+ :pw_dir, :string,
36
+ :pw_shell, :string,
37
+ :pw_expire, :ulong
38
+ )
39
+ end
40
+
41
+ # struct group from /usr/include/grp.h
42
+ class GroupStruct < FFI::Struct
43
+ layout(
44
+ :gr_name, :string,
45
+ :gr_passwd, :string,
46
+ :gr_gid, :uint,
47
+ :gr_mem, :pointer
48
+ )
49
+ end
50
+
51
+ # I'm blending the timeval struct in directly here
52
+ class LastlogStruct < FFI::Struct
53
+ layout(
54
+ :ll_time, :int32,
55
+ :ll_line, [:char, 32],
56
+ :ll_host, [:char, 256]
57
+ )
58
+ end
59
+
60
+ public
61
+
62
+ # Returns the login for the current process.
63
+ #
64
+ def self.get_login
65
+ buf = FFI::MemoryPointer.new(:char, 256)
66
+
67
+ if getlogin_r(buf, buf.size) != 0
68
+ raise Error, "getlogin_r function failed: " + strerror(FFI.errno)
69
+ end
70
+
71
+ buf.read_string
72
+ end
73
+
74
+ # Returns a User object for the given name or uid. Raises an error
75
+ # if a user cannot be found.
76
+ #
77
+ # Examples:
78
+ #
79
+ # Sys::Admin.get_user('joe')
80
+ # Sys::Admin.get_user(501)
81
+ #
82
+ def self.get_user(uid)
83
+ buf = FFI::MemoryPointer.new(:char, 1024)
84
+ pbuf = FFI::MemoryPointer.new(PasswdStruct)
85
+ temp = PasswdStruct.new
86
+
87
+ if uid.is_a?(String)
88
+ if getpwnam_r(uid, temp, buf, buf.size, pbuf) != 0
89
+ raise Error, "getpwnam_r function failed: " + strerror(FFI.errno)
90
+ end
91
+ else
92
+ if getpwuid_r(uid, temp, buf, buf.size, pbuf) != 0
93
+ raise Error, "getpwuid_r function failed: " + strerror(FFI.errno)
94
+ end
95
+ end
96
+
97
+ ptr = pbuf.read_pointer
98
+
99
+ if ptr.null?
100
+ raise Error, "no user found for #{uid}"
101
+ end
102
+
103
+ pwd = PasswdStruct.new(ptr)
104
+ get_user_from_struct(pwd)
105
+ end
106
+
107
+ # Returns a Group object for the given name or uid. Raises an error
108
+ # if a group cannot be found.
109
+ #
110
+ # Examples:
111
+ #
112
+ # Sys::Admin.get_group('admin')
113
+ # Sys::Admin.get_group(101)
114
+ #
115
+ def self.get_group(gid)
116
+ buf = FFI::MemoryPointer.new(:char, 1024)
117
+ pbuf = FFI::MemoryPointer.new(PasswdStruct)
118
+ temp = GroupStruct.new
119
+
120
+ if gid.is_a?(String)
121
+ if getgrnam_r(gid, temp, buf, buf.size, pbuf) != 0
122
+ raise Error, "getgrnam_r function failed: " + strerror(FFI.errno)
123
+ end
124
+ else
125
+ if getgrgid_r(gid, temp, buf, buf.size, pbuf) != 0
126
+ raise Error, "getgrgid_r function failed: " + strerror(FFI.errno)
127
+ end
128
+ end
129
+
130
+ ptr = pbuf.read_pointer
131
+
132
+ if ptr.null?
133
+ raise Error, "no group found for #{gid}"
134
+ end
135
+
136
+ grp = GroupStruct.new(ptr)
137
+ get_group_from_struct(grp)
138
+ end
139
+
140
+ # Returns an array of User objects for each user on the system.
141
+ #
142
+ def self.users
143
+ users = []
144
+
145
+ begin
146
+ setpwent()
147
+
148
+ until (ptr = getpwent()).null?
149
+ pwd = PasswdStruct.new(ptr)
150
+ users << get_user_from_struct(pwd)
151
+ end
152
+ ensure
153
+ endpwent()
154
+ end
155
+
156
+ users
157
+ end
158
+
159
+ # Returns an array of Group objects for each user on the system.
160
+ #
161
+ def self.groups
162
+ groups = []
163
+
164
+ begin
165
+ setgrent()
166
+
167
+ until (ptr = getgrent()).null?
168
+ grp = GroupStruct.new(ptr)
169
+ groups << get_group_from_struct(grp)
170
+ end
171
+ ensure
172
+ endgrent()
173
+ end
174
+
175
+ groups
176
+ end
177
+
178
+ private
179
+
180
+ # Takes a GroupStruct and converts it to a Group object.
181
+ def self.get_group_from_struct(grp)
182
+ Group.new do |g|
183
+ g.name = grp[:gr_name]
184
+ g.passwd = grp[:gr_passwd]
185
+ g.gid = grp[:gr_gid]
186
+ g.members = grp[:gr_mem].read_array_of_string
187
+ end
188
+ end
189
+
190
+ # Takes a UserStruct and converts it to a User object.
191
+ def self.get_user_from_struct(pwd)
192
+ user = User.new do |u|
193
+ u.name = pwd[:pw_name]
194
+ u.passwd = pwd[:pw_passwd]
195
+ u.uid = pwd[:pw_uid]
196
+ u.gid = pwd[:pw_gid]
197
+ u.change = Time.at(pwd[:pw_change])
198
+ u.access_class = pwd[:pw_class]
199
+ u.gecos = pwd[:pw_gecos]
200
+ u.dir = pwd[:pw_dir]
201
+ u.shell = pwd[:pw_shell]
202
+ u.expire = Time.at(pwd[:pw_expire])
203
+ end
204
+
205
+ log = get_lastlog_info(user.uid)
206
+
207
+ if log
208
+ user.login_time = Time.at(log[:ll_time])
209
+ user.login_device = log[:ll_line].to_s
210
+ user.login_host = log[:ll_host].to_s
211
+ end
212
+
213
+ user
214
+ end
215
+
216
+ # Get lastlog information for the given user.
217
+ def self.get_lastlog_info(uid)
218
+ logfile = '/var/log/lastlog'
219
+ lastlog = LastlogStruct.new
220
+
221
+ begin
222
+ fd = open_c(logfile, File::RDONLY)
223
+
224
+ if fd != -1
225
+ bytes = pread_c(fd, lastlog, lastlog.size, uid * lastlog.size)
226
+ if bytes < 0
227
+ raise Error, "pread function failed: " + strerror(FFI.errno)
228
+ end
229
+ else
230
+ nil # Ignore, improper permissions
231
+ end
232
+ ensure
233
+ close_c(fd) if fd && fd >= 0
234
+ end
235
+
236
+ lastlog
237
+ end
238
+ end
239
+ end