etcutils 0.1.5-x86-linux

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,1182 @@
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
+
29
+ #include "etcutils.h"
30
+ uid_t uid_global = 0;
31
+ gid_t gid_global = 0;
32
+
33
+
34
+ /* Start of helper functions */
35
+ static VALUE
36
+ next_uid(int argc, VALUE *argv, VALUE self)
37
+ {
38
+ uid_t req;
39
+ VALUE i;
40
+
41
+ rb_scan_args(argc, argv, "01", &i);
42
+ if (NIL_P(i))
43
+ req = uid_global;
44
+ else
45
+ req = NUM2UIDT(i);
46
+
47
+ if ((req < 0) || (req > 65533))
48
+ rb_raise(rb_eArgError, "UID must be between 0 and 65533");
49
+ while ( getpwuid(req) ) req++;
50
+
51
+ if (NIL_P(i))
52
+ uid_global = req + 1;
53
+ else
54
+ uid_global = req;
55
+
56
+ return UIDT2NUM(req);
57
+ }
58
+
59
+ static VALUE
60
+ next_gid(int argc, VALUE *argv, VALUE self)
61
+ {
62
+ gid_t req;
63
+ VALUE i;
64
+
65
+ rb_scan_args(argc, argv, "01", &i);
66
+ if (NIL_P(i))
67
+ req = gid_global;
68
+ else
69
+ req = NUM2GIDT(i);
70
+
71
+ if ((req < 0) || (req > 65533))
72
+ rb_raise(rb_eArgError, "GID must be between 0 and 65533");
73
+ while ( getgrgid(req) ) req++;
74
+
75
+ if (NIL_P(i))
76
+ gid_global = req +1;
77
+ else
78
+ gid_global = req;
79
+
80
+ return GIDT2NUM(req);
81
+ }
82
+
83
+ static void
84
+ etcutils_errno(VALUE str)
85
+ {
86
+ // SafeStringValue(str);
87
+ // if ( (errno) && ( !(errno == ENOTTY) || !(errno == ENOENT) ) )
88
+ // rb_sys_fail( StringValuePtr(str) );
89
+ /*
90
+ Errno::ENOTTY: Inappropriate ioctl for device
91
+ https://bugs.ruby-lang.org/issues/6127
92
+ ioctl range error in 1.9.3
93
+ Fixed in 1.9.3-p194 (REVISION r37138)
94
+ Ubuntu System Ruby (via APT) - 1.9.3-p0 (REVISION 33570)
95
+ */
96
+ //errno = 0;
97
+ }
98
+
99
+ static void
100
+ ensure_file(VALUE io)
101
+ {
102
+ rb_io_check_initialized(RFILE(io)->fptr);
103
+ }
104
+
105
+ static void
106
+ free_char_members(char ** mem, int c)
107
+ {
108
+ if (NULL != mem) {
109
+ int i=0;
110
+ for (i=0; i<c+1 ; i++) free(mem[i]);
111
+ free(mem);
112
+ }
113
+ }
114
+
115
+ static char**
116
+ setup_char_members(VALUE ary)
117
+ {
118
+ char ** mem;
119
+ VALUE temp;
120
+ long i;
121
+ Check_Type(ary,T_ARRAY);
122
+
123
+ mem = malloc((RARRAY_LEN(ary) + 1)*sizeof(char**));
124
+ if (mem == NULL)
125
+ rb_memerror();
126
+
127
+ for (i = 0; i < RARRAY_LEN(ary); i++) {
128
+ temp = rb_obj_as_string(RARRAY_PTR(ary)[i]);
129
+ StringValueCStr(temp);
130
+ mem[i] = malloc((RSTRING_LEN(temp))*sizeof(char*));;
131
+
132
+ if (mem[i] == NULL) rb_memerror();
133
+ strcpy(mem[i], RSTRING_PTR(temp));
134
+ }
135
+ mem[i] = NULL;
136
+
137
+ return mem;
138
+ }
139
+
140
+ static VALUE
141
+ setup_safe_str(const char *str)
142
+ {
143
+ return rb_tainted_str_new2(str); // this already handles characters >= 0
144
+ }
145
+
146
+ static VALUE
147
+ setup_safe_array(char **arr)
148
+ {
149
+ VALUE mem = rb_ary_new();
150
+
151
+ while (*arr)
152
+ rb_ary_push(mem, setup_safe_str(*arr++));
153
+ return mem;
154
+ }
155
+
156
+ static VALUE
157
+ setup_gshadow(struct sgrp *sgroup)
158
+ {
159
+ if (!sgroup) errno || (errno = 61); // ENODATA
160
+ etcutils_errno( setup_safe_str ( "Error setting up GShadow instance." ) );
161
+ return rb_struct_new(cGShadow,
162
+ setup_safe_str(SGRP_NAME(sgroup)),
163
+ setup_safe_str(sgroup->sg_passwd),
164
+ setup_safe_array(sgroup->sg_adm),
165
+ setup_safe_array(sgroup->sg_mem),
166
+ NULL);
167
+ }
168
+
169
+ static VALUE
170
+ setup_shadow(struct spwd *shadow)
171
+ {
172
+ if (!shadow) errno || (errno = 61); // ENODATA
173
+ etcutils_errno( setup_safe_str ( "Error setting up Shadow instance." ) );
174
+ return rb_struct_new(cShadow,
175
+ setup_safe_str(shadow->sp_namp),
176
+ setup_safe_str(shadow->sp_pwdp),
177
+ INT2FIX(shadow->sp_lstchg),
178
+ INT2FIX(shadow->sp_min),
179
+ INT2FIX(shadow->sp_max),
180
+ INT2FIX(shadow->sp_warn),
181
+ INT2FIX(shadow->sp_inact),
182
+ INT2FIX(shadow->sp_expire),
183
+ INT2FIX(shadow->sp_flag),
184
+ NULL);
185
+ }
186
+
187
+ static VALUE
188
+ setup_group(struct group *grp)
189
+ {
190
+ if (!grp) errno || (errno = 61); // ENODATA
191
+ etcutils_errno( setup_safe_str ( "Error setting up Group instance." ) );
192
+ return rb_struct_new(cGroup,
193
+ setup_safe_str(grp->gr_name),
194
+ setup_safe_str(grp->gr_passwd),
195
+ GIDT2NUM(grp->gr_gid),
196
+ setup_safe_array(grp->gr_mem),
197
+ NULL);
198
+ }
199
+
200
+ static VALUE
201
+ setup_passwd(struct passwd *pwd)
202
+ {
203
+ if (!pwd) errno || (errno = 61); // ENODATA
204
+ etcutils_errno( setup_safe_str ( "Error setting up Password instance." ) );
205
+ return rb_struct_new(cPasswd,
206
+ setup_safe_str(pwd->pw_name),
207
+ setup_safe_str(pwd->pw_passwd),
208
+ UIDT2NUM(pwd->pw_uid),
209
+ GIDT2NUM(pwd->pw_gid),
210
+ setup_safe_str(pwd->pw_gecos),
211
+ setup_safe_str(pwd->pw_dir),
212
+ setup_safe_str(pwd->pw_shell),
213
+ NULL);
214
+ }
215
+ /* End of helper functions */
216
+
217
+ static VALUE
218
+ etcutils_setsgent(VALUE self)
219
+ {
220
+ #ifdef HAVE_SETSGENT
221
+ setsgent();
222
+ #endif
223
+ return Qnil;
224
+ }
225
+
226
+ static VALUE
227
+ etcutils_endsgent(VALUE self)
228
+ {
229
+ #ifdef HAVE_ENDSGENT
230
+ endsgent();
231
+ #endif
232
+ return Qnil;
233
+ }
234
+
235
+ static VALUE
236
+ etcutils_setgrent(VALUE self)
237
+ {
238
+ #ifdef HAVE_SETGRENT
239
+ setgrent();
240
+ #endif
241
+ return Qnil;
242
+ }
243
+
244
+ static VALUE
245
+ etcutils_endgrent(VALUE self)
246
+ {
247
+ #ifdef HAVE_ENDGRENT
248
+ endgrent();
249
+ #endif
250
+ return Qnil;
251
+ }
252
+
253
+ static VALUE
254
+ etcutils_setspent(VALUE self)
255
+ {
256
+ #ifdef HAVE_SETSPENT
257
+ setspent();
258
+ #endif
259
+ return Qnil;
260
+ }
261
+
262
+ static VALUE
263
+ etcutils_setpwent(VALUE self)
264
+ {
265
+ #ifdef HAVE_SETPWENT
266
+ setpwent();
267
+ #endif
268
+ return Qnil;
269
+ }
270
+
271
+ static VALUE
272
+ etcutils_endpwent(VALUE self)
273
+ {
274
+ #ifdef HAVE_ENDPWENT
275
+ endpwent();
276
+ #endif
277
+ return Qnil;
278
+ }
279
+
280
+ static VALUE
281
+ etcutils_endspent(VALUE self)
282
+ {
283
+ #ifdef HAVE_ENDSPENT
284
+ endspent();
285
+ #endif
286
+ return Qnil;
287
+ }
288
+
289
+ static VALUE
290
+ etcutils_sgetpwent(VALUE self, VALUE nam)
291
+ {
292
+ VALUE ary, uid, gid, tmp;
293
+ struct passwd *pwd;
294
+ struct group *grp;
295
+
296
+ SafeStringValue(nam);
297
+ ary = rb_str_split(nam,":");
298
+
299
+ etcutils_setpwent(self);
300
+ etcutils_setgrent(self);
301
+
302
+ nam = rb_ary_entry(ary,0);
303
+ SafeStringValue(nam);
304
+ if (pwd = getpwnam( StringValuePtr(nam) )) {
305
+ rb_ary_store(ary, 2, UIDT2NUM(pwd->pw_uid) );
306
+ rb_ary_store(ary, 3, UIDT2NUM(pwd->pw_gid) );
307
+ } else {
308
+ uid = rb_ary_entry(ary,2);
309
+ // If there actually is a UID and that UID isn't already assigned
310
+ if ( (!( NIL_P(uid) || RSTRING_LEN(uid) == 0 )) && (getpwuid( NUM2UIDT( rb_Integer( uid ) ) )) ) {
311
+ tmp = rb_Integer( uid );
312
+ next_uid(1, &tmp, self);
313
+ }
314
+ uid = next_uid(0, 0, self);
315
+
316
+ gid = rb_ary_entry(ary,3);
317
+ if ( NIL_P(gid) || RSTRING_LEN(gid) == 0 )
318
+ if ( (grp = getgrnam( StringValuePtr(nam) )) ) { // Found a group with the same name
319
+ gid = GIDT2NUM(grp->gr_gid);
320
+ // See if the UID with value GID is available
321
+ // If so, we can keep a little sanity and match the GID and UID
322
+ tmp = uid;
323
+ next_uid(1, &gid, self);
324
+ uid = next_uid(0, 0, self);
325
+ if (! uid == gid)
326
+ uid = tmp;
327
+ } else {
328
+ next_gid(1, &uid, self);
329
+ gid = next_gid(0, 0, self);
330
+ }
331
+ else if ( (grp = getgrgid( NUM2GIDT( rb_Integer(gid) ) )) )
332
+ gid = GIDT2NUM(grp->gr_gid);
333
+ else
334
+ rb_raise(rb_eArgError,
335
+ "Group ID %ld does not exist!", gid);
336
+
337
+ rb_ary_store(ary, 2, rb_Integer( uid ) );
338
+ rb_ary_store(ary, 3, rb_Integer( gid ) );
339
+ }
340
+
341
+ return rb_struct_alloc( self, ary );
342
+ }
343
+
344
+ static VALUE
345
+ etcutils_sgetspent(VALUE self, VALUE nam)
346
+ {
347
+ struct spwd *shadow;
348
+
349
+ SafeStringValue(nam);
350
+ if ( !(shadow = sgetspent(StringValuePtr(nam))) )
351
+ rb_raise(rb_eArgError,
352
+ "can't parse %s into EtcUtils::Shadow", StringValuePtr(nam));
353
+
354
+ return setup_shadow(shadow);
355
+ }
356
+
357
+ static VALUE
358
+ etcutils_sgetgrent(VALUE self, VALUE nam)
359
+ {
360
+ VALUE ary, gid, mem;
361
+ struct group *grp;
362
+ struct passwd *pwd;
363
+
364
+ SafeStringValue(nam);
365
+ ary = rb_str_split(nam,":");
366
+
367
+ etcutils_setgrent(self);
368
+ etcutils_setpwent(self);
369
+ nam = rb_ary_entry(ary,0);
370
+ SafeStringValue(nam);
371
+ if (grp = getgrnam( StringValuePtr(nam) ))
372
+ rb_ary_store(ary, 2, GIDT2NUM(grp->gr_gid) );
373
+ else if (pwd = getpwnam( StringValuePtr(nam) ))
374
+ rb_ary_store(ary, 2, GIDT2NUM(pwd->pw_gid) );
375
+ else {
376
+ gid = rb_ary_entry(ary,2);
377
+ if ( NIL_P(gid) || RSTRING_LEN(gid) == 0 )
378
+ gid = next_gid(0, 0, self);
379
+ rb_ary_store(ary, 2, rb_Integer( gid ) );
380
+ }
381
+
382
+ if (NIL_P(mem = rb_ary_entry(ary,3)))
383
+ mem = rb_ary_new();
384
+ else
385
+ mem = rb_str_split(mem,",");
386
+
387
+ rb_ary_store(ary, 3, mem);
388
+
389
+ return rb_struct_alloc(self, ary);
390
+ }
391
+
392
+ static VALUE
393
+ etcutils_sgetsgent(VALUE self, VALUE nam)
394
+ {
395
+ struct sgrp *gshadow;
396
+
397
+ SafeStringValue(nam);
398
+ if ( !(gshadow = sgetsgent(StringValuePtr(nam))) )
399
+ rb_raise(rb_eArgError,
400
+ "can't parse %s into EtcUtils::GShadow", StringValuePtr(nam));
401
+
402
+ return setup_gshadow(gshadow);
403
+ }
404
+
405
+ static VALUE
406
+ etc_fgetgrent(VALUE self, VALUE io)
407
+ {
408
+ struct group *grp;
409
+
410
+ ensure_file(io);
411
+ if ( (grp = fgetgrent(RFILE_FPTR(io))) == NULL )
412
+ return Qnil;
413
+
414
+ return setup_group(grp);
415
+ }
416
+
417
+ static VALUE
418
+ etc_fgetpwent(VALUE self, VALUE io)
419
+ {
420
+ struct passwd *pwd;
421
+
422
+ ensure_file(io);
423
+ if ( (pwd = fgetpwent(RFILE_FPTR(io))) == NULL )
424
+ return Qnil;
425
+
426
+ return setup_passwd(pwd);
427
+ }
428
+
429
+ static VALUE
430
+ etcutils_fgetspent(VALUE self, VALUE io)
431
+ {
432
+ struct spwd *spasswd;
433
+
434
+ ensure_file(io);
435
+ if ( (spasswd = fgetspent(RFILE_FPTR(io))) == NULL )
436
+ return Qnil;
437
+
438
+ return setup_shadow(spasswd);
439
+ }
440
+
441
+ static VALUE
442
+ etcutils_fgetsgent(VALUE self, VALUE io)
443
+ {
444
+ struct sgrp *sgroup;
445
+
446
+ ensure_file(io);
447
+ if ( (sgroup = fgetsgent(RFILE_FPTR(io))) == NULL )
448
+ return Qnil;
449
+
450
+ return setup_gshadow(sgroup);
451
+ }
452
+
453
+ static VALUE
454
+ etcutils_getpwXXX(VALUE self, VALUE v)
455
+ {
456
+ struct passwd *strt;
457
+ etcutils_setpwent(self);
458
+
459
+ if (FIXNUM_P(v))
460
+ strt = getpwuid(NUM2UIDT(v));
461
+ else {
462
+ SafeStringValue(v);
463
+ strt = getpwnam(StringValuePtr(v));
464
+ }
465
+
466
+ if (!strt)
467
+ return Qnil;
468
+
469
+ return setup_passwd(strt);
470
+ }
471
+
472
+ static VALUE
473
+ etcutils_getspXXX(VALUE self, VALUE v)
474
+ {
475
+ struct spwd *strt;
476
+ etcutils_setspent(self);
477
+
478
+ if (FIXNUM_P(v)) {
479
+ struct passwd *s;
480
+ if ( (s = getpwuid(NUM2UIDT(v))) )
481
+ v = rb_str_new2(s->pw_name);
482
+ else
483
+ return Qnil;
484
+ }
485
+
486
+ SafeStringValue(v);
487
+ strt = getspnam(StringValuePtr(v));
488
+
489
+ if (!strt)
490
+ return Qnil;
491
+
492
+ return setup_shadow(strt);
493
+ }
494
+
495
+ static VALUE
496
+ etcutils_getsgXXX(VALUE self, VALUE v)
497
+ {
498
+ struct sgrp *strt;
499
+ etcutils_setsgent(self);
500
+
501
+ if (FIXNUM_P(v)) {
502
+ struct group *s;
503
+ if ( (s = getgrgid(NUM2UIDT(v))) )
504
+ v = setup_safe_str(s->gr_name);
505
+ }
506
+
507
+ SafeStringValue(v);
508
+ strt = getsgnam(StringValuePtr(v));
509
+
510
+ if (!strt)
511
+ return Qnil;
512
+
513
+ return setup_gshadow(strt);
514
+ }
515
+
516
+ static VALUE
517
+ etcutils_getgrXXX(VALUE self, VALUE v)
518
+ {
519
+ struct group *strt;
520
+ etcutils_setgrent(self);
521
+
522
+ if (FIXNUM_P(v))
523
+ strt = getgrgid(NUM2UIDT(v));
524
+ else {
525
+ SafeStringValue(v);
526
+ strt = getgrnam(StringValuePtr(v));
527
+ }
528
+
529
+ if (!strt)
530
+ return Qnil;
531
+ return setup_group(strt);
532
+ }
533
+
534
+ /**
535
+ * EtcUtils putXXent functions
536
+ *
537
+ */
538
+
539
+ static VALUE
540
+ pwd_putpwent(VALUE self, VALUE io)
541
+ {
542
+ struct passwd pwd, *tmp_str;
543
+ VALUE name = rb_struct_getmember(self,rb_intern("name"));
544
+ VALUE passwd = rb_struct_getmember(self,rb_intern("passwd"));
545
+ VALUE gecos = rb_struct_getmember(self,rb_intern("gecos"));
546
+ VALUE dir = rb_struct_getmember(self,rb_intern("dir"));
547
+ VALUE shell = rb_struct_getmember(self,rb_intern("shell"));
548
+ VALUE path = RFILE_PATH(io);
549
+ long i;
550
+
551
+ ensure_file(io);
552
+
553
+ rewind(RFILE_FPTR(io));
554
+ i = 0;
555
+ while ( (tmp_str = fgetpwent(RFILE_FPTR(io))) ) {
556
+ i++;
557
+ if ( !strcmp(tmp_str->pw_name, StringValuePtr( name ) ) )
558
+ rb_raise(rb_eArgError, "%s is already mentioned in %s:%ld",
559
+ tmp_str->pw_name, StringValuePtr(path), i );
560
+ }
561
+
562
+ pwd.pw_name = StringValueCStr( name );
563
+ pwd.pw_passwd = StringValueCStr( passwd );
564
+ pwd.pw_uid = NUM2UIDT( rb_struct_getmember(self,rb_intern("uid")) );
565
+ pwd.pw_gid = NUM2GIDT( rb_struct_getmember(self,rb_intern("gid")) );
566
+ pwd.pw_gecos = StringValueCStr( gecos );
567
+ pwd.pw_dir = StringValueCStr( dir );
568
+ pwd.pw_shell = StringValueCStr( shell );
569
+
570
+ if ( (putpwent(&pwd, RFILE_FPTR(io))) )
571
+ etcutils_errno(path);
572
+
573
+ return Qtrue;
574
+ }
575
+
576
+ static VALUE
577
+ etc_putpwent(VALUE klass, VALUE entry, VALUE io)
578
+ {
579
+ return pwd_putpwent(entry,io);
580
+ }
581
+
582
+
583
+ static VALUE
584
+ spwd_putspent(VALUE self, VALUE io)
585
+ {
586
+ struct spwd spasswd, *tmp_str;
587
+ VALUE name = rb_struct_getmember(self,rb_intern("name"));
588
+ VALUE passwd = rb_struct_getmember(self,rb_intern("passwd"));
589
+ VALUE path = RFILE_PATH(io);
590
+ long i;
591
+
592
+ ensure_file(io);
593
+
594
+ rewind(RFILE_FPTR(io));
595
+ i = 0;
596
+ while ( (tmp_str = fgetspent(RFILE_FPTR(io))) ) {
597
+ i++;
598
+ if ( !strcmp(tmp_str->sp_namp,StringValuePtr( name )) )
599
+ rb_raise(rb_eArgError, "%s is already mentioned in %s:%ld",
600
+ tmp_str->sp_namp, StringValuePtr(path), i );
601
+ }
602
+
603
+ spasswd.sp_namp = StringValueCStr( name );
604
+ spasswd.sp_pwdp = StringValueCStr( passwd );
605
+ spasswd.sp_lstchg = FIX2INT( rb_struct_getmember(self,rb_intern("last_change")) );
606
+ spasswd.sp_min = FIX2INT( rb_struct_getmember(self,rb_intern("min_change")) );
607
+ spasswd.sp_max = FIX2INT( rb_struct_getmember(self,rb_intern("max_change")) );
608
+ spasswd.sp_warn = FIX2INT( rb_struct_getmember(self,rb_intern("warn")) );
609
+ spasswd.sp_inact = FIX2INT( rb_struct_getmember(self,rb_intern("inactive")) );
610
+ spasswd.sp_expire = FIX2INT( rb_struct_getmember(self,rb_intern("expire")) );
611
+ spasswd.sp_flag = FIX2INT( rb_struct_getmember(self,rb_intern("flag")) );
612
+
613
+ if ( (putspent(&spasswd, RFILE_FPTR(io))) )
614
+ etcutils_errno(path);
615
+
616
+ return Qtrue;
617
+ }
618
+
619
+ static VALUE
620
+ etcutils_putspent(VALUE klass, VALUE entry, VALUE io)
621
+ {
622
+ return spwd_putspent(entry,io);
623
+ }
624
+
625
+ static VALUE
626
+ grp_putgrent(VALUE self, VALUE io)
627
+ {
628
+ struct group grp, *tmp_str;
629
+ VALUE name = rb_struct_getmember(self,rb_intern("name"));
630
+ VALUE passwd = rb_struct_getmember(self,rb_intern("passwd"));
631
+ VALUE path = RFILE_PATH(io);
632
+ long i;
633
+
634
+ ensure_file(io);
635
+
636
+ rewind(RFILE_FPTR(io));
637
+ i = 0;
638
+ while ( (tmp_str = fgetgrent(RFILE_FPTR(io))) ) {
639
+ i++;
640
+ if ( !strcmp(tmp_str->gr_name,StringValuePtr( name ) ) )
641
+ rb_raise(rb_eArgError, "%s is already mentioned in %s:%ld",
642
+ tmp_str->gr_name, StringValuePtr(path), i );
643
+ }
644
+
645
+ grp.gr_name = StringValueCStr( name );
646
+ grp.gr_passwd = StringValueCStr( passwd );
647
+ grp.gr_gid = NUM2GIDT( rb_struct_getmember(self,rb_intern("gid")) );
648
+ grp.gr_mem = setup_char_members( rb_struct_getmember(self,rb_intern("members")) );
649
+
650
+ if ( putgrent(&grp,RFILE_FPTR(io)) )
651
+ etcutils_errno(RFILE_PATH(io));
652
+
653
+ free_char_members(grp.gr_mem, RARRAY_LEN( rb_struct_getmember(self,rb_intern("members")) ));
654
+
655
+ return Qtrue;
656
+ }
657
+
658
+ static VALUE
659
+ etc_putgrent(VALUE klass, VALUE entry, VALUE io)
660
+ {
661
+ return grp_putgrent(entry,io);
662
+ }
663
+
664
+
665
+ static VALUE
666
+ sgrp_putsgent(VALUE self, VALUE io)
667
+ {
668
+ struct sgrp sgroup, *tmp_str;
669
+ VALUE name = rb_struct_getmember(self,rb_intern("name"));
670
+ VALUE passwd = rb_struct_getmember(self,rb_intern("passwd"));
671
+ VALUE path = RFILE_PATH(io);
672
+ long i;
673
+
674
+ rewind(RFILE_FPTR(io));
675
+ i = 0;
676
+ while ( (tmp_str = fgetsgent(RFILE_FPTR(io))) ) {
677
+ i++;
678
+ if ( !strcmp(SGRP_NAME(tmp_str),StringValuePtr( name ) ) )
679
+ rb_raise(rb_eArgError, "%s is already mentioned in %s:%ld",
680
+ SGRP_NAME(tmp_str), StringValuePtr(path), i );
681
+ }
682
+
683
+ #ifdef HAVE_ST_SG_NAMP
684
+ sgroup.sg_namp = StringValueCStr( name );
685
+ #endif
686
+ #if HAVE_ST_SG_NAME
687
+ sgroup.sg_name = StringValueCStr( name );
688
+ #endif
689
+
690
+ sgroup.sg_passwd = StringValueCStr( passwd );
691
+ // char** members start here
692
+ sgroup.sg_adm = setup_char_members( rb_struct_getmember(self,rb_intern("admins")) );
693
+ sgroup.sg_mem = setup_char_members( rb_struct_getmember(self,rb_intern("members")) );
694
+
695
+ if ( putsgent(&sgroup,RFILE_FPTR(io)) )
696
+ etcutils_errno(RFILE_PATH(io));
697
+
698
+ free_char_members(sgroup.sg_adm, RARRAY_LEN( rb_struct_getmember(self,rb_intern("admins")) ) );
699
+ free_char_members(sgroup.sg_mem, RARRAY_LEN( rb_struct_getmember(self,rb_intern("members")) ) );
700
+
701
+ return Qtrue;
702
+ }
703
+
704
+ static VALUE
705
+ etcutils_putsgent(VALUE klass, VALUE entry, VALUE io)
706
+ {
707
+ return sgrp_putsgent(entry,io);
708
+ }
709
+
710
+ static VALUE
711
+ etcutils_locked_p(VALUE self)
712
+ {
713
+ if (lckpwdf())
714
+ return Qtrue;
715
+ else if (!ulckpwdf())
716
+ return Qfalse;
717
+ else
718
+ rb_raise(rb_eIOError,"Unable to determine the locked state of password files");
719
+ }
720
+
721
+ static VALUE
722
+ etcutils_lckpwdf(VALUE self)
723
+ {
724
+ VALUE r;
725
+ if ( !(r = etcutils_locked_p(self)) ) {
726
+ if ( !(lckpwdf()) )
727
+ r = Qtrue;
728
+ }
729
+ return r;
730
+ }
731
+
732
+ static VALUE
733
+ etcutils_ulckpwdf(VALUE self)
734
+ {
735
+ VALUE r;
736
+ if ( (r = etcutils_locked_p(self)) )
737
+ if ( !(ulckpwdf()) )
738
+ r = Qtrue;
739
+ return r;
740
+ }
741
+
742
+ static int in_lock = 0;
743
+ static int spwd_block = 0;
744
+ static int pwd_block = 0;
745
+ static int sgrp_block = 0;
746
+ static int grp_block = 0;
747
+
748
+ static VALUE
749
+ lock_ensure(void)
750
+ {
751
+ ulckpwdf();
752
+ in_lock = (int)Qfalse;
753
+ return Qnil;
754
+ }
755
+
756
+ static VALUE
757
+ etcutils_lock(VALUE self)
758
+ {
759
+ if (etcutils_lckpwdf(self)) {
760
+ if (rb_block_given_p()) {
761
+ if (in_lock)
762
+ rb_raise(rb_eRuntimeError, "parallel lock iteration");
763
+ rb_ensure(rb_yield, Qnil, lock_ensure, 0);
764
+ return Qnil;
765
+ }
766
+ return Qtrue;
767
+ } else
768
+ rb_raise(rb_eIOError, "unable to create file lock");
769
+ }
770
+
771
+ static VALUE
772
+ etcutils_unlock(VALUE self)
773
+ {
774
+ return etcutils_ulckpwdf(self);
775
+ }
776
+
777
+ static VALUE
778
+ shadow_iterate(void)
779
+ {
780
+ struct spwd *shadow;
781
+
782
+ setspent();
783
+ while ( (shadow = getspent()) ) {
784
+ rb_yield(setup_shadow(shadow));
785
+ }
786
+ return Qnil;
787
+ }
788
+
789
+ static VALUE
790
+ shadow_ensure(void)
791
+ {
792
+ endspent();
793
+ spwd_block = (int)Qfalse;
794
+ return Qnil;
795
+ }
796
+
797
+ static void
798
+ each_shadow(void)
799
+ {
800
+ if (spwd_block)
801
+ rb_raise(rb_eRuntimeError, "parallel shadow iteration");
802
+ spwd_block = (int)Qtrue;
803
+ rb_ensure(shadow_iterate, 0, shadow_ensure, 0);
804
+ }
805
+
806
+ static VALUE
807
+ pwd_iterate(void)
808
+ {
809
+ struct passwd *pwd;
810
+
811
+ setspent();
812
+ while ( (pwd = getpwent()) ) {
813
+ rb_yield(setup_passwd(pwd));
814
+ }
815
+ return Qnil;
816
+ }
817
+
818
+ static VALUE
819
+ pwd_ensure(void)
820
+ {
821
+ endpwent();
822
+ pwd_block = (int)Qfalse;
823
+ return Qnil;
824
+ }
825
+
826
+ static void
827
+ each_passwd(void)
828
+ {
829
+ if (pwd_block)
830
+ rb_raise(rb_eRuntimeError, "parallel passwd iteration");
831
+ pwd_block = (int)Qtrue;
832
+ rb_ensure(pwd_iterate, 0, pwd_ensure, 0);
833
+ }
834
+
835
+
836
+ static VALUE
837
+ etcutils_getpwent(VALUE self)
838
+ {
839
+ struct passwd *pwd;
840
+
841
+ if (rb_block_given_p())
842
+ each_passwd();
843
+ else if ( (pwd = getpwent()) )
844
+ return setup_passwd(pwd);
845
+ return Qnil;
846
+ }
847
+
848
+
849
+ static VALUE
850
+ grp_iterate(void)
851
+ {
852
+ struct group *grp;
853
+
854
+ setgrent();
855
+ while ( (grp = getgrent()) ) {
856
+ rb_yield(setup_group(grp));
857
+ }
858
+ return Qnil;
859
+ }
860
+
861
+ static VALUE
862
+ grp_ensure(void)
863
+ {
864
+ endgrent();
865
+ grp_block = (int)Qfalse;
866
+ return Qnil;
867
+ }
868
+
869
+ static void
870
+ each_group(void)
871
+ {
872
+ if (grp_block)
873
+ rb_raise(rb_eRuntimeError, "parallel group iteration");
874
+ grp_block = (int)Qtrue;
875
+ rb_ensure(grp_iterate, 0, grp_ensure, 0);
876
+ }
877
+
878
+
879
+ static VALUE
880
+ etcutils_getgrent(VALUE self)
881
+ {
882
+ struct group *grp;
883
+
884
+ if (rb_block_given_p())
885
+ each_group();
886
+ else if ( (grp = getgrent()) )
887
+ return setup_group(grp);
888
+ return Qnil;
889
+ }
890
+
891
+
892
+ static VALUE
893
+ etcutils_getspent(VALUE self)
894
+ {
895
+ struct spwd *shadow;
896
+
897
+ if (rb_block_given_p())
898
+ each_shadow();
899
+ else if ( (shadow = getspent()) )
900
+ return setup_shadow(shadow);
901
+ return Qnil;
902
+ }
903
+
904
+ static VALUE
905
+ sgrp_iterate(void)
906
+ {
907
+ struct sgrp *sgroup;
908
+
909
+ setsgent();
910
+ while ( (sgroup = getsgent()) ) {
911
+ rb_yield(setup_gshadow(sgroup));
912
+ }
913
+ return Qnil;
914
+ }
915
+
916
+ static VALUE
917
+ sgrp_ensure(void)
918
+ {
919
+ endsgent();
920
+ sgrp_block = (int)Qfalse;
921
+ return Qnil;
922
+ }
923
+
924
+ static void
925
+ each_sgrp(void)
926
+ {
927
+ if (sgrp_block)
928
+ rb_raise(rb_eRuntimeError, "parallel gshadow iteration");
929
+ sgrp_block = (int)Qtrue;
930
+ rb_ensure(sgrp_iterate, 0, sgrp_ensure, 0);
931
+ }
932
+
933
+
934
+ static VALUE
935
+ etcutils_getsgent(VALUE self)
936
+ {
937
+ struct sgrp *sgroup;
938
+
939
+ if (rb_block_given_p())
940
+ each_sgrp();
941
+ else if ( (sgroup = getsgent()) )
942
+ return setup_gshadow(sgroup);
943
+ return Qnil;
944
+
945
+ }
946
+
947
+ static VALUE
948
+ strt_to_entry(VALUE self)
949
+ {
950
+ VALUE v, ary = rb_ary_new();
951
+ long i;
952
+
953
+ for (i=0; i<RSTRUCT_LEN(self); i++) {
954
+ v = RSTRUCT_PTR(self)[i];
955
+ if (NIL_P(v))
956
+ v = setup_safe_str("");
957
+
958
+ if (TYPE(v) == T_ARRAY)
959
+ rb_ary_push(ary, rb_ary_join( (v), setup_safe_str(",") ));
960
+ else if (TYPE(v) == T_STRING)
961
+ rb_ary_push(ary,v);
962
+ else if (FIXNUM_P(v)) {
963
+ if (FIX2INT(v) < 0 )
964
+ v = setup_safe_str("");
965
+ rb_ary_push(ary,v);
966
+ } else
967
+ Check_Type(v, T_STRING);
968
+ }
969
+
970
+ return rb_ary_join(ary, setup_safe_str(":"));
971
+ }
972
+
973
+ static VALUE
974
+ etcutils_setXXent(VALUE self)
975
+ {
976
+ etcutils_setpwent(self);
977
+ etcutils_setgrent(self);
978
+ etcutils_setspent(self);
979
+ etcutils_setsgent(self);
980
+ return Qnil;
981
+ }
982
+
983
+ static VALUE
984
+ etcutils_endXXent(VALUE self)
985
+ {
986
+ etcutils_endpwent(self);
987
+ etcutils_endgrent(self);
988
+ etcutils_endspent(self);
989
+ etcutils_endsgent(self);
990
+ return Qnil;
991
+ }
992
+
993
+ void Init_etcutils()
994
+ {
995
+ VALUE mEtcUtils = rb_define_module("EtcUtils");
996
+ rb_extend_object(mEtcUtils, rb_mEnumerable);
997
+ rb_define_const(mEtcUtils,"VERSION", setup_safe_str(EUVERSION));
998
+
999
+ // EtcUtils Constants
1000
+ rb_define_global_const("PASSWD", setup_safe_str(PASSWD));
1001
+ rb_define_global_const("SHADOW", setup_safe_str(SHADOW));
1002
+ rb_define_global_const("GROUP", setup_safe_str(GROUP));
1003
+ rb_define_global_const("GSHADOW", setup_safe_str(GSHADOW));
1004
+
1005
+ // EtcUtils Functions
1006
+ rb_define_module_function(mEtcUtils,"next_uid",next_uid,-1);
1007
+ rb_define_module_function(mEtcUtils,"next_gid",next_gid,-1);
1008
+ rb_define_module_function(mEtcUtils,"next_uid=",next_uid,-1);
1009
+ rb_define_module_function(mEtcUtils,"next_gid=",next_gid,-1);
1010
+ rb_define_module_function(mEtcUtils,"setXXent",etcutils_setXXent,0);
1011
+ rb_define_module_function(mEtcUtils,"endXXent",etcutils_endXXent,0);
1012
+
1013
+ // Shadow Functions
1014
+ rb_define_module_function(mEtcUtils,"getspent",etcutils_getspent,0);
1015
+ rb_define_module_function(mEtcUtils,"find_spwd",etcutils_getspXXX,1);
1016
+ rb_define_module_function(mEtcUtils,"setspent",etcutils_setspent,0);
1017
+ rb_define_module_function(mEtcUtils,"endspent",etcutils_endspent,0);
1018
+ rb_define_module_function(mEtcUtils,"sgetspent",etcutils_sgetspent,1);
1019
+ rb_define_module_function(mEtcUtils,"fgetspent",etcutils_fgetspent,1);
1020
+ rb_define_module_function(mEtcUtils,"putspent",etcutils_putspent,2);
1021
+ // Backward compatibility
1022
+ rb_define_module_function(mEtcUtils, "getspnam",etcutils_getspXXX,1);
1023
+
1024
+ // Password Functions
1025
+ rb_define_module_function(mEtcUtils,"getpwent",etcutils_getpwent,0);
1026
+ rb_define_module_function(mEtcUtils,"find_pwd",etcutils_getpwXXX,1);
1027
+ rb_define_module_function(mEtcUtils,"setpwent",etcutils_setpwent,0);
1028
+ rb_define_module_function(mEtcUtils,"endpwent",etcutils_endpwent,0);
1029
+ rb_define_module_function(mEtcUtils,"fgetpwent",etc_fgetpwent,1);
1030
+ rb_define_module_function(mEtcUtils,"putpwent",etc_putpwent,2);
1031
+ // Backward compatibility
1032
+ rb_define_module_function(mEtcUtils,"getpwnam",etcutils_getpwXXX,1);
1033
+
1034
+ // GShadow Functions
1035
+ rb_define_module_function(mEtcUtils,"getsgent",etcutils_getsgent,0);
1036
+ rb_define_module_function(mEtcUtils,"find_sgrp",etcutils_getsgXXX,1);
1037
+ rb_define_module_function(mEtcUtils,"setsgent",etcutils_setsgent,0);
1038
+ rb_define_module_function(mEtcUtils,"endsgent",etcutils_endsgent,0);
1039
+ rb_define_module_function(mEtcUtils,"sgetsgent",etcutils_sgetsgent,1);
1040
+ rb_define_module_function(mEtcUtils,"fgetsgent",etcutils_fgetsgent,1);
1041
+ rb_define_module_function(mEtcUtils,"putsgent",etcutils_putsgent,2);
1042
+ // Backward compatibility
1043
+ rb_define_module_function(mEtcUtils,"getsgnam",etcutils_getsgXXX,1);
1044
+
1045
+ // Group Functions
1046
+ rb_define_module_function(mEtcUtils,"getgrent",etcutils_getgrent,0);
1047
+ rb_define_module_function(mEtcUtils,"find_grp",etcutils_getgrXXX,1);
1048
+ rb_define_module_function(mEtcUtils,"setgrent",etcutils_setgrent,0);
1049
+ rb_define_module_function(mEtcUtils,"endgrent",etcutils_endgrent,0);
1050
+ rb_define_module_function(mEtcUtils,"fgetgrent",etc_fgetgrent,1);
1051
+ rb_define_module_function(mEtcUtils,"putgrent",etc_putgrent,2);
1052
+ // Backward compatibility
1053
+ rb_define_module_function(mEtcUtils,"getgrnam",etcutils_getgrXXX,1);
1054
+
1055
+ // Lock Functions
1056
+ rb_define_module_function(mEtcUtils,"lckpwdf",etcutils_lckpwdf,0);
1057
+ rb_define_module_function(mEtcUtils,"ulckpwdf",etcutils_ulckpwdf,0);
1058
+ rb_define_module_function(mEtcUtils,"lock",etcutils_lock,0);
1059
+ rb_define_module_function(mEtcUtils,"unlock",etcutils_unlock,0);
1060
+ rb_define_module_function(mEtcUtils,"locked?",etcutils_locked_p,0);
1061
+
1062
+ cPasswd = rb_struct_define(NULL,
1063
+ "name",
1064
+ "passwd",
1065
+ "uid",
1066
+ "gid",
1067
+ "gecos",
1068
+ "dir",
1069
+ "shell",
1070
+ NULL);
1071
+ /* Define-const: Passwd
1072
+ *
1073
+ * Passwd is a Struct that contains the following members:
1074
+ *
1075
+ * name::
1076
+ * contains the short login name of the user as a String.
1077
+ * passwd::
1078
+ * contains the encrypted password of the user as a String.
1079
+ * an 'x' is returned if shadow passwords are in use. An '*' is returned
1080
+ * if the user cannot log in using a password.
1081
+ * uid::
1082
+ * contains the integer user ID (uid) of the user.
1083
+ * gid::
1084
+ * contains the integer group ID (gid) of the user's primary group.
1085
+ * dir::
1086
+ * contains the path to the home directory of the user as a String.
1087
+ * gecos::
1088
+ * contains a longer String description of the user, such as a
1089
+ * full name. Some Unix systems provide structured information
1090
+ * in the gecos field, but this is system-dependent.
1091
+ * shell::
1092
+ * contains the path to the login shell of the user as a String.
1093
+ */
1094
+ rb_define_const(mEtcUtils,"Passwd",cPasswd);
1095
+ rb_set_class_path(cPasswd, mEtcUtils, "Passwd");
1096
+ rb_define_singleton_method(cPasswd,"get",etcutils_getpwent,0);
1097
+ rb_define_singleton_method(cPasswd,"find",etcutils_getpwXXX,1); // -1 return array
1098
+ rb_define_singleton_method(cPasswd,"parse",etcutils_sgetpwent,1);
1099
+ rb_define_singleton_method(cPasswd,"set",etcutils_setpwent,0);
1100
+ rb_define_singleton_method(cPasswd,"end",etcutils_endpwent,0);
1101
+ rb_define_singleton_method(cPasswd,"each",etcutils_getpwent,0);
1102
+ rb_define_method(cPasswd, "fputs", pwd_putpwent, 1);
1103
+ rb_define_method(cPasswd, "to_entry", strt_to_entry,0);
1104
+
1105
+ cShadow = rb_struct_define(NULL,
1106
+ "name",
1107
+ "passwd",
1108
+ "last_change",
1109
+ "min_change",
1110
+ "max_change",
1111
+ "warn",
1112
+ "inactive",
1113
+ "expire",
1114
+ "flag",
1115
+ NULL);
1116
+
1117
+ rb_define_const(mEtcUtils,"Shadow",cShadow);
1118
+ rb_set_class_path(cShadow, mEtcUtils, "Shadow");
1119
+ rb_define_const(rb_cStruct, "Shadow", cShadow); /* deprecated name */
1120
+ rb_define_singleton_method(cShadow,"get",etcutils_getspent,0);
1121
+ rb_define_singleton_method(cShadow,"find",etcutils_getspXXX,1);
1122
+ rb_define_singleton_method(cShadow,"parse",etcutils_sgetspent,1);
1123
+ rb_define_singleton_method(cShadow,"set",etcutils_setspent,0);
1124
+ rb_define_singleton_method(cShadow,"end",etcutils_endspent,0);
1125
+ rb_define_singleton_method(cShadow,"each",etcutils_getspent,0);
1126
+ rb_define_method(cShadow, "fputs", spwd_putspent, 1);
1127
+ rb_define_method(cShadow, "to_entry", strt_to_entry,0);
1128
+
1129
+ cGroup = rb_struct_define(NULL,
1130
+ "name",
1131
+ "passwd",
1132
+ "gid",
1133
+ "members",
1134
+ NULL);
1135
+ /* Define-const: Group
1136
+ *
1137
+ * The struct contains the following members:
1138
+ *
1139
+ * name::
1140
+ * contains the name of the group as a String.
1141
+ * passwd::
1142
+ * contains the encrypted password as a String. An 'x' is
1143
+ * returned if password access to the group is not available; an empty
1144
+ * string is returned if no password is needed to obtain membership of
1145
+ * the group.
1146
+ * gid::
1147
+ * contains the group's numeric ID as an integer.
1148
+ * mem::
1149
+ * is an Array of Strings containing the short login names of the
1150
+ * members of the group.
1151
+ */
1152
+ rb_define_class_under(mEtcUtils,"Group",cGroup);
1153
+ rb_set_class_path(cGroup, mEtcUtils, "Group");
1154
+ rb_define_singleton_method(cGroup,"get",etcutils_getgrent,0);
1155
+ rb_define_singleton_method(cGroup,"find",etcutils_getgrXXX,1);
1156
+ rb_define_singleton_method(cGroup,"parse",etcutils_sgetgrent,1);
1157
+ rb_define_singleton_method(cGroup,"set",etcutils_setgrent,0);
1158
+ rb_define_singleton_method(cGroup,"end",etcutils_endgrent,0);
1159
+ rb_define_singleton_method(cGroup,"each",etcutils_getgrent,0);
1160
+ rb_define_method(cGroup, "fputs", grp_putgrent, 1);
1161
+ rb_define_method(cGroup, "to_entry", strt_to_entry,0);
1162
+
1163
+ cGShadow = rb_struct_define(NULL,
1164
+ "name",
1165
+ "passwd",
1166
+ "admins",
1167
+ "members",
1168
+ NULL);
1169
+
1170
+ rb_define_const(mEtcUtils, "GShadow",cGShadow);
1171
+ rb_define_const(mEtcUtils, "Gshadow",cGShadow);
1172
+ rb_set_class_path(cGShadow, mEtcUtils, "GShadow");
1173
+ rb_define_const(rb_cStruct, "GShadow", cGShadow); /* deprecated name */
1174
+ rb_define_singleton_method(cGShadow,"get",etcutils_getsgent,0);
1175
+ rb_define_singleton_method(cGShadow,"find",etcutils_getsgXXX,1); //getsgent, getsguid
1176
+ rb_define_singleton_method(cGShadow,"parse",etcutils_sgetsgent,1);
1177
+ rb_define_singleton_method(cGShadow,"set",etcutils_setsgent,0);
1178
+ rb_define_singleton_method(cGShadow,"end",etcutils_endsgent,0);
1179
+ rb_define_singleton_method(cGShadow,"each",etcutils_getsgent,0);
1180
+ rb_define_method(cGShadow, "fputs", sgrp_putsgent, 1);
1181
+ rb_define_method(cGShadow, "to_entry", strt_to_entry,0);
1182
+ }