sys-admin 1.4.4-x86-mswin32-60 → 1.5.0-x86-mswin32-60
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +17 -0
- data/README +25 -47
- data/Rakefile +6 -1
- data/lib/sys/admin.rb +417 -201
- data/sys-admin.gemspec +4 -4
- data/test/{tc_admin.rb → test_sys_admin.rb} +12 -5
- data/test/test_sys_admin_unix.rb +246 -0
- data/test/{tc_windows.rb → test_sys_admin_windows.rb} +117 -111
- metadata +12 -10
- data/test/tc_unix.rb +0 -81
data/CHANGES
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
== 1.5.0 - 29-Mar-2009
|
2
|
+
* INTERFACE CHANGE (WINDOWS ONLY): The interface for MS Windows has undergone
|
3
|
+
a radical change. Most methods now accept a hash of options that are
|
4
|
+
passed directly to the underlying WMI class. Please see the documentation
|
5
|
+
for details.
|
6
|
+
* Now works on various BSD flavors.
|
7
|
+
* Added the User#groups method. This returns an array of groups that the
|
8
|
+
user belongs to. Suggestion inspired by Gonzalo Garramuno.
|
9
|
+
* Added the Group#members method. The returns an array of users that the
|
10
|
+
group contains.
|
11
|
+
* Changed User#class to User#access_class for UNIX flavors to avoid
|
12
|
+
conflicts with the Ruby core Object method.
|
13
|
+
* Added more tests and renamed the test files.
|
14
|
+
* Removed an unnecessary function call where a platform might try to
|
15
|
+
get lastlog information even if the lastlog.h or utmp.h headers couldn't
|
16
|
+
be found.
|
17
|
+
|
1
18
|
== 1.4.4 - 19-Nov-2008
|
2
19
|
* Added the User#uid method for MS Windows (which is just the user's relative
|
3
20
|
identifier).
|
data/README
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
== Description
|
2
|
-
The sys-admin
|
2
|
+
The sys-admin library is a unified, cross platform replacement for the
|
3
3
|
Etc module.
|
4
4
|
|
5
5
|
== Installation
|
6
|
+
= Typical Gem Installation
|
7
|
+
gem install sys-admin
|
8
|
+
= Local installation
|
6
9
|
rake test (optional)
|
7
10
|
rake install
|
8
11
|
|
@@ -36,39 +39,33 @@
|
|
36
39
|
Admin.get_login
|
37
40
|
Returns the user name (only) of the current login.
|
38
41
|
|
39
|
-
Admin.get_user(name,
|
40
|
-
Admin.get_user(uid,
|
41
|
-
Returns a User object based on +name+ or +uid+.
|
42
|
+
Admin.get_user(name, options = {})
|
43
|
+
Admin.get_user(uid, options = {})
|
44
|
+
Returns a User object based on +name+ or +uid+. The +options+ hash is
|
45
|
+
for MS Windows only, and allows you to restrict the search based on the
|
46
|
+
options you provide, e.g. 'domain' or 'localaccount'.
|
42
47
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
Windows only: you may specify a host from which information is retrieved.
|
52
|
-
The default is the local machine. You can retrieve either a global or
|
53
|
-
local group, depending on the value of the +local+ argument.
|
54
|
-
|
55
|
-
Admin.groups(host=localhost, local=true)
|
56
|
-
Admin.groups(host=localhost, local=true){ |group| ... }
|
48
|
+
Admin.get_group(name, options = {})
|
49
|
+
Admin.get_group(gid, options = {})
|
50
|
+
Returns a Group object based on +name+ or +uid+. The +options+ hash is
|
51
|
+
for MS Windows only, and allows you to restrict the search based on the
|
52
|
+
options you provide, e.g. 'domain' or 'localaccount'.
|
53
|
+
|
54
|
+
Admin.groups(options = {})
|
55
|
+
Admin.groups(options = {}){ |group| ... }
|
57
56
|
In block form, yields a Group object for each user on the system. In
|
58
57
|
non-block form, returns an Array of Group objects.
|
59
58
|
|
60
|
-
|
61
|
-
|
62
|
-
local group, depending on the value of the +local+ argument.
|
59
|
+
The +options+ hash is for MS Windows only, and allows you to restrict the
|
60
|
+
search based on the options you provide, e.g. 'domain' or 'localaccount'.
|
63
61
|
|
64
|
-
Admin.users(
|
65
|
-
Admin.users(
|
62
|
+
Admin.users(options = {})
|
63
|
+
Admin.users(options = {}){ |user| ... }
|
66
64
|
In block form, yields a User object for each user on the system. In
|
67
65
|
non-block form, returns an Array of User objects.
|
68
66
|
|
69
|
-
|
70
|
-
|
71
|
-
local group, depending on the value of the +local+ argument.
|
67
|
+
The +options+ hash is for MS Windows only, and allows you to restrict the
|
68
|
+
search based on the options you provide, e.g. 'domain' or 'localaccount'.
|
72
69
|
|
73
70
|
== User class
|
74
71
|
=== User (Windows)
|
@@ -140,33 +137,14 @@ Admin::Error < StandardError
|
|
140
137
|
information. This means that the WMI service must be running on the
|
141
138
|
target machine in order to work (which it is, by default).
|
142
139
|
|
143
|
-
Note that, by default, local user and group information is retrieved
|
144
|
-
instead of global. You probably do NOT want to iterate over global users
|
145
|
-
or groups because there can be quite a few on your domain.
|
146
|
-
|
147
140
|
=== UNIX
|
148
141
|
The underlying implementation is similar to core Ruby's Etc implementation.
|
149
142
|
But, in addition to the different interface, I use the re-entrant version
|
150
143
|
of the appropriate functions when available.
|
151
144
|
|
152
145
|
== Future Plans
|
153
|
-
Add the following methods for UNIX:
|
154
|
-
|
155
|
-
* Admin.add_local_user
|
156
|
-
* Admin.config_local_user
|
157
|
-
* Admin.delete_local_user
|
158
|
-
* Admin.add_global_user
|
159
|
-
* Admin.config_global_user
|
160
|
-
* Admin.delete_global_user
|
161
|
-
|
162
|
-
* Admin.add_local_group
|
163
|
-
* Admin.config_local_group
|
164
|
-
* Admin.delete_local_group
|
165
|
-
* Admin.add_global_group
|
166
|
-
* Admin.config_global_group
|
167
|
-
* Admin.delete_global_group
|
168
|
-
|
169
146
|
Make the User and Group objects comparable.
|
147
|
+
Add ability to add, configure and delete users on Unix platforms.
|
170
148
|
|
171
149
|
== Known Bugs
|
172
150
|
None that I'm aware of. If you find any, please log them on the project
|
@@ -176,7 +154,7 @@ Admin::Error < StandardError
|
|
176
154
|
Ruby's
|
177
155
|
|
178
156
|
== Copyright
|
179
|
-
(C) 2005-
|
157
|
+
(C) 2005-2009, Daniel J. Berger
|
180
158
|
All Rights Reserved
|
181
159
|
|
182
160
|
== Author
|
data/Rakefile
CHANGED
@@ -52,5 +52,10 @@ Rake::TestTask.new("test") do |t|
|
|
52
52
|
t.libs << 'ext'
|
53
53
|
t.libs.delete('lib')
|
54
54
|
end
|
55
|
-
t.
|
55
|
+
t.libs << 'test'
|
56
|
+
t.test_files = FileList['test/test_sys_admin.rb']
|
57
|
+
end
|
58
|
+
|
59
|
+
task :test do
|
60
|
+
Rake.application[:clean].execute
|
56
61
|
end
|
data/lib/sys/admin.rb
CHANGED
@@ -31,6 +31,9 @@ module Sys
|
|
31
31
|
# Sets whether or not the group is local (as opposed to global).
|
32
32
|
attr_writer :local
|
33
33
|
|
34
|
+
# An array of members for that group. May contain SID's.
|
35
|
+
attr_accessor :members
|
36
|
+
|
34
37
|
# Creates and returns a new Group object. This class encapsulates
|
35
38
|
# the information for a group account, whether it be global or local.
|
36
39
|
#
|
@@ -128,6 +131,9 @@ module Sys
|
|
128
131
|
|
129
132
|
# Full name of a local user.
|
130
133
|
attr_accessor :full_name
|
134
|
+
|
135
|
+
# An array of groups to which the user belongs.
|
136
|
+
attr_accessor :groups
|
131
137
|
|
132
138
|
# Date the user account was created.
|
133
139
|
attr_accessor :install_date
|
@@ -282,7 +288,7 @@ module Sys
|
|
282
288
|
end
|
283
289
|
|
284
290
|
class Admin
|
285
|
-
VERSION = '1.
|
291
|
+
VERSION = '1.5.0'
|
286
292
|
|
287
293
|
# This is the error raised in the majority of cases if anything goes wrong
|
288
294
|
# with any of the Sys::Admin methods.
|
@@ -300,222 +306,348 @@ module Sys
|
|
300
306
|
SidTypeComputer = 9
|
301
307
|
|
302
308
|
private
|
309
|
+
|
310
|
+
# A private method that lower cases all keys, and converts them
|
311
|
+
# all to symbols.
|
312
|
+
#
|
313
|
+
def self.munge_options(opts)
|
314
|
+
rhash = {}
|
315
|
+
|
316
|
+
opts.each{ |k, v|
|
317
|
+
k = k.to_s.downcase.to_sym
|
318
|
+
rhash[k] = v
|
319
|
+
}
|
320
|
+
|
321
|
+
rhash
|
322
|
+
end
|
323
|
+
|
324
|
+
# An internal, private method for getting a list of groups for
|
325
|
+
# a particular user.
|
326
|
+
#
|
327
|
+
def self.get_groups(domain, user)
|
328
|
+
array = []
|
329
|
+
adsi = WIN32OLE.connect("WinNT://#{domain}/#{user}")
|
330
|
+
adsi.groups.each{ |g| array << g.name }
|
331
|
+
array
|
332
|
+
end
|
333
|
+
|
334
|
+
# An internal, private method for getting a list of members for
|
335
|
+
# any particular group.
|
336
|
+
#
|
337
|
+
def self.get_members(domain, group)
|
338
|
+
array = []
|
339
|
+
adsi = WIN32OLE.connect("WinNT://#{domain}/#{group}")
|
340
|
+
adsi.members.each{ |g| array << g.name }
|
341
|
+
array
|
342
|
+
end
|
303
343
|
|
304
344
|
# Used by the get_login method
|
305
345
|
GetUserName = Win32API.new('advapi32', 'GetUserName', 'PP', 'L') # :nodoc:
|
306
346
|
|
307
347
|
public
|
308
348
|
|
309
|
-
#
|
310
|
-
#
|
311
|
-
#
|
312
|
-
#
|
313
|
-
|
314
|
-
|
315
|
-
|
349
|
+
# Creates the given +user+. If no domain option is specified,
|
350
|
+
# then it defaults to your local host, i.e. a local account is
|
351
|
+
# created.
|
352
|
+
#
|
353
|
+
# Any options provided are treated as IADsUser interface methods
|
354
|
+
# and are called before SetInfo is finally called.
|
355
|
+
#
|
356
|
+
# Examples:
|
357
|
+
#
|
358
|
+
# # Create a local user with no options
|
359
|
+
# Sys::Admin.add_user(:name => 'asmith')
|
360
|
+
#
|
361
|
+
# # Create a local user with options
|
362
|
+
# Sys::Admin.add_user(
|
363
|
+
# :name => 'asmith',
|
364
|
+
# :description => 'Really cool guy',
|
365
|
+
# :password => 'abc123'
|
366
|
+
# )
|
367
|
+
#
|
368
|
+
# # Create a user on a specific domain
|
369
|
+
# Sys::Admin.add_user(
|
370
|
+
# :name => 'asmith',
|
371
|
+
# :domain => 'XX',
|
372
|
+
# :fullname => 'Al Smith'
|
373
|
+
# )
|
374
|
+
#--
|
375
|
+
# Most options are passed to the 'put' method. However, we handle the
|
376
|
+
# password specially since it's a separate method, and some environments
|
377
|
+
# require that it be set up front.
|
378
|
+
#
|
379
|
+
def self.add_user(options = {})
|
380
|
+
options = munge_options(options)
|
381
|
+
|
382
|
+
name = options.delete(:name) or raise ArgumentError, 'No user given'
|
383
|
+
domain = options[:domain]
|
384
|
+
|
385
|
+
if domain.nil?
|
386
|
+
domain = Socket.gethostname
|
387
|
+
moniker = "WinNT://#{domain},Computer"
|
388
|
+
else
|
389
|
+
moniker = "WinNT://#{domain}"
|
390
|
+
end
|
391
|
+
|
392
|
+
begin
|
393
|
+
adsi = WIN32OLE.connect(moniker)
|
394
|
+
user = adsi.create('user', name)
|
316
395
|
options.each{ |option, value|
|
317
|
-
|
396
|
+
if option.to_s == 'password'
|
397
|
+
user.setpassword(value)
|
398
|
+
else
|
399
|
+
user.put(option.to_s, value)
|
400
|
+
end
|
318
401
|
}
|
319
|
-
|
402
|
+
user.setinfo
|
320
403
|
rescue WIN32OLERuntimeError => err
|
321
404
|
raise Error, err
|
322
405
|
end
|
323
406
|
end
|
324
407
|
|
325
|
-
# Configures the
|
326
|
-
# is
|
408
|
+
# Configures the +user+ using +options+. If no domain option is
|
409
|
+
# specified then your local host is used, i.e. you are configuring
|
410
|
+
# a local user account.
|
327
411
|
#
|
328
412
|
# See http://tinyurl.com/3hjv9 for a list of valid options.
|
329
|
-
#
|
330
|
-
|
413
|
+
#
|
414
|
+
# In the case of a password change, pass a two element array as the
|
415
|
+
# old value and new value.
|
416
|
+
#
|
417
|
+
# Examples:
|
418
|
+
#
|
419
|
+
# # Configure a local user
|
420
|
+
# Sys::Admin.configure_user(
|
421
|
+
# :name => 'djberge',
|
422
|
+
# :description => 'Awesome'
|
423
|
+
# )
|
424
|
+
#
|
425
|
+
# # Change the password
|
426
|
+
# Sys::Admin.configure_user(
|
427
|
+
# :name => 'asmith',
|
428
|
+
# :password => [old_pass, new_pass]
|
429
|
+
# )
|
430
|
+
#
|
431
|
+
# # Configure a user on a specific domain
|
432
|
+
# Sys::Admin.configure_user(
|
433
|
+
# :name => 'jsmrz',
|
434
|
+
# :domain => 'XX',
|
435
|
+
# :firstname => 'Jo'
|
436
|
+
# )
|
437
|
+
#
|
438
|
+
def self.configure_user(options = {})
|
439
|
+
options = munge_options(options)
|
440
|
+
|
441
|
+
name = options.delete(:name) or raise ArgumentError, 'No name given'
|
442
|
+
domain = options[:domain] || Socket.gethostname
|
443
|
+
|
331
444
|
begin
|
332
|
-
adsi = WIN32OLE.connect("WinNT://#{
|
445
|
+
adsi = WIN32OLE.connect("WinNT://#{domain}/#{name},user")
|
333
446
|
options.each{ |option, value|
|
334
|
-
|
447
|
+
if option.to_s == 'password'
|
448
|
+
adsi.changepassword(value[0], value[1])
|
449
|
+
else
|
450
|
+
adsi.put(option.to_s, value)
|
451
|
+
end
|
335
452
|
}
|
336
453
|
adsi.setinfo
|
337
454
|
rescue WIN32OLERuntimeError => err
|
338
455
|
raise Error, err
|
339
456
|
end
|
340
457
|
end
|
341
|
-
|
342
|
-
#
|
458
|
+
|
459
|
+
# Deletes the given +user+ on +domain+. If no domain is specified,
|
460
|
+
# then it defaults to your local host, i.e. a local account is
|
461
|
+
# deleted.
|
343
462
|
#
|
344
|
-
def self.
|
463
|
+
def self.delete_user(user, domain = nil)
|
464
|
+
if domain.nil?
|
465
|
+
domain = Socket.gethostname
|
466
|
+
moniker = "WinNT://#{domain},Computer"
|
467
|
+
else
|
468
|
+
moniker = "WinNT://#{domain}"
|
469
|
+
end
|
470
|
+
|
345
471
|
begin
|
346
|
-
adsi = WIN32OLE.connect(
|
347
|
-
|
348
|
-
user.setinfo
|
472
|
+
adsi = WIN32OLE.connect(moniker)
|
473
|
+
adsi.delete('user', user)
|
349
474
|
rescue WIN32OLERuntimeError => err
|
350
475
|
raise Error, err
|
351
476
|
end
|
352
477
|
end
|
353
|
-
|
354
|
-
#
|
478
|
+
|
479
|
+
# Create a new +group+ using +options+. If no domain option is specified
|
480
|
+
# then a local group is created instead.
|
355
481
|
#
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
482
|
+
# Examples:
|
483
|
+
#
|
484
|
+
# # Create a local group with no options
|
485
|
+
# Sys::Admin.add_group(:name => 'Dudes')
|
486
|
+
#
|
487
|
+
# # Create a local group with options
|
488
|
+
# Sys::Admin.add_group(:name => 'Dudes', :description => 'Boys')
|
489
|
+
#
|
490
|
+
# # Create a group on a specific domain
|
491
|
+
# Sys::Admin.add_group(
|
492
|
+
# :name => 'Ladies',
|
493
|
+
# :domain => 'XYZ',
|
494
|
+
# :description => 'Girls'
|
495
|
+
# )
|
496
|
+
#
|
497
|
+
def self.add_group(options = {})
|
498
|
+
options = munge_options(options)
|
499
|
+
|
500
|
+
group = options.delete(:name) or raise ArgumentError, 'No name given'
|
501
|
+
domain = options[:domain]
|
502
|
+
|
503
|
+
if domain.nil?
|
504
|
+
domain = Socket.gethostname
|
505
|
+
moniker = "WinNT://#{domain},Computer"
|
506
|
+
else
|
507
|
+
moniker = "WinNT://#{domain}"
|
363
508
|
end
|
364
|
-
end
|
365
509
|
|
366
|
-
# Deletes the local +user+ from +host+, or localhost if no host specified.
|
367
|
-
#
|
368
|
-
def self.delete_local_user(user, host=Socket.gethostname)
|
369
510
|
begin
|
370
|
-
adsi = WIN32OLE.connect(
|
371
|
-
adsi.
|
511
|
+
adsi = WIN32OLE.connect(moniker)
|
512
|
+
group = adsi.create('group', group)
|
513
|
+
group.setinfo
|
514
|
+
configure_group(options) unless options.empty?
|
372
515
|
rescue WIN32OLERuntimeError => err
|
373
516
|
raise Error, err
|
374
517
|
end
|
375
518
|
end
|
376
|
-
|
377
|
-
#
|
378
|
-
#
|
379
|
-
|
380
|
-
begin
|
381
|
-
adsi = WIN32OLE.connect("WinNT://#{domain}")
|
382
|
-
adsi.delete("user", user)
|
383
|
-
rescue WIN32OLERuntimeError => err
|
384
|
-
raise Error, err
|
385
|
-
end
|
386
|
-
end
|
387
|
-
|
388
|
-
# Configures the global +group+ on +domain+ using +options+.
|
519
|
+
|
520
|
+
# Configures the +group+ using +options+. If no domain option is
|
521
|
+
# specified then your local host is used, i.e. you are configuring
|
522
|
+
# a local group.
|
389
523
|
#
|
390
524
|
# See http://tinyurl.com/cjkzl for a list of valid options.
|
391
525
|
#
|
392
|
-
|
526
|
+
# Examples:
|
527
|
+
#
|
528
|
+
# # Configure a local group.
|
529
|
+
# Sys::Admin.configure_group(:name => 'Abba', :description => 'Swedish')
|
530
|
+
#
|
531
|
+
# # Configure a group on a specific domain.
|
532
|
+
# Sys::Admin.configure_group(
|
533
|
+
# :name => 'Web Team',
|
534
|
+
# :domain => 'Foo',
|
535
|
+
# :description => 'Web programming cowboys'
|
536
|
+
# )
|
537
|
+
#
|
538
|
+
def self.configure_group(options = {})
|
539
|
+
options = munge_options(options)
|
540
|
+
|
541
|
+
group = options.delete(:name) or raise ArgumentError, 'No name given'
|
542
|
+
domain = options[:domain] || Socket.gethostname
|
543
|
+
|
393
544
|
begin
|
394
545
|
adsi = WIN32OLE.connect("WinNT://#{domain}/#{group},group")
|
395
|
-
options.each{ |option, value|
|
396
|
-
adsi.put(option.to_s, value)
|
397
|
-
}
|
546
|
+
options.each{ |option, value| adsi.put(option.to_s, value) }
|
398
547
|
adsi.setinfo
|
399
548
|
rescue WIN32OLERuntimeError => err
|
400
549
|
raise Error, err
|
401
550
|
end
|
402
551
|
end
|
403
552
|
|
404
|
-
#
|
405
|
-
#
|
406
|
-
#
|
407
|
-
# See http://tinyurl.com/cjkzl for a list of valid options.
|
553
|
+
# Delete the +group+ from +domain+. If no domain is specified, then
|
554
|
+
# you are deleting a local group.
|
408
555
|
#
|
409
|
-
def self.
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
}
|
415
|
-
adsi.setinfo
|
416
|
-
rescue WIN32OLERuntimeError => err
|
417
|
-
raise Error, err
|
418
|
-
end
|
419
|
-
end
|
420
|
-
|
421
|
-
# Add global +group+ to +domain+.
|
422
|
-
#
|
423
|
-
def self.add_global_group(group, domain)
|
424
|
-
begin
|
425
|
-
adsi = WIN32OLE.connect("WinNT://#{domain},Computer")
|
426
|
-
obj = adsi.create("group", group)
|
427
|
-
obj.setinfo
|
428
|
-
rescue WIN32OLERuntimeError => err
|
429
|
-
raise Error, err
|
556
|
+
def self.delete_group(group, domain = nil)
|
557
|
+
if domain.nil?
|
558
|
+
domain = Socket.gethostname
|
559
|
+
moniker = "WinNT://#{domain},Computer"
|
560
|
+
else
|
561
|
+
moniker = "WinNT://#{domain}"
|
430
562
|
end
|
431
|
-
end
|
432
563
|
|
433
|
-
# Add local +group+ to +host+, or the localhost if no host is specified.
|
434
|
-
#
|
435
|
-
def self.add_local_group(group, host=Socket.gethostname)
|
436
564
|
begin
|
437
|
-
adsi = WIN32OLE.connect(
|
438
|
-
obj = adsi.
|
439
|
-
obj.setinfo
|
565
|
+
adsi = WIN32OLE.connect(moniker)
|
566
|
+
obj = adsi.delete('group', group)
|
440
567
|
rescue WIN32OLERuntimeError => err
|
441
568
|
raise Error, err
|
442
569
|
end
|
443
570
|
end
|
444
571
|
|
445
|
-
# Delete the global +group+ from +domain+.
|
446
|
-
#
|
447
|
-
def self.delete_global_group(groupid, domain)
|
448
|
-
begin
|
449
|
-
adsi = WIN32OLE.connect("WinNT://#{domain},Computer")
|
450
|
-
obj = adsi.delete("group", groupid)
|
451
|
-
rescue WIN32OLERuntimeError => err
|
452
|
-
raise Error, err
|
453
|
-
end
|
454
|
-
end
|
455
|
-
|
456
|
-
# Delete the local +group+ from +host+, or localhost if no host specified.
|
457
|
-
#
|
458
|
-
def self.delete_local_group(groupid, host=Socket.gethostname)
|
459
|
-
begin
|
460
|
-
adsi = WIN32OLE.connect("WinNT://#{host},Computer")
|
461
|
-
obj = adsi.delete("group", groupid)
|
462
|
-
rescue WIN32OLERuntimeError => err
|
463
|
-
raise Error, err
|
464
|
-
end
|
465
|
-
end
|
466
|
-
|
467
572
|
# Returns the user name (only) of the current login.
|
468
573
|
#
|
469
574
|
def self.get_login
|
470
575
|
buffer = 0.chr * 256
|
471
|
-
nsize
|
576
|
+
nsize = [buffer.size].pack("L")
|
472
577
|
|
473
578
|
if GetUserName.call(buffer, nsize) == 0
|
474
579
|
raise Error, 'GetUserName() call failed in get_login'
|
475
580
|
end
|
476
581
|
|
477
|
-
length
|
582
|
+
length = nsize.unpack('L')[0]
|
478
583
|
username = buffer[0 ... length].chop
|
479
584
|
username
|
480
585
|
end
|
481
|
-
|
586
|
+
|
482
587
|
# Returns a User object based on either +name+ or +uid+.
|
483
588
|
#
|
484
589
|
# call-seq:
|
485
|
-
# get_user(name,
|
486
|
-
# get_user(uid,
|
590
|
+
# Sys::Admin.get_user(name, options = {})
|
591
|
+
# Sys::Admin.get_user(uid, options = {})
|
592
|
+
#
|
593
|
+
# Looks for +usr+ information based on the options you specify, where
|
594
|
+
# the +usr+ argument can be either a user name or a RID.
|
595
|
+
#
|
596
|
+
# If a 'host' option is specified, information is retrieved from that
|
597
|
+
# host. Otherwise, the local host is used.
|
598
|
+
#
|
599
|
+
# All other options are converted to WQL statements against the
|
600
|
+
# Win32_UserAccount WMI object. See http://tinyurl.com/by9nvn for a
|
601
|
+
# list of possible options.
|
487
602
|
#
|
488
|
-
#
|
489
|
-
# default is the local machine. You may also specify whether to
|
490
|
-
# retrieve a local or global account. The default is local.
|
603
|
+
# Examples:
|
491
604
|
#
|
492
|
-
|
493
|
-
|
605
|
+
# # Get a user by name
|
606
|
+
# Admin.get_user('djberge')
|
607
|
+
#
|
608
|
+
# # Get a user by uid
|
609
|
+
# Admin.get_user(100)
|
610
|
+
#
|
611
|
+
# # Get a user on a specific domain
|
612
|
+
# Admin.get_user('djberge', :domain => 'TEST')
|
613
|
+
#--
|
614
|
+
# The reason for keeping the +usr+ variable as a separate argument
|
615
|
+
# instead of rolling it into the options hash was to keep a unified
|
616
|
+
# API between the Windows and UNIX versions.
|
617
|
+
#
|
618
|
+
def self.get_user(usr, options = {})
|
619
|
+
options = munge_options(options)
|
620
|
+
|
621
|
+
host = options.delete(:host) || Socket.gethostname
|
494
622
|
cs = "winmgmts:{impersonationLevel=impersonate}!"
|
495
623
|
cs << "//#{host}/root/cimv2"
|
496
624
|
|
497
625
|
begin
|
498
626
|
wmi = WIN32OLE.connect(cs)
|
499
|
-
rescue WIN32OLERuntimeError =>
|
500
|
-
raise Error,
|
627
|
+
rescue WIN32OLERuntimeError => err
|
628
|
+
raise Error, err
|
501
629
|
end
|
502
630
|
|
503
631
|
query = "select * from win32_useraccount"
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
632
|
+
|
633
|
+
i = 0
|
634
|
+
|
635
|
+
options.each{ |opt, val|
|
636
|
+
if i == 0
|
637
|
+
query << " where #{opt} = '#{val}'"
|
638
|
+
i += 1
|
509
639
|
else
|
510
|
-
query << "
|
640
|
+
query << " and #{opt} = '#{val}'"
|
511
641
|
end
|
642
|
+
}
|
643
|
+
|
644
|
+
if usr.kind_of?(Fixnum)
|
645
|
+
query << " and sid like '%-#{usr}'"
|
512
646
|
else
|
513
|
-
|
514
|
-
query << " and name = '#{usr}'"
|
515
|
-
else
|
516
|
-
query << " where name = '#{usr}'"
|
517
|
-
end
|
647
|
+
query << " and name = '#{usr}'"
|
518
648
|
end
|
649
|
+
|
650
|
+
domain = options[:domain] || host
|
519
651
|
|
520
652
|
wmi.execquery(query).each{ |user|
|
521
653
|
uid = user.sid.split('-').last.to_i
|
@@ -527,23 +659,24 @@ module Sys
|
|
527
659
|
end
|
528
660
|
|
529
661
|
user_object = User.new do |u|
|
530
|
-
u.account_type
|
531
|
-
u.caption
|
532
|
-
u.description
|
533
|
-
u.disabled
|
534
|
-
u.domain
|
535
|
-
u.full_name
|
536
|
-
u.install_date
|
537
|
-
u.local
|
538
|
-
u.lockout
|
539
|
-
u.name
|
662
|
+
u.account_type = user.accounttype
|
663
|
+
u.caption = user.caption
|
664
|
+
u.description = user.description
|
665
|
+
u.disabled = user.disabled
|
666
|
+
u.domain = user.domain
|
667
|
+
u.full_name = user.fullname
|
668
|
+
u.install_date = user.installdate
|
669
|
+
u.local = user.localaccount
|
670
|
+
u.lockout = user.lockout
|
671
|
+
u.name = user.name
|
540
672
|
u.password_changeable = user.passwordchangeable
|
541
673
|
u.password_expires = user.passwordexpires
|
542
674
|
u.password_required = user.passwordrequired
|
543
|
-
u.sid
|
544
|
-
u.sid_type
|
545
|
-
u.status
|
546
|
-
u.uid
|
675
|
+
u.sid = user.sid
|
676
|
+
u.sid_type = user.sidtype
|
677
|
+
u.status = user.status
|
678
|
+
u.uid = uid
|
679
|
+
u.groups = get_groups(domain, user.name)
|
547
680
|
end
|
548
681
|
|
549
682
|
return user_object
|
@@ -553,19 +686,34 @@ module Sys
|
|
553
686
|
raise Error, "no user found for '#{usr}'"
|
554
687
|
end
|
555
688
|
|
556
|
-
# In block form, yields a User object for each user on the system.
|
689
|
+
# In block form, yields a User object for each user on the system. In
|
557
690
|
# non-block form, returns an Array of User objects.
|
558
691
|
#
|
559
692
|
# call-seq:
|
560
|
-
# users(
|
561
|
-
# users(
|
693
|
+
# Sys::Admin.users(options = {})
|
694
|
+
# Sys::Admin.users(options = {}){ |user| ... }
|
695
|
+
#
|
696
|
+
# You may specify a host from which information is retrieved. The
|
697
|
+
# default is the local host.
|
698
|
+
#
|
699
|
+
# All other arguments are passed as WQL query parameters against
|
700
|
+
# the Win32_UserAccont WMI object.
|
701
|
+
#
|
702
|
+
# Examples:
|
703
|
+
#
|
704
|
+
# # Get all local account users
|
705
|
+
# Sys::Admin.users(:localaccount => true)
|
706
|
+
#
|
707
|
+
# # Get all user accounts on a specific domain
|
708
|
+
# Sys::Admin.users(:domain => 'FOO')
|
562
709
|
#
|
563
|
-
#
|
564
|
-
#
|
565
|
-
# local group, depending on the value of the +local+ argument.
|
710
|
+
# # Get a single user from a domain
|
711
|
+
# Sys::Admin.users(:name => 'djberge', :domain => 'FOO')
|
566
712
|
#
|
567
|
-
def self.users(
|
568
|
-
|
713
|
+
def self.users(options = {})
|
714
|
+
options = munge_options(options)
|
715
|
+
|
716
|
+
host = options.delete(:host) || Socket.gethostname
|
569
717
|
cs = "winmgmts:{impersonationLevel=impersonate}!"
|
570
718
|
cs << "//#{host}/root/cimv2"
|
571
719
|
|
@@ -576,27 +724,40 @@ module Sys
|
|
576
724
|
end
|
577
725
|
|
578
726
|
query = "select * from win32_useraccount"
|
579
|
-
|
727
|
+
|
728
|
+
i = 0
|
729
|
+
|
730
|
+
options.each{ |opt, val|
|
731
|
+
if i == 0
|
732
|
+
query << " where #{opt} = '#{val}'"
|
733
|
+
i += 1
|
734
|
+
else
|
735
|
+
query << " and #{opt} = '#{val}'"
|
736
|
+
end
|
737
|
+
}
|
738
|
+
|
580
739
|
array = []
|
740
|
+
domain = options[:domain] || host
|
581
741
|
|
582
742
|
wmi.execquery(query).each{ |user|
|
583
743
|
usr = User.new do |u|
|
584
|
-
u.account_type
|
585
|
-
u.caption
|
586
|
-
u.description
|
587
|
-
u.disabled
|
588
|
-
u.domain
|
589
|
-
u.full_name
|
590
|
-
u.install_date
|
591
|
-
u.local
|
592
|
-
u.lockout
|
593
|
-
u.name
|
744
|
+
u.account_type = user.accounttype
|
745
|
+
u.caption = user.caption
|
746
|
+
u.description = user.description
|
747
|
+
u.disabled = user.disabled
|
748
|
+
u.domain = user.domain
|
749
|
+
u.full_name = user.fullname
|
750
|
+
u.install_date = user.installdate
|
751
|
+
u.local = user.localaccount
|
752
|
+
u.lockout = user.lockout
|
753
|
+
u.name = user.name
|
594
754
|
u.password_changeable = user.passwordchangeable
|
595
755
|
u.password_expires = user.passwordexpires
|
596
756
|
u.password_required = user.passwordrequired
|
597
|
-
u.sid
|
598
|
-
u.sid_type
|
599
|
-
u.status
|
757
|
+
u.sid = user.sid
|
758
|
+
u.sid_type = user.sidtype
|
759
|
+
u.status = user.status
|
760
|
+
u.groups = get_groups(domain, user.name)
|
600
761
|
end
|
601
762
|
|
602
763
|
if block_given?
|
@@ -605,47 +766,70 @@ module Sys
|
|
605
766
|
array.push(usr)
|
606
767
|
end
|
607
768
|
}
|
769
|
+
|
608
770
|
return array unless block_given?
|
609
771
|
end
|
610
772
|
|
611
|
-
# Returns a Group object based on either +name+ or +
|
773
|
+
# Returns a Group object based on either +name+ or +gid+.
|
612
774
|
#
|
613
775
|
# call-seq:
|
614
|
-
# get_group(name,
|
615
|
-
# get_group(gid,
|
776
|
+
# Sys::Admin.get_group(name, options = {})
|
777
|
+
# Sys::Admin.get_group(gid, options = {})
|
778
|
+
#
|
779
|
+
# If a numeric value is sent as the first parameter, it is treated
|
780
|
+
# as a RID and is checked against the SID for a match.
|
781
|
+
#
|
782
|
+
# You may specify a host as an option from which information is
|
783
|
+
# retrieved. The default is the local host.
|
784
|
+
#
|
785
|
+
# All other options are passed as WQL parameters to the Win32_Group
|
786
|
+
# WMI object. See http://tinyurl.com/bngc8s for a list of possible
|
787
|
+
# options.
|
788
|
+
#
|
789
|
+
# Examples:
|
790
|
+
#
|
791
|
+
# # Find a group by name
|
792
|
+
# Sys::Admin.get_group('Web Team')
|
793
|
+
#
|
794
|
+
# # Find a group by id
|
795
|
+
# Sys::Admin.get_group(31667)
|
616
796
|
#
|
617
|
-
#
|
618
|
-
#
|
619
|
-
# local group, depending on the value of the +local+ argument.
|
797
|
+
# # Find a group on a specific domain
|
798
|
+
# Sys::Admin.get_group('Web Team', :domain => 'FOO')
|
620
799
|
#
|
621
|
-
def self.get_group(grp,
|
622
|
-
|
800
|
+
def self.get_group(grp, options = {})
|
801
|
+
options = munge_options(options)
|
802
|
+
|
803
|
+
host = options.delete(:host) || Socket.gethostname
|
623
804
|
cs = "winmgmts:{impersonationLevel=impersonate}!"
|
624
805
|
cs << "//#{host}/root/cimv2"
|
625
|
-
|
626
|
-
|
806
|
+
|
627
807
|
begin
|
628
808
|
wmi = WIN32OLE.connect(cs)
|
629
|
-
rescue WIN32OLERuntimeError =>
|
630
|
-
raise Error,
|
809
|
+
rescue WIN32OLERuntimeError => err
|
810
|
+
raise Error, err
|
631
811
|
end
|
632
812
|
|
633
813
|
query = "select * from win32_group"
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
814
|
+
|
815
|
+
i = 0
|
816
|
+
|
817
|
+
options.each{ |opt, val|
|
818
|
+
if i == 0
|
819
|
+
query << " where #{opt} = '#{val}'"
|
820
|
+
i += 1
|
639
821
|
else
|
640
|
-
query << "
|
822
|
+
query << " and #{opt} = '#{val}'"
|
641
823
|
end
|
824
|
+
}
|
825
|
+
|
826
|
+
if grp.kind_of?(Fixnum)
|
827
|
+
query << " and sid like '%-#{grp}'"
|
642
828
|
else
|
643
|
-
|
644
|
-
query << " and name = '#{grp}'"
|
645
|
-
else
|
646
|
-
query << " where name = '#{grp}'"
|
647
|
-
end
|
829
|
+
query << " and name = '#{grp}'"
|
648
830
|
end
|
831
|
+
|
832
|
+
domain = options[:domain] || host
|
649
833
|
|
650
834
|
wmi.execquery(query).each{ |group|
|
651
835
|
gid = group.sid.split("-").last.to_i
|
@@ -667,6 +851,7 @@ module Sys
|
|
667
851
|
g.sid = group.sid
|
668
852
|
g.sid_type = group.sidtype
|
669
853
|
g.status = group.status
|
854
|
+
g.members = get_members(domain, group.name)
|
670
855
|
end
|
671
856
|
|
672
857
|
return group_object
|
@@ -680,28 +865,56 @@ module Sys
|
|
680
865
|
# non-block form, returns an Array of Group objects.
|
681
866
|
#
|
682
867
|
# call-seq:
|
683
|
-
# groups(
|
684
|
-
# groups(
|
868
|
+
# groups(options = {})
|
869
|
+
# groups(options = {}){ |group| ... }
|
870
|
+
#
|
871
|
+
# You may specify a host option from which information is retrieved.
|
872
|
+
# The default is the local host.
|
873
|
+
#
|
874
|
+
# All other options are passed as WQL parameters to the Win32_Group
|
875
|
+
# WMI object. See http://tinyurl.com/bngc8s for a list of possible
|
876
|
+
# options.
|
877
|
+
#
|
878
|
+
# Examples:
|
685
879
|
#
|
686
|
-
#
|
687
|
-
#
|
688
|
-
# local group, depending on the value of the +local+ argument.
|
880
|
+
# # Get local group information
|
881
|
+
# Sys::Admin.groups(:localaccount => true)
|
689
882
|
#
|
690
|
-
|
691
|
-
|
883
|
+
# # Get all groups on a specific domain
|
884
|
+
# Sys::Admin.groups(:domain => 'FOO')
|
885
|
+
#
|
886
|
+
# # Get a specific group on a domain
|
887
|
+
# Sys::Admin.groups(:name => 'Some Group', :domain => 'FOO')
|
888
|
+
#
|
889
|
+
def self.groups(options = {})
|
890
|
+
options = munge_options(options)
|
891
|
+
|
892
|
+
host = options.delete(:host) || Socket.gethostname
|
692
893
|
cs = "winmgmts:{impersonationLevel=impersonate}!"
|
693
894
|
cs << "//#{host}/root/cimv2"
|
694
895
|
|
695
896
|
begin
|
696
897
|
wmi = WIN32OLE.connect(cs)
|
697
|
-
rescue WIN32OLERuntimeError =>
|
698
|
-
raise Error,
|
898
|
+
rescue WIN32OLERuntimeError => err
|
899
|
+
raise Error, err
|
699
900
|
end
|
700
901
|
|
701
902
|
query = "select * from win32_group"
|
702
|
-
|
703
|
-
|
903
|
+
|
904
|
+
i = 0
|
905
|
+
|
906
|
+
options.each{ |opt, val|
|
907
|
+
if i == 0
|
908
|
+
query << " where #{opt} = '#{val}'"
|
909
|
+
i += 1
|
910
|
+
else
|
911
|
+
query << " and #{opt} = '#{val}'"
|
912
|
+
end
|
913
|
+
}
|
914
|
+
|
704
915
|
array = []
|
916
|
+
domain = options[:domain] || host
|
917
|
+
|
705
918
|
wmi.execquery(query).each{ |group|
|
706
919
|
grp = Group.new do |g|
|
707
920
|
g.caption = group.caption
|
@@ -714,13 +927,16 @@ module Sys
|
|
714
927
|
g.sid = group.sid
|
715
928
|
g.sid_type = group.sidtype
|
716
929
|
g.status = group.status
|
930
|
+
g.members = get_members(domain, group.name)
|
717
931
|
end
|
932
|
+
|
718
933
|
if block_given?
|
719
934
|
yield grp
|
720
935
|
else
|
721
936
|
array.push(grp)
|
722
937
|
end
|
723
938
|
}
|
939
|
+
|
724
940
|
return array unless block_given?
|
725
941
|
end
|
726
942
|
end
|