sys-admin 1.3.1-mswin32

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.
Files changed (6) hide show
  1. data/CHANGES +31 -0
  2. data/MANIFEST +17 -0
  3. data/README +174 -0
  4. data/lib/sys/admin.rb +403 -0
  5. data/test/tc_admin.rb +14 -0
  6. metadata +51 -0
data/CHANGES ADDED
@@ -0,0 +1,31 @@
1
+ == 1.3.1 - 29-Jun-2005
2
+ * Fixed a bug where the inability to read the lastlog file caused an error.
3
+ From now on that error is ignored, and the lastlog attributes of the User
4
+ object are set to nil.
5
+ * Added a beta version of Admin.delete_user (Windows only).
6
+
7
+ == 1.3.0 - 3-Jun-2005
8
+ * Bug fixes for Linux.
9
+ * Removed the version.h file - no longer needed since the Win32 version is
10
+ pure Ruby.
11
+
12
+ == 1.2.0 - 30-Apr-2005
13
+ * Replaced the Win32 version with a pure Ruby version that uses Win32API and
14
+ win32ole + WMI.
15
+ * The LocalGroup class no longer exists in the Win32 version. Instead, it is
16
+ now an attribute of a Group object. The issue was forced by WMI.
17
+ * The default for users and groups on Win32 systems is now local rather than
18
+ global. See the documentation for why you probably don't want to iterate
19
+ over global accounts.
20
+ * Corresponding doc changes and test suite changes.
21
+
22
+ == 1.1.0 - 1-Apr-2005
23
+ * Fixed bug where a segfault could occur when trying to retrieve a user or
24
+ group by an ID that didn't exist (Unix).
25
+ * Added tests for intentional failures.
26
+ * Added lastlog information tothe User class (Unix).
27
+ * Modified the way User objects are created internally (Unix).
28
+ * Fixed a bug in the User#shell attribute (Unix).
29
+
30
+ == 1.0.0 - 25-Mar-2005
31
+ * Initial release
@@ -0,0 +1,17 @@
1
+ extconf.rb
2
+ install.rb
3
+ sys-admin.gemspec
4
+ CHANGES
5
+ MANIFEST
6
+ README
7
+
8
+ examples/groups.rb
9
+ examples/users.rb
10
+
11
+ lib/sys/unix.c
12
+ lib/sys/unix.h
13
+ lib/sys/win32.rb
14
+
15
+ test/tc_admin.rb
16
+ test/tc_unix.rb
17
+ test/tc_win32.rb
data/README ADDED
@@ -0,0 +1,174 @@
1
+ == Description
2
+ The sys-admin package is a unified, cross platform replacement for the
3
+ Etc module.
4
+
5
+ == Installation
6
+ === Win32
7
+ ruby test\tc_admin.rb # optional
8
+ ruby install.rb
9
+
10
+ === Unix
11
+ ruby extconf.rb
12
+ nmake
13
+ ruby test\tc_admin.rb # optional
14
+ nmake site-install
15
+
16
+ == Synopsis
17
+ require "sys/admin"
18
+ include Sys
19
+
20
+ # Yields a User object for each user
21
+ Admin.users{ |user|
22
+ p user
23
+ }
24
+
25
+ # Returns an Array of User objects
26
+ a = Admin.users
27
+
28
+ # Yields a Group object for each group
29
+ Admin.groups{ |group|
30
+ p group
31
+ }
32
+
33
+ # Returns an Array of Group objects
34
+ g = Admin.groups
35
+
36
+ # Get information about a particular user
37
+ p Admin.get_user("nobody")
38
+
39
+ # Get information about a particular group
40
+ p Admin.get_group("adm")
41
+
42
+ == Admin
43
+ Admin.get_login
44
+ Returns the user name (only) of the current login.
45
+
46
+ Admin.get_user(name, host=localhost)
47
+ Admin.get_user(uid, host=localhost, local=true)
48
+ Returns a User object based on +name+ or +uid+.
49
+
50
+ Win32 only: you may specify a host from which information is retrieved.
51
+ The default is the local machine. You may also specify whether to
52
+ retrieve a local or global account. The default is local.
53
+
54
+ Admin.get_group(name, host=localhost, local=true)
55
+ Admin.get_group(gid, host=localhost, local=true)
56
+ Returns a Group object based on +name+ or +uid+.
57
+
58
+ Win32 only: you may specify a host from which information is retrieved.
59
+ The default is the local machine. You can retrieve either a global or
60
+ local group, depending on the value of the +local+ argument.
61
+
62
+ Admin.groups(host=localhost, local=true)
63
+ Admin.groups(host=localhost, local=true){ |group| ... }
64
+ In block form, yields a Group object for each user on the system. In
65
+ non-block form, returns an Array of Group objects.
66
+
67
+ Win32 only: you may specify a host from which information is retrieved.
68
+ The default is the local machine. You can retrieve either a global or
69
+ local group, depending on the value of the +local+ argument.
70
+
71
+ Admin.users(host=localhost, local=true)
72
+ Admin.users(host=localhost, local=true){ |user| ... }
73
+ In block form, yields a User object for each user on the system. In
74
+ non-block form, returns an Array of User objects.
75
+
76
+ Win32 only: you may specify a host from which information is retrieved.
77
+ The default is the local machine. You can retrieve either a global or
78
+ local group, depending on the value of the +local+ argument.
79
+
80
+ == User class
81
+ === User (Win32)
82
+ The User class has the following attributes on Win32 systems:
83
+
84
+ * account_type
85
+ * caption
86
+ * description
87
+ * domain
88
+ * password
89
+ * full_name
90
+ * install_date
91
+ * name
92
+ * sid
93
+ * status
94
+ * disabled?
95
+ * local?
96
+ * lockout?
97
+ * password_changeable?
98
+ * password_expires?
99
+ * password_required?
100
+
101
+ === User (Unix)
102
+ The User class has the following attributes on Unix systems:
103
+
104
+ * name
105
+ * passwd
106
+ * uid
107
+ * gid
108
+ * dir
109
+ * shell
110
+ * gecos
111
+ * quota
112
+ * age
113
+ * class
114
+ * comment
115
+ * expire
116
+
117
+ == Group Classes
118
+ === Group (Win32)
119
+ The Group class has the following attributes on Win32 systems:
120
+
121
+ * caption
122
+ * description
123
+ * domain
124
+ * install_date
125
+ * name
126
+ * sid
127
+ * status
128
+ * gid
129
+ * local?
130
+
131
+ === Group (Unix)
132
+ The Group class has the following attributes on Unix systems:
133
+
134
+ * name
135
+ * gid
136
+ * members
137
+ * passwd
138
+
139
+ == Error Classes
140
+ AdminError < StandardError
141
+ Raised if anything goes wrong with any of the above methods.
142
+
143
+ == Developer's Notes
144
+ === Win32
145
+ The Win32 version now uses a win32ole + WMI approach to getting
146
+ information. This means that the WMI service must be running on the
147
+ target machine in order to work (which it is, by default).
148
+
149
+ Note that, by default, local user and group information is retrieved
150
+ instead of global. You probably do NOT want to iterate over global users
151
+ or groups because there can be quite a few on your domain.
152
+
153
+ == Future Plans
154
+ The following methods will be added for both platforms:
155
+
156
+ * Admin.add_user
157
+ * Admin.config_user
158
+ * Admin.delete_user
159
+
160
+ == Known Bugs
161
+ None that I'm aware of. If you find any, please log them on the project
162
+ page at http://www.rubyforge.org/projects/sysutils.
163
+
164
+ == License
165
+ Ruby's
166
+
167
+ == Copyright
168
+ (C) 2005, Daniel J. Berger
169
+ All Rights Reserved
170
+
171
+ == Author
172
+ Daniel J. Berger
173
+ djberg96@yahoo.com
174
+ IRC nickname: imperator/mok/rubyhacker1
@@ -0,0 +1,403 @@
1
+ require "win32ole"
2
+ require "Win32API"
3
+ require "socket"
4
+
5
+ module Sys
6
+ class AdminError < StandardError; end
7
+
8
+ class Group
9
+ attr_accessor :caption, :description, :domain, :install_date
10
+ attr_accessor :name, :sid, :status, :gid
11
+ attr_writer :local
12
+ def initialize
13
+ yield self if block_given?
14
+ end
15
+
16
+ def local?
17
+ @local
18
+ end
19
+
20
+ def sid_type
21
+ @sid_type
22
+ end
23
+
24
+ def sid_type=(stype)
25
+ case stype
26
+ when 1
27
+ @sid_type = "user"
28
+ when 2
29
+ @sid_type = "group"
30
+ when 3
31
+ @sid_type = "domain"
32
+ when 4
33
+ @sid_type = "alias"
34
+ when 5
35
+ @sid_type = "well_known_group"
36
+ when 6
37
+ @sid_type = "deleted_account"
38
+ when 7
39
+ @sid_type = "invalid"
40
+ when 8
41
+ @sid_type = "unknown"
42
+ when 9
43
+ @sid_type = "computer"
44
+ else
45
+ @sid_type = "unknown"
46
+ end
47
+ @sid_type
48
+ end
49
+ end
50
+
51
+ class User
52
+
53
+ attr_accessor :caption, :description, :domain, :password
54
+ attr_accessor :full_name, :install_date, :name, :sid, :status
55
+ attr_writer :disabled, :local, :lockout, :password_changeable
56
+ attr_writer :password_expires, :password_required
57
+ attr_reader :account_type
58
+
59
+ def initialize
60
+ yield self if block_given?
61
+ end
62
+
63
+ def account_type=(type)
64
+ case type
65
+ when 256
66
+ @account_type = "duplicate"
67
+ when 512
68
+ @account_type = "normal"
69
+ when 2048
70
+ @account_type = "interdomain_trust"
71
+ when 4096
72
+ @account_type = "workstation_trust"
73
+ when 8192
74
+ @account_type = "server_trust"
75
+ else
76
+ @account_type = "unknown"
77
+ end
78
+ end
79
+
80
+ def sid_type
81
+ @sid_type
82
+ end
83
+
84
+ def sid_type=(stype)
85
+ case stype
86
+ when 1
87
+ @sid_type = "user"
88
+ when 2
89
+ @sid_type = "group"
90
+ when 3
91
+ @sid_type = "domain"
92
+ when 4
93
+ @sid_type = "alias"
94
+ when 5
95
+ @sid_type = "well_known_group"
96
+ when 6
97
+ @sid_type = "deleted_account"
98
+ when 7
99
+ @sid_type = "invalid"
100
+ when 8
101
+ @sid_type = "unknown"
102
+ when 9
103
+ @sid_type = "computer"
104
+ else
105
+ @sid_type = "unknown"
106
+ end
107
+ end
108
+
109
+ def disabled?
110
+ @disabled
111
+ end
112
+
113
+ def local?
114
+ @local
115
+ end
116
+
117
+ def lockout?
118
+ @lockout
119
+ end
120
+
121
+ def password_changeable?
122
+ @password_changeable
123
+ end
124
+
125
+ def password_expires?
126
+ @password_expires
127
+ end
128
+
129
+ def password_required?
130
+ @password_required
131
+ end
132
+ end
133
+
134
+ class Admin
135
+ VERSION = "1.3.1"
136
+
137
+ # Deletes +userid+ from the given +host+, or the local host if no host
138
+ # is specified.
139
+ #
140
+ def self.delete_user(userid=nil, host=Socket.gethostname)
141
+ begin
142
+ adsi = WIN32OLE.connect("WinNT://#{host},Computer")
143
+ rescue WIN32OLERuntimeError => err
144
+ raise AdminError, err
145
+ end
146
+
147
+ begin
148
+ adsi.delete("user", userid)
149
+ rescue WIN32OLERuntimeError => err
150
+ raise AdminError, err
151
+ end
152
+ end
153
+
154
+ # Returns the user name (only) of the current login.
155
+ #
156
+ def self.get_login
157
+ getlogin = Win32API.new("advapi32","GetUserName",['P','P'],'L')
158
+ buffer = "\0" * 256;
159
+ nsize = [256].pack("L")
160
+ getlogin.call(buffer,nsize)
161
+ len = nsize.unpack("L")[0]
162
+ username = buffer[0 ... len].chop
163
+ username
164
+ end
165
+
166
+ # Returns a User object based on either +name+ or +uid+.
167
+ #
168
+ # call-seq:
169
+ # get_user(name, host=localhost)
170
+ # get_user(uid, host=localhost, local=true)
171
+ #
172
+ # You may specify a +host+ from which information is retrieved. The
173
+ # default is the local machine. You may also specify whether to
174
+ # retrieve a local or global account. The default is local.
175
+ #
176
+ def self.get_user(uid, host=Socket.gethostname, local=true)
177
+ host = Socket.gethostname if host.nil?
178
+ cs = "winmgmts:{impersonationLevel=impersonate}!"
179
+ cs << "//#{host}/root/cimv2"
180
+
181
+ begin
182
+ wmi = WIN32OLE.connect(cs)
183
+ rescue WIN32OLERuntimeError => e
184
+ raise AdminError, e
185
+ end
186
+
187
+ query = "select * from win32_useraccount"
188
+ query << " where localaccount = true" if local
189
+
190
+ if uid.kind_of?(Fixnum)
191
+ if local
192
+ query << " and sid like '%-#{uid}'"
193
+ else
194
+ query << " where sid like '%-#{uid}'"
195
+ end
196
+ else
197
+ if local
198
+ query << " and name = '#{uid}'"
199
+ else
200
+ query << " where name = '#{uid}'"
201
+ end
202
+ end
203
+
204
+ wmi.execquery(query).each{ |user|
205
+ # Because our 'like' query isn't fulproof, let's parse
206
+ # the SID again to make sure
207
+ if uid.kind_of?(Fixnum)
208
+ if user.sid.split("-").last.to_i != uid
209
+ next
210
+ end
211
+ end
212
+ usr = User.new do |u|
213
+ u.account_type = user.accounttype
214
+ u.caption = user.caption
215
+ u.description = user.description
216
+ u.disabled = user.disabled
217
+ u.domain = user.domain
218
+ u.full_name = user.fullname
219
+ u.install_date = user.installdate
220
+ u.local = user.localaccount
221
+ u.lockout = user.lockout
222
+ u.name = user.name
223
+ u.password_changeable = user.passwordchangeable
224
+ u.password_expires = user.passwordexpires
225
+ u.password_required = user.passwordrequired
226
+ u.sid = user.sid
227
+ u.sid_type = user.sidtype
228
+ u.status = user.status
229
+ end
230
+ return usr
231
+ }
232
+ end
233
+
234
+ # In block form, yields a User object for each user on the system. In
235
+ # non-block form, returns an Array of User objects.
236
+ #
237
+ # call-seq:
238
+ # users(host=localhost, local=true)
239
+ # users(host=localhost, local=true){ |user| ... }
240
+ #
241
+ # You may specify a host from which information is retrieved. The
242
+ # default is the local machine. You can retrieve either a global or
243
+ # group, depending on the value of the +local+ argument.
244
+ #
245
+ def self.users(host=Socket.gethostname, local=true)
246
+ host = Socket.gethostname if host.nil?
247
+ cs = "winmgmts:{impersonationLevel=impersonate}!"
248
+ cs << "//#{host}/root/cimv2"
249
+
250
+ begin
251
+ wmi = WIN32OLE.connect(cs)
252
+ rescue WIN32OLERuntimeError => e
253
+ raise AdminError, e
254
+ end
255
+
256
+ query = "select * from win32_useraccount"
257
+ query << " where localaccount = true" if local
258
+ array = []
259
+
260
+ wmi.execquery(query).each{ |user|
261
+ usr = User.new do |u|
262
+ u.account_type = user.accounttype
263
+ u.caption = user.caption
264
+ u.description = user.description
265
+ u.disabled = user.disabled
266
+ u.domain = user.domain
267
+ u.full_name = user.fullname
268
+ u.install_date = user.installdate
269
+ u.local = user.localaccount
270
+ u.lockout = user.lockout
271
+ u.name = user.name
272
+ u.password_changeable = user.passwordchangeable
273
+ u.password_expires = user.passwordexpires
274
+ u.password_required = user.passwordrequired
275
+ u.sid = user.sid
276
+ u.sid_type = user.sidtype
277
+ u.status = user.status
278
+ end
279
+
280
+ if block_given?
281
+ yield usr
282
+ else
283
+ array.push(usr)
284
+ end
285
+ }
286
+ return array unless block_given?
287
+ end
288
+
289
+ # Returns a Group object based on either +name+ or +uid+.
290
+ #
291
+ # call-seq:
292
+ # get_group(name, host=localhost, local=true)
293
+ # get_group(gid, host=localhost, local=true)
294
+ #
295
+ # You may specify a host from which information is retrieved.
296
+ # The default is the local machine. You can retrieve either a global or
297
+ # local group, depending on the value of the +local+ argument.
298
+ #
299
+ def self.get_group(grp, host=Socket.gethostname, local=true)
300
+ host = Socket.gethostname if host.nil?
301
+ cs = "winmgmts:{impersonationLevel=impersonate}!"
302
+ cs << "//#{host}/root/cimv2"
303
+ gid = nil
304
+
305
+ begin
306
+ wmi = WIN32OLE.connect(cs)
307
+ rescue WIN32OLERuntimeError => e
308
+ raise AdminError, e
309
+ end
310
+
311
+ query = "select * from win32_group"
312
+ query << " where localaccount = true" if local
313
+
314
+ if grp.kind_of?(Fixnum)
315
+ if local
316
+ query << " and sid like '%-#{grp}'"
317
+ else
318
+ query << " where sid like '%-#{grp}'"
319
+ end
320
+ else
321
+ if local
322
+ query << " and name = '#{grp}'"
323
+ else
324
+ query << " where name = '#{grp}'"
325
+ end
326
+ end
327
+
328
+ wmi.execquery(query).each{ |group|
329
+ gid = group.sid.split("-").last.to_i
330
+
331
+ # Because our 'like' query isn't fulproof, let's parse
332
+ # the SID again to make sure
333
+ if grp.kind_of?(Fixnum)
334
+ next if grp != gid
335
+ end
336
+
337
+ grp = Group.new do |g|
338
+ g.caption = group.caption
339
+ g.description = group.description
340
+ g.domain = group.domain
341
+ g.gid = gid
342
+ g.install_date = group.installdate
343
+ g.local = group.localaccount
344
+ g.name = group.name
345
+ g.sid = group.sid
346
+ g.sid_type = group.sidtype
347
+ g.status = group.status
348
+ end
349
+ return grp
350
+ }
351
+ # If we're here, it means it wasn't found.
352
+ raise AdminError, "no group found for '#{grp}'"
353
+ end
354
+
355
+ # In block form, yields a Group object for each user on the system. In
356
+ # non-block form, returns an Array of Group objects.
357
+ #
358
+ # call-seq:
359
+ # groups(host=localhost, local=true)
360
+ # groups(host=localhost, local=true){ |group| ... }
361
+ #
362
+ # You may specify a host from which information is retrieved.
363
+ # The default is the local machine. You can retrieve either a global or
364
+ # local group, depending on the value of the +local+ argument.
365
+ #
366
+ def self.groups(host=Socket.gethostname, local=true)
367
+ host = Socket.gethostname if host.nil?
368
+ cs = "winmgmts:{impersonationLevel=impersonate}!"
369
+ cs << "//#{host}/root/cimv2"
370
+
371
+ begin
372
+ wmi = WIN32OLE.connect(cs)
373
+ rescue WIN32OLERuntimeError => e
374
+ raise AdminError, e
375
+ end
376
+
377
+ query = "select * from win32_group"
378
+ query << " where localaccount = true" if local
379
+
380
+ array = []
381
+ wmi.execquery(query).each{ |group|
382
+ grp = Group.new do |g|
383
+ g.caption = group.caption
384
+ g.description = group.description
385
+ g.domain = group.domain
386
+ g.gid = group.sid.split("-").last.to_i
387
+ g.install_date = group.installdate
388
+ g.local = group.localaccount
389
+ g.name = group.name
390
+ g.sid = group.sid
391
+ g.sid_type = group.sidtype
392
+ g.status = group.status
393
+ end
394
+ if block_given?
395
+ yield grp
396
+ else
397
+ array.push(grp)
398
+ end
399
+ }
400
+ return array unless block_given?
401
+ end
402
+ end
403
+ end
@@ -0,0 +1,14 @@
1
+ ###############################################################################
2
+ # tc_admin.rb
3
+ #
4
+ # This exists mostly for the sake of the gemspec, so that it calls the right
5
+ # test suite based on the platform.
6
+ ###############################################################################
7
+ $LOAD_PATH.unshift Dir.pwd
8
+ $LOAD_PATH.unshift Dir.pwd + "/test"
9
+
10
+ if File::ALT_SEPARATOR
11
+ require "tc_win32"
12
+ else
13
+ require "tc_unix"
14
+ end
metadata ADDED
@@ -0,0 +1,51 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.0
3
+ specification_version: 1
4
+ name: sys-admin
5
+ version: !ruby/object:Gem::Version
6
+ version: 1.3.1
7
+ date: 2006-11-19 00:00:00 -07:00
8
+ summary: A unified, cross platform replacement for the 'etc' package.
9
+ require_paths:
10
+ - lib
11
+ email: djberg96@gmail.com
12
+ homepage: http://www.rubyforge.org/projects/sysutils
13
+ rubyforge_project: sysutils
14
+ description: A unified, cross platform replacement for the 'etc' package.
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.8.2
24
+ version:
25
+ platform: mswin32
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Daniel J. Berger
31
+ files:
32
+ - lib/sys/admin.rb
33
+ - CHANGES
34
+ - README
35
+ - MANIFEST
36
+ test_files:
37
+ - test/tc_admin.rb
38
+ rdoc_options: []
39
+
40
+ extra_rdoc_files:
41
+ - CHANGES
42
+ - README
43
+ - MANIFEST
44
+ executables: []
45
+
46
+ extensions: []
47
+
48
+ requirements: []
49
+
50
+ dependencies: []
51
+