etcutils 0.1.5-x86-linux

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