etcutils 1.0.0

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,27 @@
1
+ # coding: utf-8
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require 'etcutils/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "etcutils"
7
+ spec.version = EtcUtils::VERSION
8
+ spec.platform = Gem::Platform::RUBY
9
+ spec.authors = ["David Campbell"]
10
+ spec.email = "david@mrcampbell.org"
11
+ spec.description = "Ruby Extension that allows for reads and writes to the /etc user db."
12
+ spec.summary = %q{This gem is specific to *nix environments, allowing for reads and writes to passwd,shadow,group, and gshadow /etc files. It is inspired by Std-lib Etc and the Gem libshadow-ruby however modified to use classes rather than structs to allow for future growth. There are probably still bugs, so use at your own risk.}
13
+ spec.homepage = "https://github.com/dacamp/etcutils"
14
+ spec.licenses = ["MIT"]
15
+
16
+ spec.extensions = ['ext/etcutils/extconf.rb']
17
+ spec.files = `git ls-files`.split($/)
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = [ 'lib', 'ext' ]
20
+
21
+
22
+ spec.has_rdoc = false
23
+
24
+ spec.add_development_dependency "bundler"
25
+ spec.add_development_dependency "rake"
26
+ spec.add_development_dependency "rake-compiler"
27
+ end
@@ -0,0 +1,1398 @@
1
+ /********************************************************************
2
+
3
+ Ruby C Extension for read write access to the Linux user database
4
+
5
+ Copyright (C) 2013 David Campbell
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining
8
+ a copy of this software and associated documentation files (the
9
+ "Software"), to deal in the Software without restriction, including
10
+ without limitation the rights to use, copy, modify, merge, publish,
11
+ distribute, sublicense, and/or sell copies of the Software, and to
12
+ permit persons to whom the Software is furnished to do so, subject to
13
+ the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be
16
+ included in all copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
22
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
+ SOFTWARE.
26
+
27
+ ********************************************************************/
28
+ #include <unistd.h>
29
+ #include <time.h>
30
+ #include "etcutils.h"
31
+
32
+ VALUE mEtcUtils;
33
+ ID id_name, id_passwd, id_uid, id_gid;
34
+ static VALUE uid_global;
35
+ static VALUE gid_global;
36
+ static VALUE assigned_uids;
37
+ static VALUE assigned_gids;
38
+
39
+ /* Start of helper functions */
40
+ VALUE next_uid(int argc, VALUE *argv, VALUE self)
41
+ {
42
+ VALUE i;
43
+ uid_t req;
44
+
45
+ rb_scan_args(argc, argv, "01", &i);
46
+ if (NIL_P(i))
47
+ i = uid_global;
48
+
49
+ i = rb_Integer(i);
50
+ req = NUM2UINT(i);
51
+
52
+ if ( req > ((unsigned int)65533) )
53
+ rb_raise(rb_eArgError, "UID must be between 0 and 65533");
54
+
55
+ while ( getpwuid(req) || rb_ary_includes(assigned_uids, UINT2NUM(req)) ) req++;
56
+ if (!argc)
57
+ rb_ary_push(assigned_uids, UINT2NUM(req));
58
+ else
59
+ uid_global = UINT2NUM(req);
60
+
61
+ return UINT2NUM(req);
62
+ }
63
+
64
+ VALUE next_gid(int argc, VALUE *argv, VALUE self)
65
+ {
66
+ VALUE i;
67
+ gid_t req;
68
+
69
+ rb_scan_args(argc, argv, "01", &i);
70
+ if (NIL_P(i))
71
+ i = gid_global;
72
+
73
+ i = rb_Integer(i);
74
+ req = NUM2UINT(i);
75
+
76
+ if ( req > ((unsigned int)65533) )
77
+ rb_raise(rb_eArgError, "GID must be between 0 and 65533");
78
+
79
+ while ( getgrgid(req) || rb_ary_includes(assigned_gids, UINT2NUM(req)) ) req++;
80
+ if (!argc)
81
+ rb_ary_push(assigned_gids, UINT2NUM(req));
82
+ else
83
+ gid_global = UINT2NUM(req);
84
+
85
+ return UINT2NUM(req);
86
+ }
87
+
88
+ VALUE iv_get_time(VALUE self, const char *name)
89
+ {
90
+ VALUE e;
91
+ time_t t;
92
+ e = rb_iv_get(self, name);
93
+
94
+ if (NIL_P(e) || NUM2INT(e) < 0)
95
+ return Qnil;
96
+
97
+ t = NUM2INT(e) * 86400;
98
+ return rb_time_new(t, 0);
99
+ }
100
+
101
+ VALUE iv_set_time(VALUE self, VALUE v, const char *name)
102
+ {
103
+ struct timeval t;
104
+ long int d;
105
+
106
+ RTIME_VAL(t) = rb_time_timeval(v);
107
+ d = ((long)t.tv_sec / 86400);
108
+
109
+ if (FIXNUM_P(v) && d == 0 && t.tv_sec == NUM2INT(v))
110
+ d = NUM2INT(v);
111
+ else if (d < 1)
112
+ d = -1;
113
+
114
+ return rb_iv_set(self, name, INT2NUM(d));
115
+ }
116
+
117
+ VALUE rb_current_time()
118
+ {
119
+ time_t s;
120
+ s = time(NULL);
121
+ return rb_time_new(s, ((time_t)0));
122
+ }
123
+
124
+ void
125
+ eu_errno(VALUE str)
126
+ {
127
+ /*
128
+ SafeStringValue(str);
129
+ if ( (errno) && ( !(errno == ENOTTY) || !(errno == ENOENT) ) )
130
+ rb_sys_fail( StringValuePtr(str) );
131
+ Errno::ENOTTY: Inappropriate ioctl for device
132
+ https://bugs.ruby-lang.org/issues/6127
133
+ ioctl range error in 1.9.3
134
+ Fixed in 1.9.3-p194 (REVISION r37138)
135
+ Ubuntu System Ruby (via APT) - 1.9.3-p0 (REVISION 33570)
136
+ errno = 0;
137
+ */
138
+ }
139
+
140
+ void ensure_eu_type(VALUE self, VALUE klass)
141
+ {
142
+ if (!rb_obj_is_kind_of(self, klass))
143
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected %s)",
144
+ rb_obj_classname(self), rb_class2name(klass));
145
+ }
146
+
147
+ void ensure_file(VALUE io)
148
+ {
149
+ rb_io_check_initialized(RFILE(io)->fptr);
150
+ }
151
+
152
+ void ensure_writes(VALUE io, int t)
153
+ {
154
+ ensure_file(io);
155
+ if (!( ((RFILE(io)->fptr)->mode) & t ))
156
+ rb_raise(rb_eIOError, "not opened for writing");
157
+ }
158
+
159
+
160
+
161
+ /* Validate (s)group members/admins
162
+ void confirm_members(char ** mem)
163
+ {
164
+ char *name;
165
+
166
+ while(name = *mem++)
167
+ if (!getpwnam(name))
168
+ rb_raise(rb_eArgError,
169
+ "%s was not found in '%s'", name, PASSWD);
170
+ }
171
+ */
172
+
173
+ void free_char_members(char ** mem, int c)
174
+ {
175
+ if (NULL != mem) {
176
+ int i;
177
+ for (i=0; i<c+1 ; i++) free(mem[i]);
178
+ free(mem);
179
+ }
180
+ }
181
+
182
+ char** setup_char_members(VALUE ary)
183
+ {
184
+ char ** mem;
185
+ VALUE tmp,last;
186
+ long i,off;
187
+ Check_Type(ary,T_ARRAY);
188
+
189
+ mem = malloc((RARRAY_LEN(ary) + 1)*sizeof(char**));
190
+ if (mem == NULL)
191
+ rb_memerror();
192
+
193
+ rb_ary_sort_bang(ary);
194
+ last = rb_str_new2("");
195
+ off = 0;
196
+
197
+ for (i = 0; i < RARRAY_LEN(ary); i++) {
198
+ tmp = rb_obj_as_string(RARRAY_PTR(ary)[i]);
199
+ if ( (rb_str_cmp(tmp, last)) ) {
200
+ StringValueCStr(tmp);
201
+ mem[i-off] = malloc((RSTRING_LEN(tmp))*sizeof(char*));;
202
+
203
+ if (mem[i-off] == NULL) rb_memerror();
204
+ strcpy(mem[i-off], RSTRING_PTR(tmp));
205
+ } else
206
+ off++;
207
+
208
+ last = tmp;
209
+ }
210
+ mem[i-off] = NULL;
211
+
212
+ return mem;
213
+ }
214
+
215
+ VALUE setup_safe_str(const char *str)
216
+ {
217
+ return rb_tainted_str_new2(str); // this already handles characters >= 0
218
+ }
219
+
220
+ VALUE setup_safe_array(char **arr)
221
+ {
222
+ VALUE mem = rb_ary_new();
223
+
224
+ while (*arr)
225
+ rb_ary_push(mem, setup_safe_str(*arr++));
226
+ return mem;
227
+ }
228
+ /* End of helper functions */
229
+
230
+ /* set/end syscalls */
231
+ VALUE eu_setpwent(VALUE self)
232
+ {
233
+ #ifdef HAVE_SETPWENT
234
+ setpwent();
235
+ #endif
236
+ return Qnil;
237
+ }
238
+
239
+ VALUE eu_endpwent(VALUE self)
240
+ {
241
+ #ifdef HAVE_ENDPWENT
242
+ endpwent();
243
+ #endif
244
+ return Qnil;
245
+ }
246
+
247
+ VALUE eu_setspent(VALUE self)
248
+ {
249
+ #ifdef HAVE_SETSPENT
250
+ setspent();
251
+ #endif
252
+ return Qnil;
253
+ }
254
+
255
+ VALUE eu_endspent(VALUE self)
256
+ {
257
+ #ifdef HAVE_ENDSPENT
258
+ endspent();
259
+ #endif
260
+ return Qnil;
261
+ }
262
+
263
+ VALUE eu_setsgent(VALUE self)
264
+ {
265
+ #ifdef HAVE_SETSGENT
266
+ setsgent();
267
+ #endif
268
+ return Qnil;
269
+ }
270
+
271
+ VALUE eu_endsgent(VALUE self)
272
+ {
273
+ #ifdef HAVE_ENDSGENT
274
+ endsgent();
275
+ #endif
276
+ return Qnil;
277
+ }
278
+
279
+ VALUE eu_setgrent(VALUE self)
280
+ {
281
+ #ifdef HAVE_SETGRENT
282
+ setgrent();
283
+ #endif
284
+ return Qnil;
285
+ }
286
+
287
+ VALUE eu_endgrent(VALUE self)
288
+ {
289
+ #ifdef HAVE_ENDGRENT
290
+ endgrent();
291
+ #endif
292
+ return Qnil;
293
+ }
294
+
295
+ /* INPUT Examples:
296
+ * - CURRENT USERS
297
+ * - bin:x:2:2:bin:/bin:/bin/bash
298
+ * - bin:x:::bin:/bin:/bin/bash
299
+ * - bin:x:::bin:/bin:/bin/sh
300
+ * - bin:x:::bin:/bin:/bin/sh
301
+ * - bin:x:::Bin User:/bin:/bin/sh
302
+ *
303
+ * CURRENT USER
304
+ * iff *one* of uid/gid is empty
305
+ * - if VAL is NOT equal to VAL in PASSWD
306
+ * - if VAL is available
307
+ * - Populate VAL
308
+ * - else raise error
309
+ * - else Populate VAL
310
+ * if PASSWORD, UID, GID, GECOS, HOMEDIR, SHELL are empty
311
+ * - populate VALUE from PASSWD
312
+ */
313
+ VALUE eu_parsecurrent(VALUE str, VALUE ary)
314
+ {
315
+ struct passwd *pwd;
316
+ pwd = getpwnam( StringValuePtr(str) );
317
+
318
+ // Password
319
+ str = rb_ary_entry(ary,1);
320
+ if ( ! rb_eql( setup_safe_str(pwd->pw_passwd), str) )
321
+ pwd->pw_passwd = StringValuePtr(str);
322
+
323
+ // UID/GID
324
+ if ( ! RSTRING_BLANK_P( (str = rb_ary_entry(ary,2)) ) ) {
325
+ str = rb_Integer( str );
326
+ if ( ! rb_eql( INT2FIX(pwd->pw_uid), str ) )
327
+ pwd->pw_uid = NUM2UIDT(str);
328
+ }
329
+
330
+ if ( ! RSTRING_BLANK_P( (str = rb_ary_entry(ary,3)) ) ) {
331
+ str = rb_Integer( str );
332
+ if ( getgrgid(NUM2GIDT(str)) )
333
+ pwd->pw_gid = NUM2GIDT(str);
334
+ }
335
+
336
+ // GECOS
337
+ str = rb_ary_entry(ary,4);
338
+ if ( ! rb_eql( setup_safe_str(pwd->pw_gecos), str) )
339
+ pwd->pw_gecos = StringValuePtr(str);
340
+
341
+ // Directory
342
+ str = rb_ary_entry(ary,5);
343
+ if ( ! rb_eql( setup_safe_str(pwd->pw_dir), str) )
344
+ pwd->pw_dir = StringValuePtr(str);
345
+
346
+ // Shell
347
+ str = rb_ary_entry(ary,6);
348
+ if ( ! rb_eql( setup_safe_str(pwd->pw_shell), str) ) {
349
+ SafeStringValue(str);
350
+ pwd->pw_shell = StringValuePtr(str);
351
+ }
352
+
353
+ return setup_passwd(pwd);
354
+ }
355
+
356
+ /* INPUT Examples:
357
+ * - NEW USERS
358
+ * - newuser:x:1000:1000:New User:/home/newuser:/bin/bash
359
+ * - newuser:x:::New User:/home/newuser:/bin/bash
360
+ * - newuser:x:::New User::/bin/bash
361
+ *
362
+ */
363
+ VALUE eu_parsenew(VALUE self, VALUE ary)
364
+ {
365
+ VALUE uid, gid, tmp, nam;
366
+ struct passwd *pwd;
367
+ struct group *grp;
368
+ int i = 0;
369
+
370
+ pwd = malloc(sizeof *pwd);
371
+
372
+ nam = rb_ary_entry(ary,i++);
373
+ pwd->pw_name = StringValuePtr(nam);
374
+
375
+ /* Setup password field
376
+ * if PASSWORD is empty
377
+ * - if SHADOW
378
+ * - PASSWORD equals 'x'
379
+ * - else
380
+ * - PASSWORD equals '*'
381
+ */
382
+ tmp = rb_ary_entry(ary,i++);
383
+ if (RSTRING_BLANK_P(tmp))
384
+ tmp = PW_DEFAULT_PASS;
385
+
386
+ pwd->pw_passwd = StringValuePtr(tmp);
387
+
388
+ /* Setup UID field */
389
+ uid = rb_ary_entry(ary,i++);
390
+ gid = rb_ary_entry(ary,i++);
391
+
392
+ /* if UID Test availability */
393
+ if (! RSTRING_BLANK_P(uid))
394
+ next_uid(1, &uid, self);
395
+
396
+ uid = next_uid(0, 0, self);
397
+
398
+ /* if GID empty
399
+ * - if USERNAME found in /etc/group
400
+ * - GID equals struct group->gid
401
+ * - else next_gid
402
+ * else if GID < 1000
403
+ * - assign GID
404
+ * - else
405
+ * - next_gid
406
+ */
407
+ if (RSTRING_BLANK_P(gid))
408
+ if ( (grp = getgrnam( StringValuePtr(nam) )) ) // Found a group with the same name
409
+ gid = GIDT2NUM(grp->gr_gid);
410
+ else {
411
+ next_gid(1, &uid, self);
412
+ gid = next_gid(0, 0, self);
413
+ }
414
+ else {
415
+ tmp = rb_Integer(gid);
416
+ if ( (NUM2UINT(tmp) != 0) && ( NUM2UINT(tmp) < ((unsigned int)1000)) )
417
+ gid = tmp;
418
+ else {
419
+ next_gid(1, &tmp, self);
420
+ gid = next_gid(0, 0, self);
421
+ }
422
+ }
423
+
424
+ pwd->pw_uid = NUM2UIDT(uid);
425
+ pwd->pw_gid = NUM2GIDT(gid);
426
+
427
+ /* _launchservicesd:*:239:239::0:0:_launchservicesd:/var/empty:/usr/bin/false */
428
+ /* daemon:x:1:1:daemon:/usr/sbin:/bin/sh */
429
+ #ifdef HAVE_ST_PW_CLASS
430
+ if ( RSTRING_BLANK_P(tmp = rb_ary_entry(ary, i)) )
431
+ tmp = setup_safe_str("");
432
+ pwd->pw_class = StringValuePtr( tmp );
433
+
434
+ i++;
435
+ #endif
436
+
437
+ #ifdef HAVE_ST_PW_CHANGE
438
+ if ( RSTRING_BLANK_P(tmp = rb_ary_entry(ary,i)) )
439
+ tmp = setup_safe_str("0");
440
+
441
+ pwd->pw_change = (time_t)NUM2UIDT((VALUE)rb_Integer( tmp ));
442
+ i++;
443
+ #endif
444
+
445
+
446
+ #ifdef HAVE_ST_PW_EXPIRE
447
+ if ( RSTRING_BLANK_P(tmp = rb_ary_entry(ary,i)) )
448
+ tmp = setup_safe_str("0");
449
+
450
+ pwd->pw_expire = (time_t)NUM2UIDT((VALUE)rb_Integer( tmp ));
451
+ i++;
452
+ #endif
453
+
454
+ /* if GECOS, HOMEDIR, SHELL is empty
455
+ * - GECOS defaults to USERNAME
456
+ * - Assign default VALUE (Need to set config VALUES)
457
+ */
458
+ if ( RSTRING_BLANK_P(tmp = rb_ary_entry(ary,i)) )
459
+ tmp = nam;
460
+ pwd->pw_gecos = StringValuePtr( tmp );
461
+ i++;
462
+
463
+ if ( RSTRING_BLANK_P(tmp = rb_ary_entry(ary,i)) )
464
+ tmp = rb_str_plus(setup_safe_str("/home/"), nam);
465
+ pwd->pw_dir = StringValuePtr( tmp );
466
+ i++;
467
+
468
+
469
+ /* This might be a null, indicating that the system default
470
+ * should be used.
471
+ */
472
+ if (RSTRING_BLANK_P(tmp = rb_ary_entry(ary,i)) )
473
+ tmp = setup_safe_str(DEFAULT_SHELL);
474
+ pwd->pw_shell = StringValuePtr( tmp );
475
+
476
+ tmp = setup_passwd(pwd);
477
+
478
+ if (pwd)
479
+ free(pwd);
480
+ return tmp;
481
+ }
482
+ /* End of set/end syscalls */
483
+
484
+ /* INPUT Examples:
485
+ * - CURRENT USERS
486
+ * - bin:x:2:2:bin:/bin:/bin/bash
487
+ * - bin:x:::bin:/bin:/bin/bash
488
+ * - bin:x:::bin:/bin:/bin/sh
489
+ * - bin:x:::bin:/bin:/bin/sh
490
+ * - bin:x:::Bin User:/bin:/bin/sh
491
+ *
492
+ * - NEW USERS
493
+ * - newuser:x:1000:1000:New User:/home/newuser:/bin/bash
494
+ * - newuser:x:::New User:/home/newuser:/bin/bash
495
+ * - newuser:x:::New User::/bin/bash
496
+ *
497
+ * UNIVERSAL BEHAVIOR
498
+ * if USERNAME empty
499
+ * - raise error
500
+ * CURRENT USER
501
+ * iff one of uid/gid is empty
502
+ * - if VAL is NOT equal to VAL in PASSWD
503
+ * - if VAL is available
504
+ * - Populate VAL
505
+ * - else raise error
506
+ * - else Populate VAL
507
+ * if PASSWORD, UID, GID, GECOS, HOMEDIR, SHELL are empty
508
+ * - populate VALUE from PASSWD
509
+ * NEW USER
510
+ * if UID/GID are empty
511
+ * - next_uid/next_gid
512
+ * else
513
+ * - Test VALUE availability
514
+ * then
515
+ * - Populate UID/GID
516
+ * if GECOS, HOMEDIR, SHELL is empty
517
+ * - GECOS defaults to USERNAME
518
+ * - Assign default VALUE (Need to set config VALUES)
519
+ * if PASSWORD is empty
520
+ * - raise Error
521
+ *
522
+ */
523
+ VALUE eu_sgetpwent(VALUE self, VALUE str)
524
+ {
525
+ VALUE ary;
526
+
527
+ eu_setpwent(self);
528
+ eu_setgrent(self);
529
+
530
+ ary = rb_str_split(str, ":");
531
+ str = rb_ary_entry(ary,0);
532
+
533
+ if (RSTRING_BLANK_P(str))
534
+ rb_raise(rb_eArgError,"User name must be present.");
535
+
536
+ if (getpwnam( StringValuePtr(str) ))
537
+ return eu_parsecurrent(str, ary);
538
+ else
539
+ return eu_parsenew(self, ary);
540
+ }
541
+
542
+ VALUE eu_sgetspent(VALUE self, VALUE nam)
543
+ {
544
+ #ifdef SHADOW
545
+ struct spwd *shadow;
546
+
547
+ SafeStringValue(nam);
548
+ if ( !(shadow = sgetspent(StringValuePtr(nam))) )
549
+ rb_raise(rb_eArgError,
550
+ "can't parse %s into EtcUtils::Shadow", StringValuePtr(nam));
551
+
552
+ return setup_shadow(shadow);
553
+ #else
554
+ return Qnil;
555
+ #endif
556
+ }
557
+
558
+ // name:passwd:gid:members
559
+ static VALUE eu_grp_cur(VALUE str, VALUE ary)
560
+ {
561
+ struct group *grp;
562
+ grp = getgrnam( StringValuePtr(str) );
563
+
564
+ // Password
565
+ str = rb_ary_entry(ary,1);
566
+ if ( ! rb_eql( setup_safe_str(grp->gr_passwd), str) )
567
+ grp->gr_passwd = StringValuePtr(str);
568
+
569
+ // GID
570
+ if ( ! RSTRING_BLANK_P( (str = rb_ary_entry(ary,2)) ) ) {
571
+ str = rb_Integer( str );
572
+ if ( !getgrgid(NUM2GIDT(str)) )
573
+ grp->gr_gid = NUM2GIDT(str);
574
+ }
575
+
576
+ // Group Members
577
+ if ( RSTRING_BLANK_P( (str = rb_ary_entry(ary,3)) ))
578
+ str = rb_str_new2("");
579
+
580
+ ary = rb_str_split(str,",");
581
+ if ( ! rb_eql( setup_safe_array(grp->gr_mem), ary) )
582
+ grp->gr_mem = setup_char_members( ary );
583
+
584
+ return setup_group(grp);
585
+ }
586
+
587
+ static VALUE eu_grp_new(VALUE self, VALUE ary)
588
+ {
589
+ VALUE gid, tmp, nam;
590
+ struct passwd *pwd;
591
+ struct group *grp;
592
+
593
+ grp = malloc(sizeof *grp);
594
+
595
+ nam = rb_ary_entry(ary,0);
596
+ grp->gr_name = StringValuePtr(nam);
597
+
598
+ /* Setup password field
599
+ * if PASSWORD is empty
600
+ * - if SHADOW
601
+ * - PASSWORD equals 'x'
602
+ * - else
603
+ * - PASSWORD equals '*'
604
+ */
605
+ tmp = rb_ary_entry(ary,1);
606
+ if (RSTRING_BLANK_P(tmp))
607
+ tmp = PW_DEFAULT_PASS;
608
+
609
+ grp->gr_passwd = StringValuePtr(tmp);
610
+
611
+ /* Setup GID field */
612
+ gid = rb_ary_entry(ary,2);
613
+
614
+ /* if GID empty
615
+ * - if USERNAME found in /etc/group
616
+ * - GID equals struct group->gid
617
+ * - else next_gid
618
+ * else
619
+ * - if UID value (as GID) found in /etc/group
620
+ * - next_gid
621
+ * - else
622
+ * - Test availability
623
+ */
624
+ if (RSTRING_BLANK_P(gid))
625
+ if ( (pwd = getpwnam( StringValuePtr(nam) )) ) // Found a group with the same name
626
+ gid = GIDT2NUM(pwd->pw_gid);
627
+ else
628
+ gid = next_gid(0, 0, self);
629
+ else {
630
+ if ( getgrgid( (gid_t) gid ) )
631
+ next_gid(1, &gid, self);
632
+ else if ( (tmp = rb_Integer( gid )) )
633
+ next_gid(1, &tmp, self);
634
+
635
+ gid = next_gid(0, 0, self);
636
+ }
637
+
638
+ grp->gr_gid = NUM2GIDT(gid);
639
+
640
+ if (RSTRING_BLANK_P(tmp = rb_ary_entry(ary,3)))
641
+ tmp = rb_str_new2("");
642
+ grp->gr_mem = setup_char_members( rb_str_split(tmp,",") );
643
+
644
+ nam = setup_group(grp);
645
+ free_char_members(grp->gr_mem, (int)RARRAY_LEN(rb_str_split(tmp,",")));
646
+
647
+ if (grp)
648
+ free(grp);
649
+ return nam;
650
+ }
651
+
652
+ // name:passwd:gid:members
653
+ VALUE eu_sgetgrent(VALUE self, VALUE str)
654
+ {
655
+ VALUE ary;
656
+
657
+ eu_setpwent(self);
658
+ eu_setgrent(self);
659
+
660
+ ary = rb_str_split(str, ":");
661
+ str = rb_ary_entry(ary,0);
662
+
663
+ if (RSTRING_BLANK_P(str))
664
+ rb_raise(rb_eArgError,"Group name must be present.");
665
+
666
+ if (getgrnam( StringValuePtr(str) ))
667
+ return eu_grp_cur(str, ary);
668
+ else
669
+ return eu_grp_new(self, ary);
670
+ }
671
+
672
+ VALUE eu_sgetsgent(VALUE self, VALUE nam)
673
+ {
674
+ #ifdef GSHADOW
675
+ struct sgrp *gshadow;
676
+
677
+ SafeStringValue(nam);
678
+ if ( !(gshadow = sgetsgent(StringValuePtr(nam))) )
679
+ rb_raise(rb_eArgError,
680
+ "can't parse %s into EtcUtils::GShadow", StringValuePtr(nam));
681
+
682
+ return setup_gshadow(gshadow);
683
+ #else
684
+ return Qnil;
685
+ #endif
686
+ }
687
+
688
+
689
+ /* fget* functions are not available on OSx/BSD based OSes */
690
+ #ifdef HAVE_FGETGRENT
691
+ static VALUE
692
+ eu_fgetgrent(VALUE self, VALUE io)
693
+ {
694
+ struct group *grp;
695
+
696
+ ensure_file(io);
697
+ if ( (grp = fgetgrent(RFILE_FPTR(io))) == NULL )
698
+ return Qnil;
699
+
700
+ return setup_group(grp);
701
+ }
702
+ #endif
703
+
704
+ #ifdef HAVE_FGETPWENT
705
+ static VALUE
706
+ eu_fgetpwent(VALUE self, VALUE io)
707
+ {
708
+ struct passwd *pwd;
709
+
710
+ ensure_file(io);
711
+ if ( (pwd = fgetpwent(RFILE_FPTR(io))) == NULL )
712
+ return Qnil;
713
+
714
+ return setup_passwd(pwd);
715
+ }
716
+ #endif
717
+
718
+ #ifdef HAVE_FGETSPENT
719
+ static VALUE
720
+ eu_fgetspent(VALUE self, VALUE io)
721
+ {
722
+ struct spwd *spwd;
723
+
724
+ ensure_file(io);
725
+ if ( (spwd = fgetspent(RFILE_FPTR(io))) == NULL )
726
+ return Qnil;
727
+
728
+ return setup_shadow(spwd);
729
+ }
730
+ #endif
731
+
732
+ #ifdef HAVE_FGETSGENT
733
+ static VALUE
734
+ eu_fgetsgent(VALUE self, VALUE io)
735
+ {
736
+ struct sgrp *sgroup;
737
+
738
+ ensure_file(io);
739
+ if ( (sgroup = fgetsgent(RFILE_FPTR(io))) == NULL )
740
+ return Qnil;
741
+
742
+ return setup_gshadow(sgroup);
743
+ }
744
+ #endif
745
+
746
+ VALUE eu_getpwd(VALUE self, VALUE v)
747
+ {
748
+ struct passwd *strt;
749
+ eu_setpwent(self);
750
+
751
+ if ( FIXNUM_P(v) )
752
+ strt = getpwuid(NUM2UIDT(v));
753
+ else {
754
+ SafeStringValue(v);
755
+ strt = getpwnam(StringValuePtr(v));
756
+ }
757
+
758
+ if (!strt)
759
+ return Qnil;
760
+
761
+ return setup_passwd(strt);
762
+ }
763
+
764
+ VALUE eu_getspwd(VALUE self, VALUE v)
765
+ {
766
+ #ifdef SHADOW
767
+ struct spwd *strt;
768
+ eu_setspent(self);
769
+
770
+ if ( FIXNUM_P(v) ) {
771
+ struct passwd *s;
772
+ if ( (s = getpwuid(NUM2UIDT(v))) )
773
+ v = rb_str_new2(s->pw_name);
774
+ else
775
+ return Qnil;
776
+ }
777
+
778
+ SafeStringValue(v);
779
+ strt = getspnam(StringValuePtr(v));
780
+
781
+ if (!strt)
782
+ return Qnil;
783
+
784
+ return setup_shadow(strt);
785
+ #else
786
+ return Qnil;
787
+ #endif
788
+ }
789
+
790
+ VALUE eu_getsgrp(VALUE self, VALUE v)
791
+ {
792
+ #ifdef GSHADOW
793
+ struct sgrp *strt;
794
+ eu_setsgent(self);
795
+
796
+ if ( FIXNUM_P(v) ) {
797
+ struct group *s;
798
+ if ( (s = getgrgid(NUM2UIDT(v))) )
799
+ v = setup_safe_str(s->gr_name);
800
+ }
801
+
802
+ SafeStringValue(v);
803
+ strt = getsgnam(StringValuePtr(v));
804
+
805
+ if (!strt)
806
+ return Qnil;
807
+
808
+ return setup_gshadow(strt);
809
+ #else
810
+ return Qnil;
811
+ #endif
812
+ }
813
+
814
+ VALUE eu_getgrp(VALUE self, VALUE v)
815
+ {
816
+ struct group *strt;
817
+ eu_setgrent(self);
818
+
819
+ if (FIXNUM_P(v))
820
+ strt = getgrgid(NUM2UIDT(v));
821
+ else {
822
+ SafeStringValue(v);
823
+ strt = getgrnam(StringValuePtr(v));
824
+ }
825
+
826
+ if (!strt)
827
+ return Qnil;
828
+ return setup_group(strt);
829
+ }
830
+
831
+ static VALUE
832
+ eu_putpwent(VALUE mod, VALUE entry, VALUE io)
833
+ {
834
+ return user_putpwent(entry,io);
835
+ }
836
+
837
+ #ifdef SHADOW
838
+ static VALUE
839
+ eu_putspent(VALUE mod, VALUE entry, VALUE io)
840
+ {
841
+ return user_putspent(entry,io);
842
+ }
843
+ #endif
844
+
845
+ static VALUE
846
+ eu_putgrent(VALUE mod, VALUE entry, VALUE io)
847
+ {
848
+ return group_putgrent(entry,io);
849
+ }
850
+
851
+ #ifdef GSHADOW
852
+ static VALUE
853
+ eu_putsgent(VALUE mod, VALUE entry, VALUE io)
854
+ {
855
+ return group_putsgent(entry,io);
856
+ }
857
+ #endif
858
+
859
+ #ifdef HAVE_LCKPWDF
860
+ static VALUE
861
+ eu_locked_p(VALUE self)
862
+ {
863
+ int i;
864
+ errno = 0;
865
+ i = lckpwdf();
866
+ if (errno)
867
+ rb_raise(rb_eSystemCallError, "Error locking passwd files: %s", strerror(errno));
868
+
869
+ if (i)
870
+ return Qtrue;
871
+ else if (!ulckpwdf())
872
+ return Qfalse;
873
+ else
874
+ rb_raise(rb_eIOError,"Unable to determine the locked state of password files");
875
+ }
876
+ #endif
877
+
878
+ #ifdef HAVE_LCKPWDF
879
+ static VALUE
880
+ eu_lckpwdf(VALUE self)
881
+ {
882
+ VALUE r;
883
+ if ( !(r = eu_locked_p(self)) ) {
884
+ if ( !(lckpwdf()) )
885
+ r = Qtrue;
886
+ }
887
+ return r;
888
+ }
889
+ #endif
890
+
891
+ #ifdef HAVE_ULCKPWDF
892
+ static VALUE
893
+ eu_ulckpwdf(VALUE self)
894
+ {
895
+ VALUE r;
896
+ if ( (r = eu_locked_p(self)) )
897
+ if ( !(ulckpwdf()) )
898
+ r = Qtrue;
899
+ return r;
900
+ }
901
+
902
+ static int in_lock = 0;
903
+
904
+ static VALUE
905
+ lock_ensure(void)
906
+ {
907
+ ulckpwdf();
908
+ in_lock = (int)Qfalse;
909
+ return Qnil;
910
+ }
911
+
912
+ static VALUE
913
+ eu_lock(VALUE self)
914
+ {
915
+ if (eu_lckpwdf(self)) {
916
+ if (rb_block_given_p()) {
917
+ if (in_lock)
918
+ rb_raise(rb_eRuntimeError, "parallel lock iteration");
919
+ rb_ensure(rb_yield, Qnil, lock_ensure, 0);
920
+ return Qnil;
921
+ }
922
+ return Qtrue;
923
+ } else
924
+ rb_raise(rb_eIOError, "unable to create file lock");
925
+ }
926
+
927
+ static VALUE
928
+ eu_unlock(VALUE self)
929
+ {
930
+ return eu_ulckpwdf(self);
931
+ }
932
+ #endif
933
+
934
+ #ifdef SHADOW
935
+ static int spwd_block = 0;
936
+
937
+ static VALUE shadow_iterate(void)
938
+ {
939
+ struct spwd *shadow;
940
+
941
+ setspent();
942
+ while ( (shadow = getspent()) )
943
+ rb_yield(setup_shadow(shadow));
944
+
945
+ return Qnil;
946
+ }
947
+
948
+ static VALUE shadow_ensure(void)
949
+ {
950
+ endspent();
951
+ spwd_block = (int)Qfalse;
952
+ return Qnil;
953
+ }
954
+
955
+ static void each_shadow(void)
956
+ {
957
+ if (spwd_block)
958
+ rb_raise(rb_eRuntimeError, "parallel shadow iteration");
959
+ spwd_block = (int)Qtrue;
960
+ rb_ensure(shadow_iterate, 0, shadow_ensure, 0);
961
+ }
962
+
963
+ VALUE eu_getspent(VALUE self)
964
+ {
965
+ struct spwd *shadow;
966
+
967
+ if (rb_block_given_p())
968
+ each_shadow();
969
+ else if ( (shadow = getspent()) )
970
+ return setup_shadow(shadow);
971
+ return Qnil;
972
+ }
973
+ #endif
974
+
975
+ #ifdef PASSWD
976
+ static int pwd_block = 0;
977
+
978
+ static VALUE pwd_iterate(void)
979
+ {
980
+ struct passwd *pwd;
981
+
982
+ setpwent();
983
+ while ( (pwd = getpwent()) )
984
+ rb_yield(setup_passwd(pwd));
985
+ return Qnil;
986
+ }
987
+
988
+ static VALUE pwd_ensure(void)
989
+ {
990
+ endpwent();
991
+ pwd_block = (int)Qfalse;
992
+ return Qnil;
993
+ }
994
+
995
+ static void each_passwd(void)
996
+ {
997
+ if (pwd_block)
998
+ rb_raise(rb_eRuntimeError, "parallel passwd iteration");
999
+ pwd_block = (int)Qtrue;
1000
+ rb_ensure(pwd_iterate, 0, pwd_ensure, 0);
1001
+ }
1002
+
1003
+ VALUE eu_getpwent(VALUE self)
1004
+ {
1005
+ struct passwd *pwd;
1006
+
1007
+ if (rb_block_given_p())
1008
+ each_passwd();
1009
+ else if ( (pwd = getpwent()) )
1010
+ return setup_passwd(pwd);
1011
+ return Qnil;
1012
+ }
1013
+ #endif
1014
+
1015
+ #ifdef GROUP
1016
+ static int grp_block = 0;
1017
+
1018
+ static VALUE grp_iterate(void)
1019
+ {
1020
+ struct group *grp;
1021
+
1022
+ setgrent();
1023
+ while ( (grp = getgrent()) ) {
1024
+ rb_yield(setup_group(grp));
1025
+ }
1026
+ return Qnil;
1027
+ }
1028
+
1029
+ static VALUE grp_ensure(void)
1030
+ {
1031
+ endgrent();
1032
+ grp_block = (int)Qfalse;
1033
+ return Qnil;
1034
+ }
1035
+
1036
+ static void each_group(void)
1037
+ {
1038
+ if (grp_block)
1039
+ rb_raise(rb_eRuntimeError, "parallel group iteration");
1040
+ grp_block = (int)Qtrue;
1041
+ rb_ensure(grp_iterate, 0, grp_ensure, 0);
1042
+ }
1043
+
1044
+ VALUE eu_getgrent(VALUE self)
1045
+ {
1046
+ struct group *grp;
1047
+
1048
+ if (rb_block_given_p())
1049
+ each_group();
1050
+ else if ( (grp = getgrent()) )
1051
+ return setup_group(grp);
1052
+ return Qnil;
1053
+ }
1054
+ #endif
1055
+
1056
+ #ifdef GSHADOW
1057
+ static int sgrp_block = 0;
1058
+
1059
+ static VALUE sgrp_iterate(void)
1060
+ {
1061
+ struct sgrp *sgroup;
1062
+
1063
+ setsgent();
1064
+ while ( (sgroup = getsgent()) )
1065
+ rb_yield(setup_gshadow(sgroup));
1066
+ return Qnil;
1067
+ }
1068
+
1069
+ static VALUE sgrp_ensure(void)
1070
+ {
1071
+ #ifdef HAVE_ENDSGENT
1072
+ endsgent();
1073
+ sgrp_block = (int)Qfalse;
1074
+ #endif
1075
+ return Qnil;
1076
+ }
1077
+
1078
+ static void each_sgrp(void)
1079
+ {
1080
+ if (sgrp_block)
1081
+ rb_raise(rb_eRuntimeError, "parallel gshadow iteration");
1082
+ sgrp_block = (int)Qtrue;
1083
+ rb_ensure(sgrp_iterate, 0, sgrp_ensure, 0);
1084
+ }
1085
+
1086
+ VALUE eu_getsgent(VALUE self)
1087
+ {
1088
+ struct sgrp *sgroup;
1089
+
1090
+ if (rb_block_given_p())
1091
+ each_sgrp();
1092
+ else if ( (sgroup = getsgent()) )
1093
+ return setup_gshadow(sgroup);
1094
+ return Qnil;
1095
+ }
1096
+ #endif
1097
+
1098
+ VALUE eu_to_entry(VALUE self, VALUE(*user_to)(VALUE, VALUE))
1099
+ {
1100
+ size_t ln;
1101
+ VALUE line, io;
1102
+ char filename[] = "/tmp/etc_utilsXXXXXX";
1103
+ int fd = mkstemp(filename);
1104
+
1105
+ if ( fd == -1 )
1106
+ rb_raise(rb_eIOError,
1107
+ "Error creating temp file: %s", strerror(errno));
1108
+
1109
+ io = rb_file_open(filename,"w+");
1110
+
1111
+ line = user_to(self, io);
1112
+ if (!rb_obj_is_kind_of(line, rb_cString)) {
1113
+ rewind(RFILE_FPTR(io));
1114
+ line = rb_io_gets(io);
1115
+ }
1116
+
1117
+ if ( close(fd) < 0)
1118
+ rb_raise(rb_eIOError, "Error closing temp file: %s", strerror(errno));
1119
+
1120
+ rb_io_close(io);
1121
+
1122
+ if ( unlink(filename) < 0 )
1123
+ rb_raise(rb_eIOError, "Error unlinking temp file: %s", strerror(errno));
1124
+
1125
+ if (NIL_P(line))
1126
+ return Qnil;
1127
+
1128
+ ln = RSTRING_LEN(line);
1129
+
1130
+ if (RSTRING_PTR(line)[ln-1] == '\n')
1131
+ rb_str_resize(line, ln-1);
1132
+
1133
+ return line;
1134
+ }
1135
+
1136
+ static VALUE
1137
+ eu_setXXent(VALUE self)
1138
+ {
1139
+ eu_setpwent(self);
1140
+ eu_setgrent(self);
1141
+ eu_setspent(self);
1142
+ eu_setsgent(self);
1143
+ return Qnil;
1144
+ }
1145
+
1146
+ static VALUE
1147
+ eu_endXXent(VALUE self)
1148
+ {
1149
+ eu_endpwent(self);
1150
+ eu_endgrent(self);
1151
+ eu_endspent(self);
1152
+ eu_endsgent(self);
1153
+ return Qnil;
1154
+ }
1155
+
1156
+ static VALUE
1157
+ eu_getlogin(VALUE self)
1158
+ {
1159
+ struct passwd *pwd;
1160
+
1161
+ pwd = getpwuid(geteuid());
1162
+ return setup_passwd(pwd);
1163
+ }
1164
+
1165
+ static VALUE
1166
+ eu_passwd_p(VALUE self)
1167
+ {
1168
+ #ifdef PASSWD
1169
+ return Qtrue;
1170
+ #else
1171
+ return Qfalse;
1172
+ #endif
1173
+ }
1174
+
1175
+ static int
1176
+ eu_file_readable_p(const char *fname)
1177
+ {
1178
+ if (eaccess(fname, R_OK) < 0) return Qfalse;
1179
+ return Qtrue;
1180
+ }
1181
+
1182
+ static VALUE
1183
+ eu_read_passwd_p(VALUE self)
1184
+ {
1185
+ if (eu_passwd_p(self))
1186
+ return eu_file_readable_p(PASSWD);
1187
+ return Qfalse;
1188
+ }
1189
+
1190
+ static VALUE
1191
+ eu_shadow_p(VALUE self)
1192
+ {
1193
+ #ifdef SHADOW
1194
+ return Qtrue;
1195
+ #else
1196
+ return Qfalse;
1197
+ #endif
1198
+ }
1199
+
1200
+ static VALUE
1201
+ eu_read_shadow_p(VALUE self)
1202
+ {
1203
+ #ifdef SHADOW
1204
+ if (eu_shadow_p(self))
1205
+ return eu_file_readable_p(SHADOW);
1206
+ #endif
1207
+ return Qfalse;
1208
+ }
1209
+
1210
+ static VALUE
1211
+ eu_group_p(VALUE self)
1212
+ {
1213
+ #ifdef GROUP
1214
+ return Qtrue;
1215
+ #else
1216
+ return Qfalse;
1217
+ #endif
1218
+ }
1219
+
1220
+ static VALUE
1221
+ eu_read_group_p(VALUE self)
1222
+ {
1223
+ if (eu_group_p(self))
1224
+ return eu_file_readable_p(GROUP);
1225
+ return Qfalse;
1226
+ }
1227
+
1228
+ static VALUE
1229
+ eu_gshadow_p(VALUE self)
1230
+ {
1231
+ #ifdef GSHADOW
1232
+ return Qtrue;
1233
+ #else
1234
+ return Qfalse;
1235
+ #endif
1236
+ }
1237
+
1238
+ static VALUE
1239
+ eu_read_gshadow_p(VALUE self)
1240
+ {
1241
+ #ifdef GSHADOW
1242
+ if (eu_gshadow_p(self) && eu_file_readable_p(GSHADOW))
1243
+ if (getsgent()) {
1244
+ setsgent();
1245
+ return Qtrue;
1246
+ }
1247
+ #endif
1248
+ return Qfalse;
1249
+ }
1250
+
1251
+ static VALUE
1252
+ eu_lockable_p(VALUE self)
1253
+ {
1254
+ #if defined(HAVE_LCKPWDF) ||defined(HAVE_ULCKPWDF)
1255
+ return Qtrue;
1256
+ #else
1257
+ return Qfalse;
1258
+ #endif
1259
+ }
1260
+
1261
+ void Init_etcutils()
1262
+ {
1263
+ mEtcUtils = rb_define_module("EtcUtils");
1264
+
1265
+ assigned_uids = rb_ary_new();
1266
+ assigned_gids = rb_ary_new();
1267
+ uid_global = UINT2NUM((uid_t)0);
1268
+ gid_global = UINT2NUM((gid_t)0);
1269
+
1270
+ rb_global_variable(&assigned_uids);
1271
+ rb_global_variable(&assigned_gids);
1272
+ rb_global_variable(&uid_global);
1273
+ rb_global_variable(&gid_global);
1274
+
1275
+ rb_cPasswd = rb_define_class_under(mEtcUtils,"Passwd",rb_cObject);
1276
+ rb_extend_object(rb_cPasswd, rb_mEnumerable);
1277
+
1278
+ rb_cShadow = rb_define_class_under(mEtcUtils,"Shadow",rb_cObject);
1279
+ rb_extend_object(rb_cShadow, rb_mEnumerable);
1280
+
1281
+ rb_cGroup = rb_define_class_under(mEtcUtils,"Group",rb_cObject);
1282
+ rb_extend_object(rb_cGroup, rb_mEnumerable);
1283
+
1284
+ rb_cGshadow = rb_define_class_under(mEtcUtils,"GShadow",rb_cObject);
1285
+ rb_extend_object(rb_cGshadow, rb_mEnumerable);
1286
+ rb_define_const(mEtcUtils, "Gshadow", rb_cGshadow);
1287
+
1288
+ id_name = rb_intern("@name");
1289
+ id_passwd = rb_intern("@passwd");
1290
+ id_uid = rb_intern("@uid");
1291
+ id_gid = rb_intern("@gid");
1292
+
1293
+ /* EtcUtils Constants */
1294
+ #ifdef PASSWD
1295
+ rb_define_const(mEtcUtils, "PASSWD", setup_safe_str(PASSWD));
1296
+ #endif
1297
+ #ifdef SHADOW
1298
+ rb_define_const(mEtcUtils, "SHADOW", setup_safe_str(SHADOW));
1299
+ #endif
1300
+ #ifdef GROUP
1301
+ rb_define_const(mEtcUtils, "GROUP", setup_safe_str(GROUP));
1302
+ #endif
1303
+ #ifdef GSHADOW
1304
+ rb_define_const(mEtcUtils, "GSHADOW", setup_safe_str(GSHADOW));
1305
+ #endif
1306
+ rb_define_const(mEtcUtils, "SHELL", setup_safe_str(DEFAULT_SHELL));
1307
+
1308
+ /* EtcUtils Reflective Functions */
1309
+ rb_define_module_function(mEtcUtils,"me",eu_getlogin,0);
1310
+ rb_define_module_function(mEtcUtils,"getlogin",eu_getlogin,0);
1311
+ /* EtcUtils Truthy Functions */
1312
+ rb_define_module_function(mEtcUtils,"has_passwd?",eu_passwd_p,0);
1313
+ rb_define_module_function(mEtcUtils,"read_passwd?",eu_read_passwd_p,0);
1314
+ rb_define_module_function(mEtcUtils,"has_shadow?",eu_shadow_p,0);
1315
+ rb_define_module_function(mEtcUtils,"read_shadow?",eu_read_shadow_p,0);
1316
+ rb_define_module_function(mEtcUtils,"has_group?",eu_group_p,0);
1317
+ rb_define_module_function(mEtcUtils,"read_group?",eu_read_group_p,0);
1318
+ rb_define_module_function(mEtcUtils,"has_gshadow?",eu_gshadow_p,0);
1319
+ rb_define_module_function(mEtcUtils,"read_gshadow?",eu_read_gshadow_p,0);
1320
+ rb_define_module_function(mEtcUtils,"can_lockfile?",eu_lockable_p,0);
1321
+ /* EtcUtils Module functions */
1322
+ rb_define_module_function(mEtcUtils,"next_uid",next_uid,-1);
1323
+ rb_define_module_function(mEtcUtils,"next_gid",next_gid,-1);
1324
+ rb_define_module_function(mEtcUtils,"next_uid=",next_uid,-1);
1325
+ rb_define_module_function(mEtcUtils,"next_gid=",next_gid,-1);
1326
+ rb_define_module_function(mEtcUtils,"setXXent",eu_setXXent,0);
1327
+ rb_define_module_function(mEtcUtils,"endXXent",eu_endXXent,0);
1328
+ /* EtcUtils Lock Functions */
1329
+ #ifdef HAVE_LCKPWDF
1330
+ rb_define_module_function(mEtcUtils,"lckpwdf",eu_lckpwdf,0);
1331
+ rb_define_module_function(mEtcUtils,"lock",eu_lock,0);
1332
+ rb_define_module_function(mEtcUtils,"locked?",eu_locked_p,0);
1333
+ #endif
1334
+ #ifdef HAVE_ULCKPWDF
1335
+ rb_define_module_function(mEtcUtils,"ulckpwdf",eu_ulckpwdf,0);
1336
+ rb_define_module_function(mEtcUtils,"unlock",eu_unlock,0);
1337
+ #endif
1338
+
1339
+
1340
+ #ifdef SHADOW
1341
+ /* EU::Shadow module helpers */
1342
+ rb_define_module_function(mEtcUtils,"getspent",eu_getspent,0);
1343
+ rb_define_module_function(mEtcUtils,"find_spwd",eu_getspwd,1);
1344
+ rb_define_module_function(mEtcUtils,"setspent",eu_setspent,0);
1345
+ rb_define_module_function(mEtcUtils,"endspent",eu_endspent,0);
1346
+ rb_define_module_function(mEtcUtils,"sgetspent",eu_sgetspent,1);
1347
+ rb_define_module_function(mEtcUtils,"fgetspent",eu_fgetspent,1);
1348
+ rb_define_module_function(mEtcUtils,"putspent",eu_putspent,2);
1349
+ /* Backward compatibility */
1350
+ rb_define_module_function(mEtcUtils, "getspnam",eu_getspwd,1);
1351
+ #endif
1352
+
1353
+ #ifdef PASSWD
1354
+ /* EU::Passwd module helpers */
1355
+ rb_define_module_function(mEtcUtils,"getpwent",eu_getpwent,0);
1356
+ rb_define_module_function(mEtcUtils,"find_pwd",eu_getpwd,1);
1357
+ rb_define_module_function(mEtcUtils,"setpwent",eu_setpwent,0);
1358
+ rb_define_module_function(mEtcUtils,"endpwent",eu_endpwent,0);
1359
+ rb_define_module_function(mEtcUtils,"sgetpwent",eu_sgetpwent,1);
1360
+ #ifdef HAVE_FGETPWENT
1361
+ rb_define_module_function(mEtcUtils,"fgetpwent",eu_fgetpwent,1);
1362
+ #endif
1363
+ rb_define_module_function(mEtcUtils,"putpwent",eu_putpwent,2);
1364
+ /* Backward compatibility */
1365
+ rb_define_module_function(mEtcUtils,"getpwnam",eu_getpwd,1);
1366
+ #endif
1367
+
1368
+ #ifdef GSHADOW
1369
+ /* EU::GShadow module helpers */
1370
+ rb_define_module_function(mEtcUtils,"getsgent",eu_getsgent,0);
1371
+ rb_define_module_function(mEtcUtils,"find_sgrp",eu_getsgrp,1);
1372
+ rb_define_module_function(mEtcUtils,"setsgent",eu_setsgent,0);
1373
+ rb_define_module_function(mEtcUtils,"endsgent",eu_endsgent,0);
1374
+ rb_define_module_function(mEtcUtils,"sgetsgent",eu_sgetsgent,1);
1375
+ rb_define_module_function(mEtcUtils,"fgetsgent",eu_fgetsgent,1);
1376
+ rb_define_module_function(mEtcUtils,"putsgent",eu_putsgent,2);
1377
+ /* Backward compatibility */
1378
+ rb_define_module_function(mEtcUtils,"getsgnam",eu_getsgrp,1);
1379
+ #endif
1380
+
1381
+ #ifdef GROUP
1382
+ /* EU::Group module helpers */
1383
+ rb_define_module_function(mEtcUtils,"getgrent",eu_getgrent,0);
1384
+ rb_define_module_function(mEtcUtils,"find_grp",eu_getgrp,1);
1385
+ rb_define_module_function(mEtcUtils,"setgrent",eu_setgrent,0);
1386
+ rb_define_module_function(mEtcUtils,"endgrent",eu_endgrent,0);
1387
+ rb_define_module_function(mEtcUtils,"sgetgrent",eu_sgetgrent,1);
1388
+ #ifdef HAVE_FGETGRENT
1389
+ rb_define_module_function(mEtcUtils,"fgetgrent",eu_fgetgrent,1);
1390
+ #endif
1391
+ rb_define_module_function(mEtcUtils,"putgrent",eu_putgrent,2);
1392
+ /* Backward compatibility */
1393
+ rb_define_module_function(mEtcUtils,"getgrnam",eu_getgrp,1);
1394
+ #endif
1395
+
1396
+ Init_etcutils_user();
1397
+ Init_etcutils_group();
1398
+ }