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.
- data/CHANGES +31 -0
- data/MANIFEST +17 -0
- data/README +174 -0
- data/examples/groups.rb +39 -0
- data/examples/users.rb +35 -0
- data/extconf.rb +62 -0
- data/lib/sys/unix.c +283 -0
- data/lib/sys/unix.h +411 -0
- data/lib/sys/win32.orig +403 -0
- data/test/tc_admin.rb +14 -0
- data/test/tc_unix.rb +78 -0
- data/test/tc_win32.rb +248 -0
- metadata +57 -0
data/lib/sys/unix.h
ADDED
@@ -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
|
+
}
|
data/lib/sys/win32.orig
ADDED
@@ -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
|