etcutils 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }