sys-admin 1.8.0-universal-mingw32

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