etcutils 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/.gitignore +22 -0
- data/.travis.yml +19 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +20 -0
- data/LICENSE +20 -0
- data/README.md +335 -0
- data/Rakefile +16 -0
- data/etcutils.gemspec +27 -0
- data/ext/etcutils/etcutils.c +1398 -0
- data/ext/etcutils/etcutils.h +189 -0
- data/ext/etcutils/extconf.rb +51 -0
- data/ext/etcutils/group.c +192 -0
- data/ext/etcutils/passwd.c +297 -0
- data/lib/etcutils.rb +4 -0
- data/lib/etcutils/version.rb +3 -0
- data/tests/README +141 -0
- data/tests/etcutils_test_helper.rb +8 -0
- data/tests/root/etc_utils.rb +5 -0
- data/tests/root/gshadow_tests.rb +153 -0
- data/tests/root/locking.rb +23 -0
- data/tests/root/shadow_tests.rb +161 -0
- data/tests/test_etc_utils.rb +107 -0
- data/tests/test_eu_locking.rb +15 -0
- data/tests/test_eu_next_uid_next_gid.rb +32 -0
- data/tests/test_eu_sgetpwent.rb +91 -0
- data/tests/test_group_class.rb +128 -0
- data/tests/test_passwd_class.rb +125 -0
- data/tests/user/etc_utils.rb +6 -0
- data/tests/user/locking.rb +7 -0
- metadata +119 -0
@@ -0,0 +1,189 @@
|
|
1
|
+
#include "extconf.h"
|
2
|
+
#include "ruby.h"
|
3
|
+
#include <errno.h>
|
4
|
+
|
5
|
+
|
6
|
+
#define EUVERSION "0.1.5"
|
7
|
+
|
8
|
+
#ifdef HAVE_RUBY_IO_H
|
9
|
+
#include "ruby/io.h"
|
10
|
+
#define RTIME_VAL(x) (x)
|
11
|
+
#else
|
12
|
+
#include "rubyio.h"
|
13
|
+
#define RTIME_VAL(x) (x.tv_sec)
|
14
|
+
#endif
|
15
|
+
|
16
|
+
#ifdef HAVE_SHADOW_H
|
17
|
+
#include <shadow.h>
|
18
|
+
#ifndef SHADOW
|
19
|
+
#define SHADOW "/etc/shadow"
|
20
|
+
#endif
|
21
|
+
#define PW_DEFAULT_PASS setup_safe_str("x")
|
22
|
+
#else
|
23
|
+
#define PW_DEFAULT_PASS setup_safe_str("*")
|
24
|
+
#endif
|
25
|
+
|
26
|
+
#ifdef HAVE_PWD_H
|
27
|
+
#include <pwd.h>
|
28
|
+
#ifndef PASSWD
|
29
|
+
#define PASSWD "/etc/passwd"
|
30
|
+
#endif
|
31
|
+
#endif
|
32
|
+
|
33
|
+
#ifdef HAVE_GSHADOW_H
|
34
|
+
#include <gshadow.h>
|
35
|
+
#elif defined(HAVE_GSHADOW__H)
|
36
|
+
#include <gshadow_.h>
|
37
|
+
#define HAVE_GSHADOW_H 1
|
38
|
+
#endif
|
39
|
+
|
40
|
+
#ifdef HAVE_GSHADOW_H
|
41
|
+
#ifndef GSHADOW
|
42
|
+
#define GSHADOW "/etc/gshadow"
|
43
|
+
#endif
|
44
|
+
#endif
|
45
|
+
|
46
|
+
#ifdef HAVE_GRP_H
|
47
|
+
#include <grp.h>
|
48
|
+
#ifndef GROUP
|
49
|
+
#define GROUP "/etc/group"
|
50
|
+
#endif
|
51
|
+
#endif
|
52
|
+
|
53
|
+
#ifndef DEFAULT_SHELL
|
54
|
+
#define DEFAULT_SHELL "/bin/bash"
|
55
|
+
#endif
|
56
|
+
|
57
|
+
#ifdef HAVE_ST_SG_NAMP
|
58
|
+
#define SGRP_NAME(s) (s)->sg_namp
|
59
|
+
#else
|
60
|
+
#define SGRP_NAME(s) (s)->sg_name
|
61
|
+
#endif
|
62
|
+
|
63
|
+
#ifndef HAVE_EACCESS
|
64
|
+
extern int eaccess(const char*, int);
|
65
|
+
#endif
|
66
|
+
|
67
|
+
#ifdef HAVE_STRUCT_RB_IO_T_PATHV
|
68
|
+
#define RFILE_PATH(x) (RFILE(x)->fptr)->pathv
|
69
|
+
#else
|
70
|
+
#define RFILE_PATH(x) ( setup_safe_str( (RFILE(x)->fptr)->path ) )
|
71
|
+
#endif
|
72
|
+
|
73
|
+
#ifdef HAVE_RB_IO_STDIO_FILE
|
74
|
+
#define RFILE_FPTR(x) rb_io_stdio_file( RFILE(x)->fptr )
|
75
|
+
#else
|
76
|
+
#define RFILE_FPTR(x) (RFILE(x)->fptr)->f
|
77
|
+
#endif
|
78
|
+
|
79
|
+
#ifndef RSTRING_BLANK_P
|
80
|
+
#define RSTRING_BLANK_P(x) (NIL_P(x) || (RSTRING_LEN(x) <= 0))
|
81
|
+
#endif
|
82
|
+
|
83
|
+
#ifndef UIDT2NUM
|
84
|
+
#define UIDT2NUM(v) LONG2NUM(v)
|
85
|
+
#endif
|
86
|
+
#ifndef NUM2UIDT
|
87
|
+
#define NUM2UIDT(v) NUM2LONG(v)
|
88
|
+
#endif
|
89
|
+
#ifndef GIDT2NUM
|
90
|
+
#define GIDT2NUM(v) LONG2NUM(v)
|
91
|
+
#endif
|
92
|
+
#ifndef NUM2GIDT
|
93
|
+
#define NUM2GIDT(v) NUM2LONG(v)
|
94
|
+
#endif
|
95
|
+
|
96
|
+
#ifndef INT2QFIX
|
97
|
+
#define INT2QFIX(v) (v >= 0 ? INT2FIX(v) : Qnil)
|
98
|
+
#endif
|
99
|
+
#ifndef UINT2QFIX
|
100
|
+
#define UINT2QFIX(v) INT2QFIX( (int)v )
|
101
|
+
#endif
|
102
|
+
|
103
|
+
#ifndef QFIX2INT
|
104
|
+
#define QFIX2INT(v) (RTEST(v) ? FIX2INT(v) : (long)-1 )
|
105
|
+
#endif
|
106
|
+
#ifndef QFIX2ULONG
|
107
|
+
#define QFIX2ULONG(v) (RTEST(v) ? FIX2ULONG(v) : (unsigned long)-1)
|
108
|
+
#endif
|
109
|
+
|
110
|
+
extern ID id_name, id_passwd, id_uid, id_gid;
|
111
|
+
extern VALUE mEtcUtils;
|
112
|
+
|
113
|
+
extern VALUE rb_cPasswd;
|
114
|
+
extern VALUE rb_cShadow;
|
115
|
+
extern VALUE rb_cGroup;
|
116
|
+
extern VALUE rb_cGshadow;
|
117
|
+
|
118
|
+
/* EU helper functions */
|
119
|
+
extern VALUE next_uid( int argc, VALUE *argv, VALUE self);
|
120
|
+
extern VALUE next_gid( int argc, VALUE *argv, VALUE self);
|
121
|
+
extern VALUE iv_get_time(VALUE self, const char *name);
|
122
|
+
extern VALUE iv_set_time(VALUE self, VALUE v, const char *name);
|
123
|
+
extern VALUE rb_current_time();
|
124
|
+
extern void eu_errno(VALUE str);
|
125
|
+
extern void ensure_file(VALUE io);
|
126
|
+
extern void ensure_writes(VALUE io, int t);
|
127
|
+
#define Check_Writes(v,t) ensure_writes((VALUE)(io),(int)(t));
|
128
|
+
extern void ensure_eu_type(VALUE self, VALUE klass);
|
129
|
+
#define Check_EU_Type(v,t) ensure_eu_type((VALUE)(v),(VALUE)(t))
|
130
|
+
|
131
|
+
extern char** setup_char_members(VALUE ary);
|
132
|
+
extern void free_char_members(char ** mem, int c);
|
133
|
+
|
134
|
+
extern VALUE setup_safe_str(const char *str);
|
135
|
+
extern VALUE setup_safe_array(char **arr);
|
136
|
+
|
137
|
+
#ifdef HAVE_SHADOW_H
|
138
|
+
extern VALUE setup_shadow(struct spwd *shadow);
|
139
|
+
#endif
|
140
|
+
extern VALUE setup_passwd(struct passwd *pwd);
|
141
|
+
|
142
|
+
extern VALUE setup_group(struct group *grp);
|
143
|
+
#if defined(HAVE_GSHADOW_H) || defined(HAVE_GSHADOW__H)
|
144
|
+
extern VALUE setup_gshadow(struct sgrp *sgroup);
|
145
|
+
#endif
|
146
|
+
|
147
|
+
extern VALUE eu_to_entry(VALUE self, VALUE(*user_to)(VALUE, VALUE));
|
148
|
+
|
149
|
+
extern VALUE eu_setpwent(VALUE self);
|
150
|
+
extern VALUE eu_setspent(VALUE self);
|
151
|
+
extern VALUE eu_setgrent(VALUE self);
|
152
|
+
extern VALUE eu_setsgent(VALUE self);
|
153
|
+
|
154
|
+
extern VALUE eu_endpwent(VALUE self);
|
155
|
+
extern VALUE eu_endspent(VALUE self);
|
156
|
+
extern VALUE eu_endsgent(VALUE self);
|
157
|
+
extern VALUE eu_endgrent(VALUE self);
|
158
|
+
|
159
|
+
extern VALUE eu_getpwent(VALUE self);
|
160
|
+
extern VALUE eu_getspent(VALUE self);
|
161
|
+
extern VALUE eu_getgrent(VALUE self);
|
162
|
+
extern VALUE eu_getsgent(VALUE self);
|
163
|
+
|
164
|
+
extern VALUE eu_getpwd(VALUE self, VALUE v);
|
165
|
+
extern VALUE eu_getspwd(VALUE self, VALUE v);
|
166
|
+
extern VALUE eu_getgrp(VALUE self, VALUE v);
|
167
|
+
extern VALUE eu_getsgrp(VALUE self, VALUE v);
|
168
|
+
|
169
|
+
extern VALUE eu_sgetpwent(VALUE self, VALUE nam);
|
170
|
+
extern VALUE eu_sgetspent(VALUE self, VALUE nam);
|
171
|
+
extern VALUE eu_sgetgrent(VALUE self, VALUE nam);
|
172
|
+
extern VALUE eu_sgetsgent(VALUE self, VALUE nam);
|
173
|
+
/* END EU helper functions */
|
174
|
+
|
175
|
+
/* EU User functions */
|
176
|
+
extern VALUE user_putpwent(VALUE self, VALUE io);
|
177
|
+
extern VALUE user_putspent(VALUE self, VALUE io);
|
178
|
+
/* END EU User functions */
|
179
|
+
|
180
|
+
/* EU Group functions */
|
181
|
+
extern VALUE group_putgrent(VALUE self, VALUE io);
|
182
|
+
extern VALUE group_putsgent(VALUE self, VALUE io);
|
183
|
+
/* END EU Group functions */
|
184
|
+
|
185
|
+
extern VALUE rb_ary_uniq_bang(VALUE ary);
|
186
|
+
|
187
|
+
extern void Init_etcutils_main();
|
188
|
+
extern void Init_etcutils_user();
|
189
|
+
extern void Init_etcutils_group();
|
@@ -0,0 +1,51 @@
|
|
1
|
+
#
|
2
|
+
# extconf.rb
|
3
|
+
#
|
4
|
+
# Modified at: <2013/07/04 16:12:45 by dcampbell>
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'mkmf'
|
8
|
+
|
9
|
+
have_header('ruby/io.h')
|
10
|
+
have_struct_member("struct rb_io_t", "pathv", "ruby/io.h")
|
11
|
+
have_func('rb_io_stdio_file')
|
12
|
+
have_func('eaccess')
|
13
|
+
|
14
|
+
have_header('etcutils.h')
|
15
|
+
|
16
|
+
if (have_header('pwd.h') && have_header('grp.h'))
|
17
|
+
short_v = ['pw','gr']
|
18
|
+
|
19
|
+
if have_header('shadow.h')
|
20
|
+
short_v << 'sp'
|
21
|
+
end
|
22
|
+
|
23
|
+
["gshadow.h","gshadow_.h"].each do |h|
|
24
|
+
short_v << 'sg'
|
25
|
+
if have_header(h)
|
26
|
+
nam = "sg_nam"+ (h =~ /_/ ? 'e' : 'p')
|
27
|
+
[nam, "sg_passwd", "sg_adm", "sg_mem"].each do |m|
|
28
|
+
have_struct_member("struct sgrp", m, h)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
have_func("lckpwdf")
|
34
|
+
have_func("ulckpwdf")
|
35
|
+
|
36
|
+
short_v.each do |h|
|
37
|
+
["get#{h}ent","sget#{h}ent","fget#{h}ent","put#{h}ent","set#{h}ent","end#{h}ent"].each do |func|
|
38
|
+
have_func(func)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
have_struct_member("struct passwd", "pw_change", "pwd.h")
|
42
|
+
have_struct_member("struct passwd", "pw_expire", "pwd.h")
|
43
|
+
have_struct_member("struct passwd", "pw_class", "pwd.h")
|
44
|
+
have_struct_member("struct passwd", "pw_field", "pwd.h")
|
45
|
+
|
46
|
+
|
47
|
+
create_header
|
48
|
+
create_makefile("etcutils")
|
49
|
+
else
|
50
|
+
puts "This system is not managed by passwd/group files.","Exiting"
|
51
|
+
end
|
@@ -0,0 +1,192 @@
|
|
1
|
+
#include "etcutils.h"
|
2
|
+
VALUE rb_cGroup, rb_cGshadow;
|
3
|
+
|
4
|
+
#ifdef HAVE_PUTGRENT
|
5
|
+
static VALUE group_gr_put(VALUE self, VALUE io)
|
6
|
+
{
|
7
|
+
struct group grp;
|
8
|
+
VALUE path;
|
9
|
+
#ifdef HAVE_FGETGRENT
|
10
|
+
struct group *tmp_grp;
|
11
|
+
long i = 0;
|
12
|
+
#endif
|
13
|
+
|
14
|
+
Check_EU_Type(self, rb_cGroup);
|
15
|
+
Check_Writes(io, FMODE_WRITABLE);
|
16
|
+
|
17
|
+
path = RFILE_PATH(io);
|
18
|
+
|
19
|
+
rewind(RFILE_FPTR(io));
|
20
|
+
grp.gr_name = RSTRING_PTR(rb_ivar_get(self, id_name));
|
21
|
+
|
22
|
+
#ifdef HAVE_FGETGRENT
|
23
|
+
while ( (tmp_grp = fgetgrent(RFILE_FPTR(io))) )
|
24
|
+
if ( !strcmp(tmp_grp->gr_name, grp.gr_name) )
|
25
|
+
rb_raise(rb_eArgError, "%s is already mentioned in %s:%ld",
|
26
|
+
tmp_grp->gr_name, StringValuePtr(path), ++i );
|
27
|
+
#endif
|
28
|
+
|
29
|
+
grp.gr_passwd = RSTRING_PTR(rb_ivar_get(self, id_passwd));
|
30
|
+
grp.gr_gid = NUM2GIDT( rb_ivar_get(self, id_gid) );
|
31
|
+
grp.gr_mem = setup_char_members( rb_iv_get(self, "@members") );
|
32
|
+
|
33
|
+
if ( putgrent(&grp,RFILE_FPTR(io)) )
|
34
|
+
eu_errno(RFILE_PATH(io));
|
35
|
+
|
36
|
+
free_char_members(grp.gr_mem, (int)RARRAY_LEN( rb_iv_get(self, "@members") ));
|
37
|
+
|
38
|
+
return Qtrue;
|
39
|
+
}
|
40
|
+
#endif
|
41
|
+
|
42
|
+
static VALUE group_gr_sprintf(VALUE self)
|
43
|
+
{
|
44
|
+
VALUE args[5];
|
45
|
+
args[0] = setup_safe_str("%s:%s:%s:%s\n");
|
46
|
+
args[1] = rb_ivar_get(self, id_name);
|
47
|
+
args[2] = rb_ivar_get(self, id_passwd);
|
48
|
+
args[3] = rb_ivar_get(self,id_gid);
|
49
|
+
args[4] = rb_ary_join((VALUE)rb_iv_get(self, "@members"), (VALUE)setup_safe_str(","));
|
50
|
+
return rb_f_sprintf(5, args);
|
51
|
+
}
|
52
|
+
|
53
|
+
VALUE group_putgrent(VALUE self, VALUE io)
|
54
|
+
{
|
55
|
+
#ifdef HAVE_PUTGRENT
|
56
|
+
return group_gr_put(self, io);
|
57
|
+
#else
|
58
|
+
return group_gr_sprintf(self);
|
59
|
+
#endif
|
60
|
+
}
|
61
|
+
|
62
|
+
VALUE group_gr_entry(VALUE self)
|
63
|
+
{
|
64
|
+
return eu_to_entry(self, group_putgrent);
|
65
|
+
}
|
66
|
+
|
67
|
+
VALUE group_putsgent(VALUE self, VALUE io)
|
68
|
+
{
|
69
|
+
#ifdef GSHADOW
|
70
|
+
struct sgrp sgroup, *tmp_sgrp;
|
71
|
+
VALUE path;
|
72
|
+
long i = 0;
|
73
|
+
|
74
|
+
Check_EU_Type(self, rb_cGshadow);
|
75
|
+
Check_Writes(io, FMODE_WRITABLE);
|
76
|
+
|
77
|
+
path = RFILE_PATH(io);
|
78
|
+
|
79
|
+
rewind(RFILE_FPTR(io));
|
80
|
+
SGRP_NAME(&sgroup) = RSTRING_PTR(rb_ivar_get(self, id_name));
|
81
|
+
|
82
|
+
while ( (tmp_sgrp = fgetsgent(RFILE_FPTR(io))) )
|
83
|
+
if ( !strcmp(SGRP_NAME(tmp_sgrp), SGRP_NAME(&sgroup)) )
|
84
|
+
rb_raise(rb_eArgError, "%s is already mentioned in %s:%ld",
|
85
|
+
RSTRING_PTR(rb_ivar_get(self, id_name)), StringValuePtr(path), ++i );
|
86
|
+
|
87
|
+
sgroup.sg_passwd = RSTRING_PTR(rb_ivar_get(self, id_passwd));
|
88
|
+
sgroup.sg_adm = setup_char_members( rb_iv_get(self,"@admins") );
|
89
|
+
sgroup.sg_mem = setup_char_members( rb_iv_get(self, "@members") );
|
90
|
+
|
91
|
+
if ( putsgent(&sgroup,RFILE_FPTR(io)) )
|
92
|
+
eu_errno(RFILE_PATH(io));
|
93
|
+
|
94
|
+
free_char_members(sgroup.sg_adm, RARRAY_LEN( rb_iv_get(self, "@admins") ));
|
95
|
+
free_char_members(sgroup.sg_mem, RARRAY_LEN( rb_iv_get(self, "@members") ));
|
96
|
+
|
97
|
+
return Qtrue;
|
98
|
+
#else
|
99
|
+
return Qnil;
|
100
|
+
#endif
|
101
|
+
}
|
102
|
+
|
103
|
+
VALUE group_sg_entry(VALUE self)
|
104
|
+
{
|
105
|
+
return eu_to_entry(self, group_putsgent);
|
106
|
+
}
|
107
|
+
|
108
|
+
VALUE setup_group(struct group *grp)
|
109
|
+
{
|
110
|
+
VALUE obj;
|
111
|
+
if (!grp) errno || (errno = 61); // ENODATA
|
112
|
+
eu_errno( setup_safe_str ( "Error setting up Group instance." ) );
|
113
|
+
|
114
|
+
obj = rb_obj_alloc(rb_cGroup);
|
115
|
+
|
116
|
+
rb_ivar_set(obj, id_name, setup_safe_str(grp->gr_name));
|
117
|
+
rb_ivar_set(obj, id_passwd, setup_safe_str(grp->gr_passwd));
|
118
|
+
rb_ivar_set(obj, id_gid, GIDT2NUM(grp->gr_gid));
|
119
|
+
rb_iv_set(obj, "@members", setup_safe_array(grp->gr_mem));
|
120
|
+
|
121
|
+
return obj;
|
122
|
+
}
|
123
|
+
|
124
|
+
#if defined(HAVE_GSHADOW_H) || defined(HAVE_GSHADOW__H)
|
125
|
+
VALUE setup_gshadow(struct sgrp *sgroup)
|
126
|
+
{
|
127
|
+
VALUE obj;
|
128
|
+
if (!sgroup) errno || (errno = 61); // ENODATA
|
129
|
+
eu_errno( setup_safe_str ( "Error setting up GShadow instance." ) );
|
130
|
+
|
131
|
+
obj = rb_obj_alloc(rb_cGshadow);
|
132
|
+
|
133
|
+
rb_ivar_set(obj, id_name, setup_safe_str(SGRP_NAME(sgroup)));
|
134
|
+
rb_ivar_set(obj, id_passwd, setup_safe_str(sgroup->sg_passwd));
|
135
|
+
rb_iv_set(obj, "@admins", setup_safe_array(sgroup->sg_adm));
|
136
|
+
rb_iv_set(obj, "@members", setup_safe_array(sgroup->sg_mem));
|
137
|
+
return obj;
|
138
|
+
}
|
139
|
+
#endif
|
140
|
+
|
141
|
+
void Init_etcutils_group()
|
142
|
+
{
|
143
|
+
/* Define-const: Group
|
144
|
+
*
|
145
|
+
* The struct contains the following members:
|
146
|
+
*
|
147
|
+
* name::
|
148
|
+
* contains the name of the group as a String.
|
149
|
+
* passwd::
|
150
|
+
* contains the encrypted password as a String. An 'x' is
|
151
|
+
* returned if password access to the group is not available; an empty
|
152
|
+
* string is returned if no password is needed to obtain membership of
|
153
|
+
* the group.
|
154
|
+
* gid::
|
155
|
+
* contains the group's numeric ID as an integer.
|
156
|
+
* mem::
|
157
|
+
* is an Array of Strings containing the short login names of the
|
158
|
+
* members of the group.
|
159
|
+
*/
|
160
|
+
#ifdef GROUP
|
161
|
+
rb_define_attr(rb_cGroup, "name", 1, 1);
|
162
|
+
rb_define_attr(rb_cGroup, "passwd", 1, 1);
|
163
|
+
rb_define_attr(rb_cGroup, "gid", 1, 1);
|
164
|
+
rb_define_attr(rb_cGroup, "members", 1, 1);
|
165
|
+
|
166
|
+
rb_define_singleton_method(rb_cGroup,"get",eu_getgrent,0);
|
167
|
+
rb_define_singleton_method(rb_cGroup,"find",eu_getgrp,1);
|
168
|
+
rb_define_singleton_method(rb_cGroup,"parse",eu_sgetgrent,1);
|
169
|
+
rb_define_singleton_method(rb_cGroup,"set",eu_setgrent,0);
|
170
|
+
rb_define_singleton_method(rb_cGroup,"end",eu_endgrent,0);
|
171
|
+
rb_define_singleton_method(rb_cGroup,"each",eu_getgrent,0);
|
172
|
+
|
173
|
+
rb_define_method(rb_cGroup, "fputs", group_putgrent,1);
|
174
|
+
rb_define_method(rb_cGroup, "to_entry", group_gr_entry,0);
|
175
|
+
#endif
|
176
|
+
|
177
|
+
#ifdef GSHADOW
|
178
|
+
rb_define_attr(rb_cGshadow, "name", 1, 1);
|
179
|
+
rb_define_attr(rb_cGshadow, "passwd", 1, 1);
|
180
|
+
rb_define_attr(rb_cGshadow, "admins", 1, 1);
|
181
|
+
rb_define_attr(rb_cGshadow, "members", 1, 1);
|
182
|
+
|
183
|
+
rb_define_singleton_method(rb_cGshadow,"get",eu_getsgent,0);
|
184
|
+
rb_define_singleton_method(rb_cGshadow,"find",eu_getsgrp,1); //getsgent, getsguid
|
185
|
+
rb_define_singleton_method(rb_cGshadow,"parse",eu_sgetsgent,1);
|
186
|
+
rb_define_singleton_method(rb_cGshadow,"set",eu_setsgent,0);
|
187
|
+
rb_define_singleton_method(rb_cGshadow,"end",eu_endsgent,0);
|
188
|
+
rb_define_singleton_method(rb_cGshadow,"each",eu_getsgent,0);
|
189
|
+
rb_define_method(rb_cGshadow, "fputs", group_putsgent, 1);
|
190
|
+
rb_define_method(rb_cGshadow, "to_entry", group_sg_entry,0);
|
191
|
+
#endif
|
192
|
+
}
|
@@ -0,0 +1,297 @@
|
|
1
|
+
#include "etcutils.h"
|
2
|
+
|
3
|
+
VALUE rb_cPasswd, rb_cShadow;
|
4
|
+
int expire_warned = 0;
|
5
|
+
|
6
|
+
static VALUE
|
7
|
+
user_get_pw_change(VALUE self)
|
8
|
+
{
|
9
|
+
return iv_get_time(self, "@last_pw_change");
|
10
|
+
}
|
11
|
+
|
12
|
+
static VALUE
|
13
|
+
user_set_pw_change(VALUE self, VALUE pw)
|
14
|
+
{
|
15
|
+
rb_ivar_set(self, id_passwd, pw);
|
16
|
+
return iv_set_time(self, rb_current_time(), "@last_pw_change");
|
17
|
+
}
|
18
|
+
|
19
|
+
static VALUE
|
20
|
+
user_get_expire(VALUE self)
|
21
|
+
{
|
22
|
+
return iv_get_time(self, "@expire");
|
23
|
+
}
|
24
|
+
|
25
|
+
static VALUE
|
26
|
+
user_set_expire(VALUE self, VALUE v)
|
27
|
+
{
|
28
|
+
if ((rb_equal(v, INT2FIX(0))) && (expire_warned == 0)) {
|
29
|
+
rb_warn("Setting %s#expire to 0 should not be used as it is interpreted as either an account with no expiration, or as an expiration of Jan 1, 1970.", rb_obj_classname(self));
|
30
|
+
expire_warned = 1;
|
31
|
+
}
|
32
|
+
|
33
|
+
return iv_set_time(self, v, "@expire");
|
34
|
+
}
|
35
|
+
|
36
|
+
#ifdef HAVE_PUTPWENT
|
37
|
+
static VALUE user_pw_put(VALUE self, VALUE io)
|
38
|
+
{
|
39
|
+
struct passwd pwd;
|
40
|
+
VALUE path;
|
41
|
+
|
42
|
+
#ifdef HAVE_FGETPWENT
|
43
|
+
struct passwd *tmp_pwd;
|
44
|
+
long i = 0;
|
45
|
+
#endif
|
46
|
+
|
47
|
+
Check_EU_Type(self, rb_cPasswd);
|
48
|
+
Check_Writes(io, FMODE_WRITABLE);
|
49
|
+
|
50
|
+
path = RFILE_PATH(io);
|
51
|
+
|
52
|
+
rewind(RFILE_FPTR(io));
|
53
|
+
pwd.pw_name = RSTRING_PTR(rb_ivar_get(self, id_name));
|
54
|
+
|
55
|
+
#ifdef HAVE_FGETPWENT
|
56
|
+
while ( (tmp_pwd = fgetpwent(RFILE_FPTR(io))) )
|
57
|
+
if ( !strcmp(tmp_pwd->pw_name, pwd.pw_name) )
|
58
|
+
rb_raise(rb_eArgError, "%s is already mentioned in %s:%ld",
|
59
|
+
tmp_pwd->pw_name, StringValuePtr(path), ++i );
|
60
|
+
#endif
|
61
|
+
|
62
|
+
pwd.pw_passwd = RSTRING_PTR(rb_ivar_get(self, id_passwd));
|
63
|
+
pwd.pw_uid = NUM2UIDT( rb_ivar_get(self,id_uid) );
|
64
|
+
pwd.pw_gid = NUM2GIDT( rb_ivar_get(self,id_gid) );
|
65
|
+
pwd.pw_gecos = RSTRING_PTR(rb_iv_get(self, "@gecos"));
|
66
|
+
pwd.pw_dir = RSTRING_PTR(rb_iv_get(self, "@directory"));
|
67
|
+
pwd.pw_shell = RSTRING_PTR(rb_iv_get(self, "@shell"));
|
68
|
+
|
69
|
+
if ( (putpwent(&pwd, RFILE_FPTR(io))) )
|
70
|
+
eu_errno(path);
|
71
|
+
|
72
|
+
return Qtrue;
|
73
|
+
}
|
74
|
+
#endif
|
75
|
+
|
76
|
+
static VALUE user_pw_sprintf(VALUE self)
|
77
|
+
{
|
78
|
+
VALUE args[11];
|
79
|
+
args[0] = setup_safe_str("%s:%s:%s:%s:%s:%s:%s:%s:%s:%s\n");
|
80
|
+
args[1] = rb_ivar_get(self, id_name);
|
81
|
+
args[2] = rb_ivar_get(self, id_passwd);
|
82
|
+
args[3] = rb_ivar_get(self, id_uid);
|
83
|
+
args[4] = rb_ivar_get(self,id_gid);
|
84
|
+
args[5] = rb_iv_get(self, "@access_classs");
|
85
|
+
args[6] = rb_iv_get(self, "@last_pw_change");
|
86
|
+
args[7] = rb_iv_get(self, "@expire");
|
87
|
+
args[8] = rb_iv_get(self, "@gecos");
|
88
|
+
args[9] = rb_iv_get(self, "@directory");
|
89
|
+
args[10] = rb_iv_get(self, "@shell");
|
90
|
+
return rb_f_sprintf(11, args);
|
91
|
+
}
|
92
|
+
|
93
|
+
VALUE user_putpwent(VALUE self, VALUE io)
|
94
|
+
{
|
95
|
+
#ifdef HAVE_PUTPWENT
|
96
|
+
return user_pw_put(self, io);
|
97
|
+
#else
|
98
|
+
return user_pw_sprintf(self);
|
99
|
+
#endif
|
100
|
+
}
|
101
|
+
|
102
|
+
VALUE user_pw_entry(VALUE self)
|
103
|
+
{
|
104
|
+
return eu_to_entry(self, user_putpwent);
|
105
|
+
}
|
106
|
+
|
107
|
+
VALUE user_putspent(VALUE self, VALUE io)
|
108
|
+
{
|
109
|
+
#ifdef SHADOW
|
110
|
+
struct spwd spasswd, *tmp_spwd;
|
111
|
+
VALUE path;
|
112
|
+
long i;
|
113
|
+
errno = 0;
|
114
|
+
i = 0;
|
115
|
+
|
116
|
+
Check_EU_Type(self, rb_cShadow);
|
117
|
+
Check_Writes(io, FMODE_WRITABLE);
|
118
|
+
|
119
|
+
path = RFILE_PATH(io);
|
120
|
+
|
121
|
+
rewind(RFILE_FPTR(io));
|
122
|
+
spasswd.sp_namp = RSTRING_PTR(rb_ivar_get(self, id_name));
|
123
|
+
|
124
|
+
while ( (tmp_spwd = fgetspent(RFILE_FPTR(io))) )
|
125
|
+
if ( !strcmp(tmp_spwd->sp_namp, spasswd.sp_namp) )
|
126
|
+
rb_raise(rb_eArgError, "%s is already mentioned in %s:%ld",
|
127
|
+
tmp_spwd->sp_namp, StringValuePtr(path), ++i );
|
128
|
+
|
129
|
+
spasswd.sp_pwdp = RSTRING_PTR(rb_ivar_get(self, id_passwd));
|
130
|
+
spasswd.sp_lstchg = FIX2INT( rb_iv_get(self, "@last_pw_change") );
|
131
|
+
spasswd.sp_min = FIX2INT( rb_iv_get(self, "@min_pw_age") );
|
132
|
+
spasswd.sp_max = FIX2INT( rb_iv_get(self, "@max_pw_age") );
|
133
|
+
spasswd.sp_warn = QFIX2INT( rb_iv_get(self, "@warning") );
|
134
|
+
spasswd.sp_inact = QFIX2INT( rb_iv_get(self, "@inactive") );
|
135
|
+
spasswd.sp_expire = QFIX2INT( rb_iv_get(self, "@expire") );
|
136
|
+
spasswd.sp_flag = QFIX2ULONG( rb_iv_get(self, "@flag") );
|
137
|
+
|
138
|
+
if ( (putspent(&spasswd, RFILE_FPTR(io))) )
|
139
|
+
eu_errno(path);
|
140
|
+
|
141
|
+
return Qtrue;
|
142
|
+
#else
|
143
|
+
return Qnil;
|
144
|
+
#endif
|
145
|
+
}
|
146
|
+
|
147
|
+
VALUE user_sp_entry(VALUE self)
|
148
|
+
{
|
149
|
+
return eu_to_entry(self, user_putspent);
|
150
|
+
}
|
151
|
+
|
152
|
+
#ifdef SHADOW
|
153
|
+
VALUE setup_shadow(struct spwd *spasswd)
|
154
|
+
{
|
155
|
+
VALUE obj;
|
156
|
+
if (!spasswd) errno || (errno = 61); // ENODATA
|
157
|
+
eu_errno( setup_safe_str ( "Error setting up Shadow instance." ) );
|
158
|
+
|
159
|
+
obj = rb_obj_alloc(rb_cShadow);
|
160
|
+
|
161
|
+
rb_ivar_set(obj, id_name, setup_safe_str(spasswd->sp_namp));
|
162
|
+
rb_ivar_set(obj, id_passwd, setup_safe_str(spasswd->sp_pwdp));
|
163
|
+
|
164
|
+
rb_iv_set(obj, "@last_pw_change", INT2FIX(spasswd->sp_lstchg));
|
165
|
+
rb_iv_set(obj, "@min_pw_age", INT2FIX(spasswd->sp_min));
|
166
|
+
rb_iv_set(obj, "@max_pw_age", INT2FIX(spasswd->sp_max));
|
167
|
+
rb_iv_set(obj, "@warning", INT2QFIX(spasswd->sp_warn));
|
168
|
+
rb_iv_set(obj, "@inactive", INT2QFIX(spasswd->sp_inact));
|
169
|
+
rb_iv_set(obj, "@expire", INT2QFIX(spasswd->sp_expire));
|
170
|
+
rb_iv_set(obj, "@flag", UINT2QFIX(spasswd->sp_flag));
|
171
|
+
|
172
|
+
return obj;
|
173
|
+
}
|
174
|
+
#endif
|
175
|
+
|
176
|
+
VALUE setup_passwd(struct passwd *pwd)
|
177
|
+
{
|
178
|
+
VALUE obj;
|
179
|
+
if (!pwd) errno || (errno = 61); // ENODATA
|
180
|
+
eu_errno( setup_safe_str ( "Error setting up Password instance." ) );
|
181
|
+
|
182
|
+
obj = rb_obj_alloc(rb_cPasswd);
|
183
|
+
|
184
|
+
rb_ivar_set(obj, id_name, setup_safe_str(pwd->pw_name));
|
185
|
+
rb_ivar_set(obj, id_passwd, setup_safe_str(pwd->pw_passwd));
|
186
|
+
rb_ivar_set(obj, id_uid, UIDT2NUM(pwd->pw_uid));
|
187
|
+
rb_ivar_set(obj, id_gid, GIDT2NUM(pwd->pw_gid));
|
188
|
+
|
189
|
+
rb_iv_set(obj, "@gecos", setup_safe_str(pwd->pw_gecos));
|
190
|
+
rb_iv_set(obj, "@directory", setup_safe_str(pwd->pw_dir));
|
191
|
+
rb_iv_set(obj, "@shell", setup_safe_str(pwd->pw_shell));
|
192
|
+
#ifdef HAVE_ST_PW_CHANGE
|
193
|
+
if (!pwd->pw_change)
|
194
|
+
pwd->pw_change = (time_t)0;
|
195
|
+
rb_iv_set(obj, "@last_pw_change", INT2FIX(pwd->pw_change));
|
196
|
+
#endif
|
197
|
+
#ifdef HAVE_ST_PW_EXPIRE
|
198
|
+
if (!pwd->pw_expire)
|
199
|
+
pwd->pw_expire = (time_t)0;
|
200
|
+
|
201
|
+
rb_iv_set(obj, "@expire", INT2QFIX(pwd->pw_expire));
|
202
|
+
#endif
|
203
|
+
#ifdef HAVE_ST_PW_CLASS
|
204
|
+
if (pwd->pw_class)
|
205
|
+
rb_iv_set(obj, "@access_class", setup_safe_str(pwd->pw_class));
|
206
|
+
#endif
|
207
|
+
|
208
|
+
#ifdef HAVE_ST_PW_FIELD
|
209
|
+
if (pwd->pw_field)
|
210
|
+
rb_iv_set(obj, "@field", setup_safe_str(pwd->pw_field));
|
211
|
+
#endif
|
212
|
+
|
213
|
+
return obj;
|
214
|
+
}
|
215
|
+
|
216
|
+
void Init_etcutils_user()
|
217
|
+
{
|
218
|
+
|
219
|
+
#ifdef HAVE_PWD_H
|
220
|
+
rb_define_attr(rb_cPasswd, "name", 1, 1);
|
221
|
+
rb_define_attr(rb_cPasswd, "uid", 1, 1);
|
222
|
+
rb_define_attr(rb_cPasswd, "gid", 1, 1);
|
223
|
+
rb_define_attr(rb_cPasswd, "gecos", 1, 1);
|
224
|
+
rb_define_attr(rb_cPasswd, "directory", 1, 1);
|
225
|
+
rb_define_attr(rb_cPasswd, "shell", 1, 1);
|
226
|
+
|
227
|
+
#ifdef HAVE_ST_PW_CHANGE
|
228
|
+
rb_define_attr(rb_cPasswd, "last_pw_change", 1, 0); /* Number expressed as a count of days since Jan 1, 1970
|
229
|
+
since the last password change */
|
230
|
+
rb_define_method(rb_cPasswd, "last_pw_change_date", user_get_pw_change, 0);
|
231
|
+
rb_define_attr(rb_cPasswd, "passwd", 1, 0);
|
232
|
+
rb_define_method(rb_cPasswd, "passwd=", user_set_pw_change, 1);
|
233
|
+
#else
|
234
|
+
rb_define_attr(rb_cPasswd, "passwd", 1, 1);
|
235
|
+
#endif
|
236
|
+
#ifdef HAVE_ST_PW_EXPIRE
|
237
|
+
rb_define_attr(rb_cPasswd, "expire", 1, 0); /* Number expressed as a count of days since Jan 1, 1970
|
238
|
+
on which the account will be disabled */
|
239
|
+
rb_define_method(rb_cPasswd, "expire=", user_set_expire, 1);
|
240
|
+
rb_define_method(rb_cPasswd, "expire_date", user_get_expire, 0);
|
241
|
+
rb_define_method(rb_cPasswd, "expire_date=", user_set_expire, 1);
|
242
|
+
#endif
|
243
|
+
|
244
|
+
#ifdef HAVE_ST_PW_CLASS
|
245
|
+
rb_define_attr(rb_cPasswd, "access_class", 1, 1);
|
246
|
+
#endif
|
247
|
+
|
248
|
+
#ifdef HAVE_ST_PW_FIELD
|
249
|
+
rb_define_attr(rb_cPasswd, "field", 1, 0);
|
250
|
+
#endif
|
251
|
+
|
252
|
+
rb_define_method(rb_cPasswd, "to_entry", user_pw_entry,0);
|
253
|
+
rb_define_method(rb_cPasswd, "fputs", user_putpwent, 1);
|
254
|
+
|
255
|
+
rb_define_singleton_method(rb_cPasswd,"get",eu_getpwent,0);
|
256
|
+
rb_define_singleton_method(rb_cPasswd,"each",eu_getpwent,0);
|
257
|
+
rb_define_singleton_method(rb_cPasswd,"find",eu_getpwd,1); // -1 return array
|
258
|
+
rb_define_singleton_method(rb_cPasswd,"parse",eu_sgetpwent,1);
|
259
|
+
|
260
|
+
|
261
|
+
rb_define_singleton_method(rb_cPasswd,"set", eu_setpwent, 0);
|
262
|
+
rb_define_singleton_method(rb_cPasswd,"end", eu_endpwent, 0);
|
263
|
+
#endif
|
264
|
+
|
265
|
+
#ifdef HAVE_SHADOW_H // Shadow specific methods
|
266
|
+
rb_define_attr(rb_cShadow, "name", 1, 1); /* Login name. */
|
267
|
+
rb_define_attr(rb_cShadow, "passwd", 1, 0); /* Encrypted password. */
|
268
|
+
rb_define_attr(rb_cShadow, "min_pw_age", 1, 1); /* Minimum number of days between changes. */
|
269
|
+
rb_define_attr(rb_cShadow, "max_pw_age", 1, 1); /* Maximum number of days between changes. */
|
270
|
+
rb_define_attr(rb_cShadow, "last_pw_change", 1, 0); /* Number expressed as a count of days since Jan 1, 1970
|
271
|
+
since the last password change */
|
272
|
+
rb_define_attr(rb_cShadow, "warning", 1, 1); /* Number of days to warn user to change
|
273
|
+
the password. */
|
274
|
+
rb_define_attr(rb_cShadow, "inactive", 1, 1); /* Number of days after password expires
|
275
|
+
that account is considered inactive and disabled */
|
276
|
+
rb_define_attr(rb_cShadow, "expire", 1, 0); /* Number expressed as a count of days since Jan 1, 1970
|
277
|
+
on which the account will be disabled */
|
278
|
+
rb_define_attr(rb_cShadow, "flag", 1, 0); /* Reserved */
|
279
|
+
|
280
|
+
rb_define_method(rb_cShadow, "passwd=", user_set_pw_change, 1);
|
281
|
+
rb_define_method(rb_cShadow, "expire=", user_set_expire, 1);
|
282
|
+
rb_define_method(rb_cShadow, "last_pw_change_date", user_get_pw_change, 0);
|
283
|
+
rb_define_method(rb_cShadow, "expire_date", user_get_expire, 0);
|
284
|
+
rb_define_method(rb_cShadow, "expire_date=", user_set_expire, 1);
|
285
|
+
|
286
|
+
rb_define_method(rb_cShadow, "to_entry", user_sp_entry,0);
|
287
|
+
rb_define_method(rb_cShadow, "fputs", user_putspent, 1);
|
288
|
+
|
289
|
+
rb_define_singleton_method(rb_cShadow,"get",eu_getspent,0);
|
290
|
+
rb_define_singleton_method(rb_cShadow,"each",eu_getspent,0);
|
291
|
+
rb_define_singleton_method(rb_cShadow,"find",eu_getspwd,1);
|
292
|
+
rb_define_singleton_method(rb_cShadow,"parse",eu_sgetspent,1);
|
293
|
+
|
294
|
+
rb_define_singleton_method(rb_cShadow,"set", eu_setspent, 0);
|
295
|
+
rb_define_singleton_method(rb_cShadow,"end", eu_endspent, 0);
|
296
|
+
#endif
|
297
|
+
}
|