sys-admin 1.8.0-universal-mingw32

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,272 @@
1
+ require 'sys/admin/custom'
2
+ require 'sys/admin/common'
3
+
4
+ # The Linux specific code.
5
+
6
+ module Sys
7
+ class Admin
8
+ # :no-doc:
9
+ BUF_MAX = 65536 # Absolute max buffer size for retry attempts.
10
+ private_constant :BUF_MAX
11
+
12
+ # I'm making some aliases here to prevent potential conflicts
13
+ attach_function :open_c, :open, [:string, :int], :int
14
+ attach_function :pread_c, :pread, [:int, :pointer, :size_t, :off_t], :size_t
15
+ attach_function :close_c, :close, [:int], :int
16
+
17
+ attach_function :getpwnam_r, [:string, :pointer, :pointer, :size_t, :pointer], :int
18
+ attach_function :getpwuid_r, [:long, :pointer, :pointer, :size_t, :pointer], :int
19
+ attach_function :getpwent_r, [:pointer, :pointer, :size_t, :pointer], :int
20
+ attach_function :getgrent_r, [:pointer, :pointer, :size_t, :pointer], :int
21
+ attach_function :getgrnam_r, [:string, :pointer, :pointer, :size_t, :pointer], :int
22
+ attach_function :getgrgid_r, [:long, :pointer, :pointer, :size_t, :pointer], :int
23
+
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_gecos, :string,
35
+ :pw_dir, :string,
36
+ :pw_shell, :string
37
+ )
38
+ end
39
+
40
+ private_constant :PasswdStruct
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
+ private_constant :GroupStruct
53
+
54
+ # I'm blending the timeval struct in directly here
55
+ class LastlogStruct < FFI::Struct
56
+ layout(
57
+ :ll_time, :uint,
58
+ :ll_line, [:char, 32],
59
+ :ll_host, [:char, 256]
60
+ )
61
+ end
62
+
63
+ private_constant :LastlogStruct
64
+
65
+ # Returns the login for the current process.
66
+ #
67
+ def self.get_login
68
+ get_user(geteuid()).name
69
+ end
70
+
71
+ # Returns a User object for the given name or uid. Raises an error
72
+ # if a user cannot be found.
73
+ #
74
+ # Examples:
75
+ #
76
+ # Sys::Admin.get_user('joe')
77
+ # Sys::Admin.get_user(501)
78
+ #
79
+ def self.get_user(uid)
80
+ buf = FFI::MemoryPointer.new(:char, 1024)
81
+ pbuf = FFI::MemoryPointer.new(PasswdStruct)
82
+ temp = PasswdStruct.new
83
+
84
+ if uid.is_a?(String)
85
+ if getpwnam_r(uid, temp, buf, buf.size, pbuf) != 0
86
+ raise Error, "getpwnam_r function failed: " + strerror(FFI.errno)
87
+ end
88
+ else
89
+ if getpwuid_r(uid, temp, buf, buf.size, pbuf) != 0
90
+ raise Error, "getpwuid_r function failed: " + strerror(FFI.errno)
91
+ end
92
+ end
93
+
94
+ ptr = pbuf.read_pointer
95
+
96
+ if ptr.null?
97
+ raise Error, "no user found for #{uid}"
98
+ end
99
+
100
+ pwd = PasswdStruct.new(ptr)
101
+ get_user_from_struct(pwd)
102
+ end
103
+
104
+ # Returns a Group object for the given name or uid. Raises an error
105
+ # if a group cannot be found.
106
+ #
107
+ # Examples:
108
+ #
109
+ # Sys::Admin.get_group('admin')
110
+ # Sys::Admin.get_group(101)
111
+ #--
112
+ # For groups with a large number of members we retry, allocating another
113
+ # 1k on each retry attempt, up to a maximum of 64k, which ought to be way
114
+ # more than you'll ever need.
115
+ #
116
+ def self.get_group(gid)
117
+ size = 1024
118
+ buf = FFI::MemoryPointer.new(:char, size)
119
+ pbuf = FFI::MemoryPointer.new(PasswdStruct)
120
+ temp = GroupStruct.new
121
+
122
+ begin
123
+ if gid.is_a?(String)
124
+ val = getgrnam_r(gid, temp, buf, buf.size, pbuf)
125
+ fun = 'getgrnam_r'
126
+ else
127
+ val = getgrgid_r(gid, temp, buf, buf.size, pbuf)
128
+ fun = 'getgrgid_r'
129
+ end
130
+ raise SystemCallError.new(fun, val) if val != 0
131
+ rescue Errno::ERANGE # Large groups
132
+ size += 1024
133
+ raise if size > BUF_MAX
134
+ buf = FFI::MemoryPointer.new(:char, size)
135
+ retry
136
+ end
137
+
138
+ ptr = pbuf.read_pointer
139
+
140
+ if ptr.null?
141
+ raise Error, "no group found for '#{gid}'"
142
+ end
143
+
144
+ grp = GroupStruct.new(ptr)
145
+ get_group_from_struct(grp)
146
+ end
147
+
148
+ # Returns an array of User objects for each user on the system.
149
+ #
150
+ def self.users
151
+ users = []
152
+
153
+ buf = FFI::MemoryPointer.new(:char, 1024)
154
+ pbuf = FFI::MemoryPointer.new(PasswdStruct)
155
+ temp = PasswdStruct.new
156
+
157
+ begin
158
+ setpwent()
159
+
160
+ while getpwent_r(temp, buf, buf.size, pbuf) == 0
161
+ ptr = pbuf.read_pointer
162
+
163
+ break if ptr.null?
164
+
165
+ pwd = PasswdStruct.new(ptr)
166
+ users << get_user_from_struct(pwd)
167
+ end
168
+ ensure
169
+ endpwent()
170
+ end
171
+
172
+ users
173
+ end
174
+
175
+ # Returns an array of Group objects for each user on the system.
176
+ #
177
+ def self.groups
178
+ groups = []
179
+
180
+ buf = FFI::MemoryPointer.new(:char, 1024)
181
+ pbuf = FFI::MemoryPointer.new(GroupStruct)
182
+ temp = GroupStruct.new
183
+
184
+ begin
185
+ setgrent()
186
+
187
+ while getgrent_r(temp, buf, buf.size, pbuf) == 0
188
+ ptr = pbuf.read_pointer
189
+
190
+ break if ptr.null?
191
+
192
+ grp = GroupStruct.new(ptr)
193
+ groups << get_group_from_struct(grp)
194
+ end
195
+ ensure
196
+ endgrent()
197
+ end
198
+
199
+ groups
200
+ end
201
+
202
+ # Takes a GroupStruct and converts it to a Group object.
203
+ def self.get_group_from_struct(grp)
204
+ Group.new do |g|
205
+ g.name = grp[:gr_name]
206
+ g.passwd = grp[:gr_passwd]
207
+ g.gid = grp[:gr_gid]
208
+ g.members = grp[:gr_mem].read_array_of_string
209
+ end
210
+ end
211
+
212
+ private_class_method :get_group_from_struct
213
+
214
+ # Takes a UserStruct and converts it to a User object.
215
+ def self.get_user_from_struct(pwd)
216
+ user = User.new do |u|
217
+ u.name = pwd[:pw_name]
218
+ u.passwd = pwd[:pw_passwd]
219
+ u.uid = pwd[:pw_uid]
220
+ u.gid = pwd[:pw_gid]
221
+ u.gecos = pwd[:pw_gecos]
222
+ u.dir = pwd[:pw_dir]
223
+ u.shell = pwd[:pw_shell]
224
+ end
225
+
226
+ log = get_lastlog_info(user.uid)
227
+
228
+ if log
229
+ login_device = log[:ll_line].to_s
230
+ login_host = log[:ll_host].to_s
231
+
232
+ user.login_time = Time.at(log[:ll_time]) if log[:ll_time] > 0
233
+ user.login_device = login_device unless login_device.empty?
234
+ user.login_host = login_host unless login_host.empty?
235
+ end
236
+
237
+ user
238
+ end
239
+
240
+ private_class_method :get_user_from_struct
241
+
242
+ # Note: it seems that Linux, or at least Ubuntu, does not track logins
243
+ # via GDM (Gnome Display Manager) for some reason, so this may not return
244
+ # anything useful.
245
+ #
246
+ # The use of pread was necessary here because it's a sparse file.
247
+ #
248
+ def self.get_lastlog_info(uid)
249
+ logfile = '/var/log/lastlog'
250
+ lastlog = LastlogStruct.new
251
+
252
+ begin
253
+ fd = open_c(logfile, File::RDONLY)
254
+
255
+ if fd != -1
256
+ bytes = pread_c(fd, lastlog, lastlog.size, uid * lastlog.size)
257
+ if bytes < 0
258
+ raise Error, "pread function failed: " + strerror(FFI.errno)
259
+ end
260
+ else
261
+ nil # Ignore, improper permissions
262
+ end
263
+ ensure
264
+ close_c(fd) if fd && fd >= 0
265
+ end
266
+
267
+ lastlog
268
+ end
269
+
270
+ private_class_method :get_lastlog_info
271
+ end
272
+ end
@@ -0,0 +1,268 @@
1
+ require 'sys/admin/custom'
2
+ require 'sys/admin/common'
3
+
4
+ # The Solaris specific code.
5
+
6
+ module Sys
7
+ class Admin
8
+ # :no-doc:
9
+ BUF_MAX = 65536 # Max buffer size for retry.
10
+ private_constant :BUF_MAX
11
+
12
+ # I'm making some aliases here to prevent potential conflicts
13
+ attach_function :open_c, :open, [:string, :int], :int
14
+ attach_function :pread_c, :pread, [:int, :pointer, :size_t, :off_t], :size_t
15
+ attach_function :close_c, :close, [:int], :int
16
+
17
+ attach_function :getlogin_r, [:pointer, :size_t], :pointer
18
+ attach_function :getpwnam_r, [:string, :pointer, :pointer, :size_t], :pointer
19
+ attach_function :getpwuid_r, [:long, :pointer, :pointer, :size_t], :pointer
20
+ attach_function :getpwent_r, [:pointer, :pointer, :int], :pointer
21
+ attach_function :getgrent_r, [:pointer, :pointer, :int], :pointer
22
+ attach_function :getgrnam_r, [:string, :pointer, :pointer, :int], :pointer
23
+ attach_function :getgrgid_r, [:long, :pointer, :pointer, :int], :pointer
24
+
25
+ private_class_method :getlogin_r, :getpwnam_r, :getpwuid_r, :getpwent_r
26
+ private_class_method :getgrent_r, :getgrnam_r, :getgrgid_r
27
+ private_class_method :open_c, :pread_c, :close_c
28
+
29
+ # struct passwd from /usr/include/pwd.h
30
+ class PasswdStruct < FFI::Struct
31
+ layout(
32
+ :pw_name, :string,
33
+ :pw_passwd, :string,
34
+ :pw_uid, :uint,
35
+ :pw_gid, :uint,
36
+ :pw_age, :string,
37
+ :pw_comment, :string,
38
+ :pw_gecos, :string,
39
+ :pw_dir, :string,
40
+ :pw_shell, :string
41
+ )
42
+ end
43
+
44
+ private_constant :PasswdStruct
45
+
46
+ # struct group from /usr/include/grp.h
47
+ class GroupStruct < FFI::Struct
48
+ layout(
49
+ :gr_name, :string,
50
+ :gr_passwd, :string,
51
+ :gr_gid, :uint,
52
+ :gr_mem, :pointer
53
+ )
54
+ end
55
+
56
+ private_constant :GroupStruct
57
+
58
+ # I'm blending the timeval struct in directly here
59
+ class LastlogStruct < FFI::Struct
60
+ layout(
61
+ :ll_time, :uint,
62
+ :ll_line, [:char, 32],
63
+ :ll_host, [:char, 256]
64
+ )
65
+ end
66
+
67
+ private_constant :LastlogStruct
68
+
69
+ # Returns the login for the current process.
70
+ #
71
+ def self.get_login
72
+ buf = FFI::MemoryPointer.new(:char, 256)
73
+
74
+ ptr = getlogin_r(buf, buf.size)
75
+
76
+ if ptr.null?
77
+ raise Error, "getlogin_r function failed: " + strerror(FFI.errno)
78
+ end
79
+
80
+ buf.read_string
81
+ end
82
+
83
+ # Returns a User object for the given name or uid. Raises an error
84
+ # if a user cannot be found.
85
+ #
86
+ # Examples:
87
+ #
88
+ # Sys::Admin.get_user('joe')
89
+ # Sys::Admin.get_user(501)
90
+ #
91
+ def self.get_user(uid)
92
+ buf = FFI::MemoryPointer.new(:char, 1024)
93
+ temp = PasswdStruct.new
94
+
95
+ if uid.is_a?(String)
96
+ ptr = getpwnam_r(uid, temp, buf, buf.size)
97
+ else
98
+ ptr = getpwuid_r(uid, temp, buf, buf.size)
99
+ end
100
+
101
+ if ptr.null?
102
+ raise Error, "getpwnam_r or getpwuid_r function failed: " + strerror(FFI.errno)
103
+ end
104
+
105
+ pwd = PasswdStruct.new(ptr)
106
+ get_user_from_struct(pwd)
107
+ end
108
+
109
+ # Returns a Group object for the given name or uid. Raises an error
110
+ # if a group cannot be found.
111
+ #
112
+ # Examples:
113
+ #
114
+ # Sys::Admin.get_group('admin')
115
+ # Sys::Admin.get_group(101)
116
+ #
117
+ def self.get_group(gid)
118
+ size = 1024
119
+ buf = FFI::MemoryPointer.new(:char, size)
120
+ temp = GroupStruct.new
121
+
122
+ begin
123
+ if gid.is_a?(String)
124
+ ptr = getgrnam_r(gid, temp, buf, buf.size)
125
+ fun = 'getgrnam_r'
126
+ else
127
+ ptr = getgrgid_r(gid, temp, buf, buf.size)
128
+ fun = 'getgrgid_r'
129
+ end
130
+
131
+ # SunOS distinguishes between a failed function call and a
132
+ # group that isn't found.
133
+
134
+ if ptr.null?
135
+ if FFI.errno > 0
136
+ raise SystemCallError.new(fun, FFI.errno)
137
+ else
138
+ raise Error, "group '#{gid}' not found"
139
+ end
140
+ end
141
+ rescue Errno::ERANGE
142
+ size += 1024
143
+ raise if size > BUF_MAX
144
+ buf = FFI::MemoryPointer.new(:char, size)
145
+ retry
146
+ end
147
+
148
+ grp = GroupStruct.new(ptr)
149
+ get_group_from_struct(grp)
150
+ end
151
+
152
+ # Returns an array of User objects for each user on the system.
153
+ #
154
+ def self.users
155
+ users = []
156
+
157
+ buf = FFI::MemoryPointer.new(:char, 1024)
158
+ temp = PasswdStruct.new
159
+
160
+ begin
161
+ setpwent()
162
+
163
+ while !(ptr = getpwent_r(temp, buf, buf.size)).null?
164
+ break if ptr.null?
165
+
166
+ pwd = PasswdStruct.new(ptr)
167
+ users << get_user_from_struct(pwd)
168
+ end
169
+ ensure
170
+ endpwent()
171
+ end
172
+
173
+ users
174
+ end
175
+
176
+ # Returns an array of Group objects for each user on the system.
177
+ #
178
+ def self.groups
179
+ groups = []
180
+
181
+ buf = FFI::MemoryPointer.new(:char, 1024)
182
+ temp = GroupStruct.new
183
+
184
+ begin
185
+ setgrent()
186
+
187
+ while !(ptr = getgrent_r(temp, buf, buf.size)).null?
188
+ break if ptr.null?
189
+
190
+ grp = GroupStruct.new(ptr)
191
+ groups << get_group_from_struct(grp)
192
+ end
193
+ ensure
194
+ endgrent()
195
+ end
196
+
197
+ groups
198
+ end
199
+
200
+ # Takes a GroupStruct and converts it to a Group object.
201
+ def self.get_group_from_struct(grp)
202
+ Group.new do |g|
203
+ g.name = grp[:gr_name]
204
+ g.passwd = grp[:gr_passwd]
205
+ g.gid = grp[:gr_gid]
206
+ g.members = grp[:gr_mem].read_array_of_string
207
+ end
208
+ end
209
+
210
+ private_class_method :get_group_from_struct
211
+
212
+ # Takes a UserStruct and converts it to a User object.
213
+ def self.get_user_from_struct(pwd)
214
+ user = User.new do |u|
215
+ u.name = pwd[:pw_name]
216
+ u.passwd = pwd[:pw_passwd]
217
+ u.uid = pwd[:pw_uid]
218
+ u.gid = pwd[:pw_gid]
219
+ u.gecos = pwd[:pw_gecos]
220
+ u.dir = pwd[:pw_dir]
221
+ u.shell = pwd[:pw_shell]
222
+ end
223
+
224
+ log = get_lastlog_info(user.uid)
225
+
226
+ if log
227
+ login_device = log[:ll_line].to_s
228
+ login_host = log[:ll_host].to_s
229
+
230
+ user.login_time = Time.at(log[:ll_time]) if log[:ll_time] > 0
231
+ user.login_device = login_device unless login_device.empty?
232
+ user.login_host = login_host unless login_host.empty?
233
+ end
234
+
235
+ user
236
+ end
237
+
238
+ private_class_method :get_use_from_struct
239
+
240
+ # The use of pread was necessary here because it's a sparse file. Note
241
+ # also that while Solaris supports the getuserattr function, it doesn't
242
+ # appear to store anything regarding login information.
243
+ #
244
+ def self.get_lastlog_info(uid)
245
+ logfile = '/var/adm/lastlog'
246
+ lastlog = LastlogStruct.new
247
+
248
+ begin
249
+ fd = open_c(logfile, File::RDONLY)
250
+
251
+ if fd != -1
252
+ bytes = pread_c(fd, lastlog, lastlog.size, uid * lastlog.size)
253
+ if bytes < 0
254
+ raise Error, "pread function failed: " + strerror(FFI.errno)
255
+ end
256
+ else
257
+ nil # Ignore, improper permissions
258
+ end
259
+ ensure
260
+ close_c(fd) if fd && fd >= 0
261
+ end
262
+
263
+ lastlog
264
+ end
265
+
266
+ private_class_method :get_lastlog_info
267
+ end
268
+ end