sys-admin 1.5.6 → 1.6.0

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