sys-admin 1.7.0 → 1.7.1

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.
@@ -1,237 +1,237 @@
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
- # :no-doc:
11
- BUF_MAX = 65536 # Max buf size for retry.
12
-
13
- attach_function :getlogin_r, [:pointer, :int], :int
14
- attach_function :getpwnam_r, [:string, :pointer, :pointer, :size_t, :pointer], :int
15
- attach_function :getpwuid_r, [:long, :pointer, :pointer, :size_t, :pointer], :int
16
- attach_function :getgrnam_r, [:string, :pointer, :pointer, :size_t, :pointer], :int
17
- attach_function :getgrgid_r, [:long, :pointer, :pointer, :size_t, :pointer], :int
18
- attach_function :getlastlogx, [:long, :pointer], :pointer
19
-
20
- private_class_method :getlogin_r, :getpwnam_r, :getpwuid_r, :getgrnam_r
21
- private_class_method :getgrgid_r, :getlastlogx
22
-
23
- # struct passwd from /usr/include/pwd.h
24
- class PasswdStruct < FFI::Struct
25
- layout(
26
- :pw_name, :string,
27
- :pw_passwd, :string,
28
- :pw_uid, :uint,
29
- :pw_gid, :uint,
30
- :pw_change, :ulong,
31
- :pw_class, :string,
32
- :pw_gecos, :string,
33
- :pw_dir, :string,
34
- :pw_shell, :string,
35
- :pw_expire, :ulong
36
- )
37
- end
38
-
39
- # struct group from /usr/include/grp.h
40
- class GroupStruct < FFI::Struct
41
- layout(
42
- :gr_name, :string,
43
- :gr_passwd, :string,
44
- :gr_gid, :uint,
45
- :gr_mem, :pointer
46
- )
47
- end
48
-
49
- # I'm blending the timeval struct in directly here
50
- class LastlogxStruct < FFI::Struct
51
- layout(
52
- :tv_sec, :long,
53
- :tv_usec, :long,
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
- size = 1024
116
- buf = FFI::MemoryPointer.new(:char, size)
117
- pbuf = FFI::MemoryPointer.new(PasswdStruct)
118
- temp = GroupStruct.new
119
-
120
- begin
121
- if gid.is_a?(String)
122
- val = getgrnam_r(gid, temp, buf, buf.size, pbuf)
123
- fun = 'getgrnam_r'
124
- else
125
- val = getgrgid_r(gid, temp, buf, buf.size, pbuf)
126
- fun = 'getgrgid_r'
127
- end
128
- raise SystemCallError.new(fun, val) if val != 0
129
- rescue Errno::ERANGE
130
- size += 1024
131
- raise if size > BUF_MAX
132
- buf = FFI::MemoryPointer.new(:char, size)
133
- retry
134
- end
135
-
136
- ptr = pbuf.read_pointer
137
-
138
- if ptr.null?
139
- raise Error, "no group found for '#{gid}'"
140
- end
141
-
142
- grp = GroupStruct.new(ptr)
143
- get_group_from_struct(grp)
144
- end
145
-
146
- # Returns an array of User objects for each user on the system.
147
- #
148
- #--
149
- # This method is somewhat slow on OSX because of the call to get
150
- # lastlog information. I'm not sure why.
151
- #
152
- def self.users
153
- users = []
154
-
155
- begin
156
- setpwent()
157
-
158
- until (ptr = getpwent()).null?
159
- pwd = PasswdStruct.new(ptr)
160
- users << get_user_from_struct(pwd)
161
- end
162
- ensure
163
- endpwent()
164
- end
165
-
166
- users
167
- end
168
-
169
- # Returns an array of Group objects for each user on the system.
170
- #
171
- def self.groups
172
- groups = []
173
-
174
- begin
175
- setgrent()
176
-
177
- until (ptr = getgrent()).null?
178
- grp = GroupStruct.new(ptr)
179
- groups << get_group_from_struct(grp)
180
- end
181
- ensure
182
- endgrent()
183
- end
184
-
185
- groups
186
- end
187
-
188
- private
189
-
190
- # Takes a GroupStruct and converts it to a Group object.
191
- def self.get_group_from_struct(grp)
192
- Group.new do |g|
193
- g.name = grp[:gr_name]
194
- g.passwd = grp[:gr_passwd]
195
- g.gid = grp[:gr_gid]
196
- g.members = grp[:gr_mem].read_array_of_string
197
- end
198
- end
199
-
200
- # Takes a UserStruct and converts it to a User object.
201
- def self.get_user_from_struct(pwd)
202
- user = User.new do |u|
203
- u.name = pwd[:pw_name]
204
- u.passwd = pwd[:pw_passwd]
205
- u.uid = pwd[:pw_uid]
206
- u.gid = pwd[:pw_gid]
207
- u.change = Time.at(pwd[:pw_change])
208
- u.access_class = pwd[:pw_class]
209
- u.gecos = pwd[:pw_gecos]
210
- u.dir = pwd[:pw_dir]
211
- u.shell = pwd[:pw_shell]
212
- u.expire = Time.at(pwd[:pw_expire])
213
- end
214
-
215
- log = get_lastlog_info(user.uid)
216
-
217
- if log
218
- user.login_time = Time.at(log[:tv_sec])
219
- user.login_device = log[:ll_line].to_s
220
- user.login_host = log[:ll_host].to_s
221
- end
222
-
223
- user
224
- end
225
-
226
- # Gets lastlog information for the given user.
227
- def self.get_lastlog_info(uid)
228
- lastlog = LastlogxStruct.new
229
-
230
- # We don't check for failure here because most will fail due to
231
- # lack of permissions and/or simple lack of information.
232
- ptr = getlastlogx(uid, lastlog)
233
-
234
- ptr.null? ? nil : lastlog
235
- end
236
- end
237
- end
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
+ # :no-doc:
11
+ BUF_MAX = 65536 # Max buf size for retry.
12
+
13
+ attach_function :getlogin_r, [:pointer, :int], :int
14
+ attach_function :getpwnam_r, [:string, :pointer, :pointer, :size_t, :pointer], :int
15
+ attach_function :getpwuid_r, [:long, :pointer, :pointer, :size_t, :pointer], :int
16
+ attach_function :getgrnam_r, [:string, :pointer, :pointer, :size_t, :pointer], :int
17
+ attach_function :getgrgid_r, [:long, :pointer, :pointer, :size_t, :pointer], :int
18
+ attach_function :getlastlogx, [:long, :pointer], :pointer
19
+
20
+ private_class_method :getlogin_r, :getpwnam_r, :getpwuid_r, :getgrnam_r
21
+ private_class_method :getgrgid_r, :getlastlogx
22
+
23
+ # struct passwd from /usr/include/pwd.h
24
+ class PasswdStruct < FFI::Struct
25
+ layout(
26
+ :pw_name, :string,
27
+ :pw_passwd, :string,
28
+ :pw_uid, :uint,
29
+ :pw_gid, :uint,
30
+ :pw_change, :ulong,
31
+ :pw_class, :string,
32
+ :pw_gecos, :string,
33
+ :pw_dir, :string,
34
+ :pw_shell, :string,
35
+ :pw_expire, :ulong
36
+ )
37
+ end
38
+
39
+ # struct group from /usr/include/grp.h
40
+ class GroupStruct < FFI::Struct
41
+ layout(
42
+ :gr_name, :string,
43
+ :gr_passwd, :string,
44
+ :gr_gid, :uint,
45
+ :gr_mem, :pointer
46
+ )
47
+ end
48
+
49
+ # I'm blending the timeval struct in directly here
50
+ class LastlogxStruct < FFI::Struct
51
+ layout(
52
+ :tv_sec, :long,
53
+ :tv_usec, :long,
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
+ size = 1024
116
+ buf = FFI::MemoryPointer.new(:char, size)
117
+ pbuf = FFI::MemoryPointer.new(PasswdStruct)
118
+ temp = GroupStruct.new
119
+
120
+ begin
121
+ if gid.is_a?(String)
122
+ val = getgrnam_r(gid, temp, buf, buf.size, pbuf)
123
+ fun = 'getgrnam_r'
124
+ else
125
+ val = getgrgid_r(gid, temp, buf, buf.size, pbuf)
126
+ fun = 'getgrgid_r'
127
+ end
128
+ raise SystemCallError.new(fun, val) if val != 0
129
+ rescue Errno::ERANGE
130
+ size += 1024
131
+ raise if size > BUF_MAX
132
+ buf = FFI::MemoryPointer.new(:char, size)
133
+ retry
134
+ end
135
+
136
+ ptr = pbuf.read_pointer
137
+
138
+ if ptr.null?
139
+ raise Error, "no group found for '#{gid}'"
140
+ end
141
+
142
+ grp = GroupStruct.new(ptr)
143
+ get_group_from_struct(grp)
144
+ end
145
+
146
+ # Returns an array of User objects for each user on the system.
147
+ #
148
+ #--
149
+ # This method is somewhat slow on OSX because of the call to get
150
+ # lastlog information. I'm not sure why.
151
+ #
152
+ def self.users
153
+ users = []
154
+
155
+ begin
156
+ setpwent()
157
+
158
+ until (ptr = getpwent()).null?
159
+ pwd = PasswdStruct.new(ptr)
160
+ users << get_user_from_struct(pwd)
161
+ end
162
+ ensure
163
+ endpwent()
164
+ end
165
+
166
+ users
167
+ end
168
+
169
+ # Returns an array of Group objects for each user on the system.
170
+ #
171
+ def self.groups
172
+ groups = []
173
+
174
+ begin
175
+ setgrent()
176
+
177
+ until (ptr = getgrent()).null?
178
+ grp = GroupStruct.new(ptr)
179
+ groups << get_group_from_struct(grp)
180
+ end
181
+ ensure
182
+ endgrent()
183
+ end
184
+
185
+ groups
186
+ end
187
+
188
+ private
189
+
190
+ # Takes a GroupStruct and converts it to a Group object.
191
+ def self.get_group_from_struct(grp)
192
+ Group.new do |g|
193
+ g.name = grp[:gr_name]
194
+ g.passwd = grp[:gr_passwd]
195
+ g.gid = grp[:gr_gid]
196
+ g.members = grp[:gr_mem].read_array_of_string
197
+ end
198
+ end
199
+
200
+ # Takes a UserStruct and converts it to a User object.
201
+ def self.get_user_from_struct(pwd)
202
+ user = User.new do |u|
203
+ u.name = pwd[:pw_name]
204
+ u.passwd = pwd[:pw_passwd]
205
+ u.uid = pwd[:pw_uid]
206
+ u.gid = pwd[:pw_gid]
207
+ u.change = Time.at(pwd[:pw_change])
208
+ u.access_class = pwd[:pw_class]
209
+ u.gecos = pwd[:pw_gecos]
210
+ u.dir = pwd[:pw_dir]
211
+ u.shell = pwd[:pw_shell]
212
+ u.expire = Time.at(pwd[:pw_expire])
213
+ end
214
+
215
+ log = get_lastlog_info(user.uid)
216
+
217
+ if log
218
+ user.login_time = Time.at(log[:tv_sec])
219
+ user.login_device = log[:ll_line].to_s
220
+ user.login_host = log[:ll_host].to_s
221
+ end
222
+
223
+ user
224
+ end
225
+
226
+ # Gets lastlog information for the given user.
227
+ def self.get_lastlog_info(uid)
228
+ lastlog = LastlogxStruct.new
229
+
230
+ # We don't check for failure here because most will fail due to
231
+ # lack of permissions and/or simple lack of information.
232
+ ptr = getlastlogx(uid, lastlog)
233
+
234
+ ptr.null? ? nil : lastlog
235
+ end
236
+ end
237
+ end