sys-admin 1.3.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.
@@ -0,0 +1,411 @@
1
+ #include <limits.h>
2
+ #include <stdlib.h>
3
+ #include <stdio.h>
4
+ #include <unistd.h>
5
+ #include <pwd.h>
6
+ #include <grp.h>
7
+ #include <fcntl.h>
8
+ #include <errno.h>
9
+ #include <string.h>
10
+
11
+ #define SYS_ADMIN_VERSION "1.3.1"
12
+
13
+ #ifdef HAVE_LASTLOG_H
14
+ #include <lastlog.h>
15
+ #else
16
+ #include <utmp.h>
17
+ #endif
18
+
19
+ #ifndef _POSIX_LOGIN_NAME_MAX
20
+ #define _POSIX_LOGIN_NAME_MAX 9
21
+ #endif
22
+
23
+ #ifdef _SC_GETPW_R_SIZE_MAX
24
+ #define USER_BUF_SIZE (sysconf(_SC_GETPW_R_SIZE_MAX))
25
+ #else
26
+ #define USER_BUF_SIZE 1024
27
+ #endif
28
+
29
+ #ifdef _SC_GETGR_R_SIZE_MAX
30
+ #define GROUP_BUF_SIZE (sysconf(_SC_GETGR_R_SIZE_MAX))
31
+ #else
32
+ #define GROUP_BUF_SIZE 7296
33
+ #endif
34
+
35
+ #ifndef _PATH_LASTLOG
36
+ #define _PATH_LASTLOG "/var/adm/lastlog"
37
+ #endif
38
+
39
+ /* Function prototypes */
40
+ static VALUE get_user(struct passwd* p);
41
+ static VALUE get_group(struct group* g);
42
+ int get_lastlog_info(const char* n, VALUE rbVal);
43
+
44
+ VALUE cUser, cGroup, cAdminError;
45
+
46
+ /*
47
+ * :no-doc:
48
+ *
49
+ * Helper function that returns a User object based on user ID.
50
+ */
51
+ static VALUE get_user_by_num(VALUE rbUID){
52
+ VALUE rbUser;
53
+ uid_t uid = NUM2INT(rbUID);
54
+
55
+ #ifdef HAVE_GETPWUID_R
56
+ char buf[USER_BUF_SIZE];
57
+ struct passwd pwd;
58
+ struct passwd* pwdbuf;
59
+
60
+ if(getpwuid_r(uid, &pwd, buf, sizeof(buf), &pwdbuf) != 0)
61
+ rb_raise(cAdminError, "%s", strerror(errno));
62
+
63
+ if(!pwdbuf)
64
+ rb_raise(cAdminError, "no user found for %i:", uid);
65
+
66
+ rbUser = get_user(pwdbuf);
67
+ #elif HAVE_GETPWUID
68
+ struct passwd* pwd;
69
+ if( (pwd = getpwuid(uid)) == NULL)
70
+ rb_raise(cAdminError, "no user found for: %i", uid);
71
+
72
+ rbUser = get_user(pwd);
73
+ #else
74
+ rb_raise(rb_eNotImpError, "getting user by user ID not supported");
75
+ #endif
76
+
77
+ return rbUser;
78
+ }
79
+
80
+ /*
81
+ * :no-doc:
82
+ *
83
+ * Helper function that returns a User object based on name.
84
+ */
85
+ static VALUE get_user_by_name(VALUE rbName){
86
+ VALUE rbUser;
87
+ SafeStringValue(rbName);
88
+
89
+ #ifdef HAVE_GETPWNAM_R
90
+ char buf[USER_BUF_SIZE];
91
+ struct passwd pwd;
92
+ struct passwd* pwdbuf;
93
+
94
+ if(getpwnam_r(RSTRING(rbName)->ptr, &pwd, buf, sizeof(buf), &pwdbuf) != 0)
95
+ rb_raise(cAdminError, "%s", strerror(errno));
96
+
97
+ if(!pwdbuf)
98
+ rb_raise(cAdminError, "no user found for %s", StringValuePtr(rbName));
99
+
100
+ rbUser = get_user(pwdbuf);
101
+ #elif HAVE_GETPWNAM
102
+ struct passwd* pwd;
103
+ if( (pwd = getpwnam(RSTRING(rbName)->ptr)) == NULL)
104
+ rb_raise(cAdminError, "no user found for %s", StringValuePtr(rbName));
105
+
106
+ rbUser = get_user(pwd);
107
+ #else
108
+ rb_raise(rb_eNotImpError, "getting user by name not supported");
109
+ #endif
110
+
111
+ return rbUser;
112
+ }
113
+
114
+ /*
115
+ * :no-doc:
116
+ *
117
+ * Helper function that returns a Group object based on group ID.
118
+ */
119
+ static VALUE get_group_by_num(VALUE rbGID){
120
+ VALUE rbGroup;
121
+ gid_t gid = NUM2INT(rbGID);
122
+
123
+ #ifdef HAVE_GETGRGID_R
124
+ char buf[GROUP_BUF_SIZE];
125
+ struct group grp;
126
+ struct group* grpbuf;
127
+
128
+ if(getgrgid_r(gid, &grp, buf, sizeof(buf), &grpbuf) != 0)
129
+ rb_raise(cAdminError, "%s", strerror(errno));
130
+
131
+ if(!grpbuf)
132
+ rb_raise(cAdminError, "no group found for group ID: %i", gid);
133
+
134
+ rbGroup = get_group(grpbuf);
135
+ #elif HAVE_GETGRGID
136
+ struct group* grp;
137
+ if( (grp = getgrgid(gid)) == NULL)
138
+ rb_raise(cAdminError, "no group found for group ID: %i", gid);
139
+
140
+ rbGroup = get_group(grp);
141
+ #else
142
+ rb_raise(rb_eNotImpError, "getting group by group ID not supported");
143
+ #endif
144
+
145
+ return rbGroup;
146
+ }
147
+
148
+ /*
149
+ * :no-doc:
150
+ *
151
+ * Helper function that returns a Group object based on group name.
152
+ */
153
+ static VALUE get_group_by_name(VALUE rbName){
154
+ VALUE rbGroup = Qnil;
155
+ SafeStringValue(rbName);
156
+ #ifdef HAVE_GETGRNAM_R
157
+ char buf[GROUP_BUF_SIZE];
158
+ struct group grp;
159
+ struct group* grpbuf;
160
+
161
+ if(getgrnam_r(RSTRING(rbName)->ptr, &grp, buf, sizeof(buf), &grpbuf) != 0)
162
+ rb_raise(cAdminError, "%s", strerror(errno));
163
+
164
+ if(!grpbuf)
165
+ rb_raise(cAdminError, "no group found for: %s", StringValuePtr(rbName));
166
+
167
+ rbGroup = get_group(grpbuf);
168
+ #elif HAVE_GETGRNAM
169
+ struct group* grp
170
+ if((grp = getgrnam(RSTRING(rbName)->ptr)) == NULL)
171
+ rb_raise(cAdminError, "no group found for: %s", StringValuePtr(rbName));
172
+
173
+ rbGroup = get_group(grp);
174
+ #else
175
+ rb_raise(rb_eNotImpError,"get_group is not supported on this platform");
176
+ #endif
177
+
178
+ return rbGroup;
179
+ }
180
+
181
+ /*
182
+ * :no-doc:
183
+ *
184
+ * Helper function that turns a struct passwd into a User object.
185
+ */
186
+ static VALUE get_user(struct passwd* p){
187
+ VALUE rbUser = rb_funcall(cUser,rb_intern("new"),0,0);
188
+
189
+ rb_iv_set(rbUser, "@name", rb_str_new2(p->pw_name));
190
+ rb_iv_set(rbUser, "@uid", INT2FIX(p->pw_uid));
191
+ rb_iv_set(rbUser, "@gid", INT2FIX(p->pw_gid));
192
+ rb_iv_set(rbUser, "@dir", rb_str_new2(p->pw_dir));
193
+ rb_iv_set(rbUser, "@shell", rb_str_new2(p->pw_shell));
194
+
195
+ #ifdef HAVE_ST_PW_PASSWD
196
+ rb_iv_set(rbUser, "@passwd", rb_str_new2(p->pw_passwd));
197
+ #endif
198
+
199
+ #ifdef HAVE_ST_PW_AGE
200
+ rb_iv_set(rbUser, "@age", INT2FIX(p->pw_age));
201
+ #endif
202
+
203
+ #ifdef HAVE_ST_PW_COMMENT
204
+ rb_iv_set(rbUser, "@comment", rb_str_new2(p->pw_comment));
205
+ #endif
206
+
207
+ #ifdef HAVE_ST_PW_GECOS
208
+ rb_iv_set(rbUser, "@gecos", rb_str_new2(p->pw_gecos));
209
+ #endif
210
+
211
+ #ifdef HAVE_ST_PW_QUOTA
212
+ rb_iv_set(rbUser, "@quota", INT2FIX(p->pw_quota));
213
+ #endif
214
+
215
+ #ifdef HAVE_ST_PW_CLASS
216
+ rb_iv_set(rbUser, "@class", rb_str_new2(p->pw_class));
217
+ #endif
218
+
219
+ #ifdef HAVE_ST_PW_EXPIRE
220
+ rb_iv_set(rbUser, "@expire", INT2FIX(p->pw_expire));
221
+ #endif
222
+
223
+ /* Get the lastlog info for the given user */
224
+ get_lastlog_info(p->pw_name, rbUser);
225
+
226
+ return rbUser;
227
+ }
228
+
229
+ /*
230
+ * :no-doc:
231
+ *
232
+ * Helper function that turns a User object into a struct passwd.
233
+ */
234
+ void get_user_from_value(VALUE rbUser, struct passwd* pwd){
235
+
236
+ VALUE rbName = rb_iv_get(rbUser, "@name");
237
+ VALUE rbUID = rb_iv_get(rbUser, "@uid");
238
+ VALUE rbGID = rb_iv_get(rbUser, "@gid");
239
+ VALUE rbDir = rb_iv_get(rbUser, "@dir");
240
+ VALUE rbShell = rb_iv_get(rbUser, "@shell");
241
+
242
+ if(NIL_P(rbName))
243
+ rb_raise(cAdminError, "user name cannot be nil");
244
+
245
+ if(!NIL_P(rbUID))
246
+ pwd->pw_uid = NUM2INT(rbUID);
247
+
248
+ if(!NIL_P(rbGID))
249
+ pwd->pw_gid = NUM2INT(rbGID);
250
+
251
+ if(!NIL_P(rbDir)){
252
+ SafeStringValue(rbDir);
253
+ pwd->pw_dir = StringValuePtr(rbDir);
254
+ }
255
+
256
+ if(!NIL_P(rbShell)){
257
+ SafeStringValue(rbShell);
258
+ pwd->pw_shell = StringValuePtr(rbShell);
259
+ }
260
+
261
+ #ifdef HAVE_ST_PW_PASSWD
262
+ VALUE rbPasswd = rb_iv_get(rbUser, "@passwd");
263
+ if(!NIL_P(rbPasswd)){
264
+ SafeStringValue(rbPasswd);
265
+ pwd->pw_passwd = StringValuePtr(rbPasswd);
266
+ }
267
+ #endif
268
+
269
+ #ifdef HAVE_ST_PW_AGE
270
+ VALUE rbAge = rb_iv_get(rbUser, "@age");
271
+ if(!NIL_P(rbAge))
272
+ pwd->pw_age = (char*)NUM2INT(rbAge);
273
+ #endif
274
+
275
+ #ifdef HAVE_ST_PW_COMMENT
276
+ VALUE rbComment = rb_iv_get(rbUser, "@comment");
277
+ if(!NIL_P(rbComment)){
278
+ SafeStringValue(rbComment);
279
+ pwd->pw_comment = StringValuePtr(rbComment);
280
+ }
281
+ #endif
282
+
283
+ #ifdef HAVE_ST_PW_GECOS
284
+ VALUE rbGecos = rb_iv_get(rbUser, "@gecos");
285
+ if(!NIL_P(rbGecos)){
286
+ SafeStringValue(rbGecos);
287
+ pwd->pw_gecos = StringValuePtr(rbGecos);
288
+ }
289
+ #endif
290
+
291
+ #ifdef HAVE_ST_PW_QUOTA
292
+ VALUE rbQuota = rb_iv_get(rbUser, "@quota");
293
+ if(!NIL_P(rbQuota))
294
+ pwd->pw_quota = NUM2INT(rbQuota);
295
+ #endif
296
+
297
+ #ifdef HAVE_ST_PW_CLASS
298
+ VALUE rbClass = rb_iv_get(rbUser, "@class");
299
+ if(!NIL_P(rbClass)){
300
+ SafeStringValue(rbClass);
301
+ pwd->pw_class = StringValuePtr(rbClass);
302
+ }
303
+ #endif
304
+
305
+ #ifdef HAVE_ST_PW_EXPIRE
306
+ VALUE rbExpire = rb_iv_get(rbUser, "@expire");
307
+ if(!NIL_P(rbExpire))
308
+ pwd->pw_expire = NUM2INT(rbExpire);
309
+ #endif
310
+
311
+ }
312
+
313
+ /*
314
+ * :no-doc:
315
+ *
316
+ * Helper function that turns a struct grp into a Group object.
317
+ */
318
+ static VALUE get_group(struct group* g){
319
+ VALUE rbGroup = rb_funcall(cGroup,rb_intern("new"),0,0);
320
+ VALUE rbArray = rb_ary_new();
321
+
322
+ /* Return the members as an Array of Strings */
323
+ while(*g->gr_mem){
324
+ rb_ary_push(rbArray, rb_str_new2(*g->gr_mem));
325
+ g->gr_mem++;
326
+ }
327
+
328
+ rb_iv_set(rbGroup, "@name", rb_str_new2(g->gr_name));
329
+ rb_iv_set(rbGroup, "@gid", INT2FIX(g->gr_gid));
330
+ rb_iv_set(rbGroup, "@members", rbArray);
331
+ #ifdef HAVE_ST_GR_PASSWD
332
+ rb_iv_set(rbGroup, "@passwd", rb_str_new2(g->gr_passwd));
333
+ #endif
334
+
335
+ return rbGroup;
336
+ }
337
+
338
+ /*
339
+ * :no-doc:
340
+ *
341
+ * Helper function that turns a Group object into a struct group.
342
+ */
343
+ void get_group_from_value(VALUE rbGroup, struct group* grp){
344
+ char** members = malloc(sizeof(char*));
345
+ VALUE rbName = rb_iv_get(rbGroup, "@name");
346
+ VALUE rbGID = rb_iv_get(rbGroup, "@gid");
347
+ VALUE rbMem = rb_iv_get(rbGroup, "@members");
348
+ VALUE rbPasswd = rb_iv_get(rbGroup, "@passwd");
349
+ int i = 0;
350
+
351
+ if(NIL_P(rbName))
352
+ rb_raise(cAdminError, "group name must be set");
353
+
354
+ SafeStringValue(rbName);
355
+ grp->gr_name = StringValuePtr(rbName);
356
+
357
+ if(!NIL_P(rbGID))
358
+ grp->gr_gid = NUM2INT(rbGID);
359
+
360
+ if(!NIL_P(rbMem)){
361
+ VALUE rbVal;
362
+ while((rbVal = rb_ary_shift(rbMem)) != Qnil){
363
+ members[i] = StringValuePtr(rbVal);
364
+ i++;
365
+ }
366
+ members[i] = '\0';
367
+ grp->gr_mem = members;
368
+ }
369
+
370
+ #ifdef HAVE_ST_GR_PASSWD
371
+ if(!NIL_P(rbPasswd)){
372
+ SafeStringValue(rbPasswd);
373
+ grp->gr_passwd = StringValuePtr(rbPasswd);
374
+ }
375
+ #endif
376
+
377
+ free(members);
378
+ }
379
+
380
+ /*
381
+ * :no-doc:
382
+ *
383
+ * Helper function that gets lastlog information for the User object.
384
+ */
385
+ int get_lastlog_info(const char* name, VALUE rbUser){
386
+ int fd;
387
+ struct lastlog log;
388
+ struct passwd* pwd;
389
+ int ll_size = sizeof(struct lastlog);
390
+
391
+ /* The lastlog information is not necessarily readable by all users, so
392
+ * ignore open() errors if they occur.
393
+ */
394
+ if((fd = open(_PATH_LASTLOG, O_RDONLY)) == -1)
395
+ return -1;
396
+
397
+ if((pwd = getpwnam(name)) == NULL)
398
+ rb_sys_fail(0);
399
+
400
+ pread(fd, &log, ll_size, pwd->pw_uid * ll_size);
401
+ close(fd);
402
+
403
+ #ifdef HAVE_ST_LL_TIME
404
+ if(log.ll_time != 0)
405
+ rb_iv_set(rbUser, "@login_time", rb_time_new(log.ll_time, 0));
406
+ #endif
407
+ rb_iv_set(rbUser, "@login_device", rb_str_new2(log.ll_line));
408
+ rb_iv_set(rbUser, "@login_host", rb_str_new2(log.ll_host));
409
+
410
+ return 0;
411
+ }
@@ -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