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.
@@ -0,0 +1,241 @@
1
+ require 'sys/admin/custom'
2
+ require 'sys/admin/common'
3
+
4
+ # The Solaris 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, :size_t], :pointer
16
+ attach_function :getpwnam_r, [:string, :pointer, :pointer, :size_t], :pointer
17
+ attach_function :getpwuid_r, [:long, :pointer, :pointer, :size_t], :pointer
18
+ attach_function :getpwent_r, [:pointer, :pointer, :int], :pointer
19
+ attach_function :getgrent_r, [:pointer, :pointer, :int], :pointer
20
+ attach_function :getgrnam_r, [:string, :pointer, :pointer, :int], :pointer
21
+ attach_function :getgrgid_r, [:long, :pointer, :pointer, :int], :pointer
22
+
23
+ private_class_method :getlogin_r, :getpwnam_r, :getpwuid_r, :getpwent_r
24
+ private_class_method :getgrent_r, :getgrnam_r, :getgrgid_r
25
+ private_class_method :open_c, :pread_c, :close_c
26
+
27
+ # struct passwd from /usr/include/pwd.h
28
+ class PasswdStruct < FFI::Struct
29
+ layout(
30
+ :pw_name, :string,
31
+ :pw_passwd, :string,
32
+ :pw_uid, :uint,
33
+ :pw_gid, :uint,
34
+ :pw_age, :string,
35
+ :pw_comment, :string,
36
+ :pw_gecos, :string,
37
+ :pw_dir, :string,
38
+ :pw_shell, :string
39
+ )
40
+ end
41
+
42
+ # struct group from /usr/include/grp.h
43
+ class GroupStruct < FFI::Struct
44
+ layout(
45
+ :gr_name, :string,
46
+ :gr_passwd, :string,
47
+ :gr_gid, :uint,
48
+ :gr_mem, :pointer
49
+ )
50
+ end
51
+
52
+ # I'm blending the timeval struct in directly here
53
+ class LastlogStruct < FFI::Struct
54
+ layout(
55
+ :ll_time, :uint,
56
+ :ll_line, [:char, 32],
57
+ :ll_host, [:char, 256]
58
+ )
59
+ end
60
+
61
+ public
62
+
63
+ # Returns the login for the current process.
64
+ #
65
+ def self.get_login
66
+ buf = FFI::MemoryPointer.new(:char, 256)
67
+
68
+ ptr = getlogin_r(buf, buf.size)
69
+
70
+ if ptr.null?
71
+ raise Error, "getlogin_r function failed: " + strerror(FFI.errno)
72
+ end
73
+
74
+ buf.read_string
75
+ end
76
+
77
+ # Returns a User object for the given name or uid. Raises an error
78
+ # if a user cannot be found.
79
+ #
80
+ # Examples:
81
+ #
82
+ # Sys::Admin.get_user('joe')
83
+ # Sys::Admin.get_user(501)
84
+ #
85
+ def self.get_user(uid)
86
+ buf = FFI::MemoryPointer.new(:char, 1024)
87
+ temp = PasswdStruct.new
88
+
89
+ if uid.is_a?(String)
90
+ ptr = getpwnam_r(uid, temp, buf, buf.size)
91
+ else
92
+ ptr = getpwuid_r(uid, temp, buf, buf.size)
93
+ end
94
+
95
+ if ptr.null?
96
+ raise Error, "getpwnam_r or getpwuid_r function failed: " + strerror(FFI.errno)
97
+ end
98
+
99
+ pwd = PasswdStruct.new(ptr)
100
+ get_user_from_struct(pwd)
101
+ end
102
+
103
+ # Returns a Group object for the given name or uid. Raises an error
104
+ # if a group cannot be found.
105
+ #
106
+ # Examples:
107
+ #
108
+ # Sys::Admin.get_group('admin')
109
+ # Sys::Admin.get_group(101)
110
+ #
111
+ def self.get_group(gid)
112
+ buf = FFI::MemoryPointer.new(:char, 1024)
113
+ temp = GroupStruct.new
114
+
115
+ if gid.is_a?(String)
116
+ ptr = getgrnam_r(gid, temp, buf, buf.size)
117
+ else
118
+ ptr = getgrgid_r(gid, temp, buf, buf.size)
119
+ end
120
+
121
+ if ptr.null?
122
+ raise Error, "getgrnam_r or getgrgid_r function failed: " + strerror(FFI.errno)
123
+ end
124
+
125
+ grp = GroupStruct.new(ptr)
126
+ get_group_from_struct(grp)
127
+ end
128
+
129
+ # Returns an array of User objects for each user on the system.
130
+ #
131
+ def self.users
132
+ users = []
133
+
134
+ buf = FFI::MemoryPointer.new(:char, 1024)
135
+ temp = PasswdStruct.new
136
+
137
+ begin
138
+ setpwent()
139
+
140
+ while !(ptr = getpwent_r(temp, buf, buf.size)).null?
141
+ break if ptr.null?
142
+
143
+ pwd = PasswdStruct.new(ptr)
144
+ users << get_user_from_struct(pwd)
145
+ end
146
+ ensure
147
+ endpwent()
148
+ end
149
+
150
+ users
151
+ end
152
+
153
+ # Returns an array of Group objects for each user on the system.
154
+ #
155
+ def self.groups
156
+ groups = []
157
+
158
+ buf = FFI::MemoryPointer.new(:char, 1024)
159
+ temp = GroupStruct.new
160
+
161
+ begin
162
+ setgrent()
163
+
164
+ while !(ptr = getgrent_r(temp, buf, buf.size)).null?
165
+ break if ptr.null?
166
+
167
+ grp = GroupStruct.new(ptr)
168
+ groups << get_group_from_struct(grp)
169
+ end
170
+ ensure
171
+ endgrent()
172
+ end
173
+
174
+ groups
175
+ end
176
+
177
+ private
178
+
179
+ # Takes a GroupStruct and converts it to a Group object.
180
+ def self.get_group_from_struct(grp)
181
+ Group.new do |g|
182
+ g.name = grp[:gr_name]
183
+ g.passwd = grp[:gr_passwd]
184
+ g.gid = grp[:gr_gid]
185
+ g.members = grp[:gr_mem].read_array_of_string
186
+ end
187
+ end
188
+
189
+ # Takes a UserStruct and converts it to a User object.
190
+ def self.get_user_from_struct(pwd)
191
+ user = User.new do |u|
192
+ u.name = pwd[:pw_name]
193
+ u.passwd = pwd[:pw_passwd]
194
+ u.uid = pwd[:pw_uid]
195
+ u.gid = pwd[:pw_gid]
196
+ u.gecos = pwd[:pw_gecos]
197
+ u.dir = pwd[:pw_dir]
198
+ u.shell = pwd[:pw_shell]
199
+ end
200
+
201
+ log = get_lastlog_info(user.uid)
202
+
203
+ if log
204
+ login_device = log[:ll_line].to_s
205
+ login_host = log[:ll_host].to_s
206
+
207
+ user.login_time = Time.at(log[:ll_time]) if log[:ll_time] > 0
208
+ user.login_device = login_device unless login_device.empty?
209
+ user.login_host = login_host unless login_host.empty?
210
+ end
211
+
212
+ user
213
+ end
214
+
215
+ # The use of pread was necessary here because it's a sparse file. Note
216
+ # also that while Solaris supports the getuserattr function, it doesn't
217
+ # appear to store anything regarding login information.
218
+ #
219
+ def self.get_lastlog_info(uid)
220
+ logfile = '/var/adm/lastlog'
221
+ lastlog = LastlogStruct.new
222
+
223
+ begin
224
+ fd = open_c(logfile, File::RDONLY)
225
+
226
+ if fd != -1
227
+ bytes = pread_c(fd, lastlog, lastlog.size, uid * lastlog.size)
228
+ if bytes < 0
229
+ raise Error, "pread function failed: " + strerror(FFI.errno)
230
+ end
231
+ else
232
+ nil # Ignore, improper permissions
233
+ end
234
+ ensure
235
+ close_c(fd) if fd && fd >= 0
236
+ end
237
+
238
+ lastlog
239
+ end
240
+ end
241
+ end
data/lib/sys/admin.rb ADDED
@@ -0,0 +1,17 @@
1
+ # Stub to require the correct based on platform
2
+ require 'rbconfig'
3
+
4
+ case RbConfig::CONFIG['host_os']
5
+ when /linux/i
6
+ require 'linux/sys/admin'
7
+ when /sunos|solaris/i
8
+ require 'sunos/sys/admin'
9
+ when /cygwin|mingw|mswin|windows|dos/i
10
+ require 'windows/sys/admin'
11
+ when /darwin|mach/i
12
+ require 'darwin/sys/admin'
13
+ when /bsd/i
14
+ require 'bsd/sys/admin'
15
+ else
16
+ require 'unix/sys/admin'
17
+ end
@@ -0,0 +1,140 @@
1
+ require 'ffi'
2
+
3
+ # The Sys module serves as a namespace only.
4
+ module Sys
5
+
6
+ # The Admin class provides a unified, cross platform replacement
7
+ # for the Etc module.
8
+ class Admin
9
+ extend FFI::Library
10
+ ffi_lib FFI::Library::LIBC
11
+
12
+ private
13
+
14
+ attach_function :strerror, [:int], :string
15
+
16
+ attach_function :getlogin, [], :string
17
+ attach_function :getuid, [], :long
18
+ attach_function :getpwnam, [:string], :pointer
19
+ attach_function :getpwuid, [:long], :pointer
20
+ attach_function :getpwent, [], :pointer
21
+ attach_function :setpwent, [], :void
22
+ attach_function :endpwent, [], :void
23
+
24
+ attach_function :getgrgid, [:long], :pointer
25
+ attach_function :getgrnam, [:string], :pointer
26
+ attach_function :getgrent, [], :pointer
27
+ attach_function :endgrent, [], :void
28
+ attach_function :setgrent, [], :void
29
+
30
+ private_class_method :getlogin, :getuid, :getpwnam, :getpwuid, :getpwent
31
+ private_class_method :setpwent, :endpwent, :getgrgid, :getgrnam
32
+ private_class_method :getgrent, :endgrent, :setgrent, :strerror
33
+
34
+ public
35
+
36
+ # The version of the sys-admin library.
37
+ VERSION = '1.6.0'
38
+
39
+ # Error typically raised if any of the Sys::Admin methods fail.
40
+ class Error < StandardError; end
41
+
42
+ # The User class encapsulates the information found in /etc/passwd.
43
+ class User
44
+ # The user name associated with the account.
45
+ attr_accessor :name
46
+
47
+ # The user's encrypted password. Deprecated by /etc/shadow.
48
+ attr_accessor :passwd
49
+
50
+ # The user's user ID.
51
+ attr_accessor :uid
52
+
53
+ # The user's group ID.
54
+ attr_accessor :gid
55
+
56
+ # Next date a password change will be needed.
57
+ attr_accessor :change
58
+
59
+ # A comment field. Rarely used now.
60
+ attr_accessor :gecos
61
+
62
+ # The user's alloted amount of disk space.
63
+ attr_accessor :quota
64
+
65
+ # The absolute path name of the user's home directory.
66
+ attr_accessor :dir
67
+
68
+ # The user's login shell.
69
+ attr_accessor :shell
70
+
71
+ # The account's expiration date
72
+ attr_accessor :expire
73
+
74
+ # TODO: Forgot what this is.
75
+ attr_accessor :fields
76
+
77
+ # The user's access class.
78
+ attr_accessor :access_class
79
+
80
+ # Another comment field.
81
+ attr_accessor :comment
82
+
83
+ # Used in the past for password aging. Deprecated by /etc/shadow.
84
+ attr_accessor :age
85
+
86
+ # The last time the user logged in.
87
+ attr_accessor :login_time
88
+
89
+ # The host name from which the user last logged in.
90
+ attr_accessor :login_host
91
+
92
+ # The name of the terminal device the user last logged on with.
93
+ attr_accessor :login_device
94
+
95
+ # Creates and returns a User object, which encapsulates the information
96
+ # typically found within an /etc/passwd entry, i.e. a struct passwd.
97
+ #
98
+ # If a block is provided, yields the object back to the block.
99
+ #
100
+ def initialize
101
+ yield self if block_given?
102
+ end
103
+
104
+ # An array of groups to which the user belongs.
105
+ def groups
106
+ array = []
107
+
108
+ Sys::Admin.groups.each{ |grp|
109
+ array << grp.name if grp.members.include?(self.name)
110
+ }
111
+
112
+ array
113
+ end
114
+ end
115
+
116
+ # The Group class encapsulates information found in /etc/group.
117
+ class Group
118
+ # The name of the group.
119
+ attr_accessor :name
120
+
121
+ # The group's group ID.
122
+ attr_accessor :gid
123
+
124
+ # An array of members associated with the group.
125
+ attr_accessor :members
126
+
127
+ # The group password, if any.
128
+ attr_accessor :passwd
129
+
130
+ # Creates and returns a Group object, which encapsulates the information
131
+ # typically found within an /etc/group entry, i.e. a struct group.
132
+ #
133
+ # If a block is provided, yields the object back to the block.
134
+ #
135
+ def initialize
136
+ yield self if block_given?
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,16 @@
1
+ require 'ffi'
2
+
3
+ class FFI::Pointer
4
+ def read_array_of_string
5
+ elements = []
6
+
7
+ loc = self
8
+
9
+ until ((element = loc.read_pointer).null?)
10
+ elements << element.read_string
11
+ loc += FFI::Type::POINTER.size
12
+ end
13
+
14
+ elements
15
+ end
16
+ end
@@ -0,0 +1,164 @@
1
+ require 'sys/admin/custom'
2
+ require 'sys/admin/common'
3
+
4
+ # Code used as a fallback for UNIX platforms.
5
+
6
+ module Sys
7
+ class Admin
8
+
9
+ private
10
+
11
+ class PasswdStruct < FFI::Struct
12
+ layout(
13
+ :pw_name, :string,
14
+ :pw_passwd, :string,
15
+ :pw_uid, :uint,
16
+ :pw_gid, :uint,
17
+ :pw_gecos, :string,
18
+ :pw_dir, :string,
19
+ :pw_shell, :string
20
+ )
21
+ end
22
+
23
+ class GroupStruct < FFI::Struct
24
+ layout(
25
+ :gr_name, :string,
26
+ :gr_passwd, :string,
27
+ :gr_gid, :uint,
28
+ :gr_mem, :pointer
29
+ )
30
+ end
31
+
32
+ public
33
+
34
+ # Returns the login for the current process.
35
+ #
36
+ def self.get_login
37
+ getlogin()
38
+ end
39
+
40
+ # Returns a User object for the given name or uid. Raises an error
41
+ # if a user cannot be found.
42
+ #
43
+ # Examples:
44
+ #
45
+ # Sys::Admin.get_user('joe')
46
+ # Sys::Admin.get_user(501)
47
+ #
48
+ def self.get_user(uid)
49
+ if uid.is_a?(String)
50
+ pwd = PasswdStruct.new(getpwnam(uid))
51
+ else
52
+ pwd = PasswdStruct.new(getpwuid(uid))
53
+ end
54
+
55
+ if pwd.null?
56
+ raise Error, "no user found for: #{uid}"
57
+ end
58
+
59
+ user = User.new do |u|
60
+ u.name = pwd[:pw_name]
61
+ u.passwd = pwd[:pw_passwd]
62
+ u.uid = pwd[:pw_uid]
63
+ u.gid = pwd[:pw_gid]
64
+ u.gecos = pwd[:pw_gecos]
65
+ u.dir = pwd[:pw_dir]
66
+ u.shell = pwd[:pw_shell]
67
+ end
68
+
69
+ user
70
+ end
71
+
72
+ # Returns a Group object for the given name or uid. Raises an error
73
+ # if a group cannot be found.
74
+ #
75
+ # Examples:
76
+ #
77
+ # Sys::Admin.get_group('admin')
78
+ # Sys::Admin.get_group(101)
79
+ #
80
+ def self.get_group(gid)
81
+ if gid.is_a?(String)
82
+ grp = GroupStruct.new(getgrnam(gid))
83
+ else
84
+ grp = GroupStruct.new(getgrgid(gid))
85
+ end
86
+
87
+ if grp.null?
88
+ raise Error, "no group found for: #{gid}"
89
+ end
90
+
91
+ Group.new do |g|
92
+ g.name = grp[:gr_name]
93
+ g.passwd = grp[:gr_passwd]
94
+ g.gid = grp[:gr_gid]
95
+ g.members = grp[:gr_mem].read_array_of_string
96
+ end
97
+ end
98
+
99
+ # Returns an array of User objects for each user on the system.
100
+ #
101
+ def self.users
102
+ users = []
103
+
104
+ begin
105
+ setpwent()
106
+
107
+ until (ptr = getpwent()).null?
108
+ pwd = PasswdStruct.new(ptr)
109
+ users << get_user_from_struct(pwd)
110
+ end
111
+ ensure
112
+ endpwent()
113
+ end
114
+
115
+ users
116
+ end
117
+
118
+ # Returns an array of Group objects for each user on the system.
119
+ #
120
+ def self.groups
121
+ groups = []
122
+
123
+ begin
124
+ setgrent()
125
+
126
+ until (ptr = getgrent()).null?
127
+ grp = GroupStruct.new(ptr)
128
+ groups << get_group_from_struct(grp)
129
+ end
130
+ ensure
131
+ endgrent()
132
+ end
133
+
134
+ groups
135
+ end
136
+
137
+ private
138
+
139
+ # Takes a GroupStruct and converts it to a Group object.
140
+ def self.get_group_from_struct(grp)
141
+ Group.new do |g|
142
+ g.name = grp[:gr_name]
143
+ g.passwd = grp[:gr_passwd]
144
+ g.gid = grp[:gr_gid]
145
+ g.members = grp[:gr_mem].read_array_of_string
146
+ end
147
+ end
148
+
149
+ # Takes a UserStruct and converts it to a User object.
150
+ def self.get_user_from_struct(pwd)
151
+ user = User.new do |u|
152
+ u.name = pwd[:pw_name]
153
+ u.passwd = pwd[:pw_passwd]
154
+ u.uid = pwd[:pw_uid]
155
+ u.gid = pwd[:pw_gid]
156
+ u.gecos = pwd[:pw_gecos]
157
+ u.dir = pwd[:pw_dir]
158
+ u.shell = pwd[:pw_shell]
159
+ end
160
+
161
+ user
162
+ end
163
+ end
164
+ end