sys-admin 1.6.4 → 1.7.0

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