rkerberos 0.3.0 → 0.3.1
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 +4 -4
- data/CHANGES.md +15 -0
- data/EXAMPLES.md +1 -1
- data/README.md +13 -2
- data/ext/rkerberos/ccache.c +9 -11
- data/ext/rkerberos/config.c +22 -16
- data/ext/rkerberos/context.c +64 -9
- data/ext/rkerberos/kadm5.c +79 -56
- data/ext/rkerberos/keytab.c +35 -30
- data/ext/rkerberos/principal.c +42 -12
- data/ext/rkerberos/rkerberos.c +55 -39
- data/ext/rkerberos/rkerberos.h +6 -0
- data/rkerberos.gemspec +1 -1
- data/spec/config_spec.rb +8 -0
- data/spec/context_spec.rb +45 -0
- data/spec/credentials_cache_spec.rb +3 -0
- data/spec/kadm5_spec.rb +42 -1
- data/spec/krb5_keytab_spec.rb +52 -1
- data/spec/krb5_spec.rb +57 -3
- data/spec/principal_spec.rb +26 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0dc45dbb751a22370948c430c6590df2a07739638dee7d208f8050d515dfbbfc
|
|
4
|
+
data.tar.gz: 318bd1b2a81b3791fddf876cdc65895a84645d9f60aa0c0cef3872005b217f6b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0aebb033c55950e140cbfc02abf00f37f4cedd5141228f0bb135d4b70dd93ce50dda121bda128374339259a4a58f7c6e5db09590cd41ba708130beafca734bd2
|
|
7
|
+
data.tar.gz: 26753f9dcecbecbf3234fc941fe42d380ac0e77829671fe4cc947dfcc081166e0faf77444fa65533bd1b26713b81f67f13f59e5be01a1f0749f3fc7b85430644
|
data/CHANGES.md
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
# 0.3.1 - 21-Aug-2026
|
|
2
|
+
* Hardened initial credential verification so it fails closed when verification
|
|
3
|
+
cannot be performed, rejects closed keytabs and credential caches, and safely
|
|
4
|
+
initializes a supplied cache before storing credentials.
|
|
5
|
+
* Added shared context lifetime tracking. `Context#close` now raises while
|
|
6
|
+
dependent wrappers remain open; `close(force: true)` logically closes the
|
|
7
|
+
context and defers native cleanup until its dependents close.
|
|
8
|
+
* Hardened native handle cleanup and closed-object checks across `Krb5`, `Kadm5`,
|
|
9
|
+
`CredentialsCache`, `Keytab`, and `Principal`.
|
|
10
|
+
* Fixed `Kadm5#modify_policy` to apply values assigned through `Policy` writers,
|
|
11
|
+
including password history, and require an explicit principal for keytab
|
|
12
|
+
authentication.
|
|
13
|
+
* Fixed `Keytab#each` and `Keytab.foreach` to raise iteration errors instead of
|
|
14
|
+
silently returning partial results.
|
|
15
|
+
|
|
1
16
|
# 0.3.0 - 20-Aug-2026
|
|
2
17
|
* Added optional shared `Context` support to the `Krb5`, `Kadm5`, `Config`,
|
|
3
18
|
`CredentialsCache`, `Keytab`, and `Principal` constructors.
|
data/EXAMPLES.md
CHANGED
data/README.md
CHANGED
|
@@ -18,7 +18,12 @@ puts krb.get_permitted_enctypes.keys.join(',')
|
|
|
18
18
|
|
|
19
19
|
# Credentials cache
|
|
20
20
|
cc = Kerberos::Krb5::CredentialsCache.new
|
|
21
|
-
krb.
|
|
21
|
+
krb.get_init_creds_password(
|
|
22
|
+
principal: ENV['KRB5_PRINCIPAL'],
|
|
23
|
+
password: ENV['KRB5_PASSWORD'],
|
|
24
|
+
ccache: cc
|
|
25
|
+
)
|
|
26
|
+
krb.verify_init_creds
|
|
22
27
|
puts cc.primary_principal
|
|
23
28
|
|
|
24
29
|
# Keytab
|
|
@@ -38,6 +43,13 @@ ctx = Kerberos::Krb5::Context.new # standard context
|
|
|
38
43
|
ctx = Kerberos::Krb5::Context.new(profile: '/etc/krb5.conf') # or use a profile
|
|
39
44
|
ctx = Kerberos::Krb5::Context.new(secure: true) # or use a secure context
|
|
40
45
|
ctx.close
|
|
46
|
+
|
|
47
|
+
# Contexts with active dependent wrappers reject close. A forced close stops
|
|
48
|
+
# direct context use immediately and defers native cleanup until dependents close.
|
|
49
|
+
ctx = Kerberos::Krb5::Context.new
|
|
50
|
+
krb = Kerberos::Krb5.new(context: ctx)
|
|
51
|
+
ctx.close(force: true)
|
|
52
|
+
krb.close
|
|
41
53
|
```
|
|
42
54
|
|
|
43
55
|
# Requirements
|
|
@@ -160,7 +172,6 @@ The test environment includes:
|
|
|
160
172
|
# TODO
|
|
161
173
|
* Create a separate class for the replay cache.
|
|
162
174
|
* Better credentials cache support.
|
|
163
|
-
* Ability to add and delete keytab entries.
|
|
164
175
|
|
|
165
176
|
# Authors
|
|
166
177
|
* Daniel Berger
|
data/ext/rkerberos/ccache.c
CHANGED
|
@@ -20,6 +20,8 @@ static void rkrb5_ccache_typed_free(void *ptr) {
|
|
|
20
20
|
krb5_free_principal(c->ctx, c->principal);
|
|
21
21
|
if (c->ctx && c->rb_context == Qnil)
|
|
22
22
|
krb5_free_context(c->ctx);
|
|
23
|
+
else if (c->rb_context != Qnil)
|
|
24
|
+
rkrb5_context_release(c->rb_context);
|
|
23
25
|
free(c);
|
|
24
26
|
}
|
|
25
27
|
|
|
@@ -91,17 +93,7 @@ static VALUE rkrb5_ccache_initialize(int argc, VALUE* argv, VALUE self){
|
|
|
91
93
|
|
|
92
94
|
// Initialize or borrow the context
|
|
93
95
|
if(!NIL_P(v_context)){
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
if(!rb_obj_is_kind_of(v_context, cKrb5Context))
|
|
97
|
-
rb_raise(rb_eTypeError, "context must be a Kerberos::Krb5::Context object");
|
|
98
|
-
|
|
99
|
-
TypedData_Get_Struct(v_context, RUBY_KRB5_CONTEXT, &rkrb5_context_data_type, ctx_ptr);
|
|
100
|
-
|
|
101
|
-
if(!ctx_ptr->ctx)
|
|
102
|
-
rb_raise(cKrb5Exception, "context is closed");
|
|
103
|
-
|
|
104
|
-
ptr->ctx = ctx_ptr->ctx;
|
|
96
|
+
ptr->ctx = rkrb5_context_borrow(v_context);
|
|
105
97
|
ptr->rb_context = v_context;
|
|
106
98
|
}
|
|
107
99
|
else{
|
|
@@ -176,6 +168,8 @@ static VALUE rkrb5_ccache_close(VALUE self){
|
|
|
176
168
|
|
|
177
169
|
if(ptr->ctx && ptr->rb_context == Qnil)
|
|
178
170
|
krb5_free_context(ptr->ctx);
|
|
171
|
+
else if(ptr->rb_context != Qnil)
|
|
172
|
+
rkrb5_context_release(ptr->rb_context);
|
|
179
173
|
|
|
180
174
|
ptr->ccache = NULL;
|
|
181
175
|
ptr->ctx = NULL;
|
|
@@ -309,6 +303,8 @@ static VALUE rkrb5_ccache_destroy(VALUE self){
|
|
|
309
303
|
|
|
310
304
|
if(ptr->ctx && ptr->rb_context == Qnil)
|
|
311
305
|
krb5_free_context(ptr->ctx);
|
|
306
|
+
else if(ptr->rb_context != Qnil)
|
|
307
|
+
rkrb5_context_release(ptr->rb_context);
|
|
312
308
|
|
|
313
309
|
ptr->ccache = NULL;
|
|
314
310
|
ptr->ctx = NULL;
|
|
@@ -324,6 +320,8 @@ static VALUE rkrb5_ccache_destroy(VALUE self){
|
|
|
324
320
|
|
|
325
321
|
if(ptr->ctx && ptr->rb_context == Qnil)
|
|
326
322
|
krb5_free_context(ptr->ctx);
|
|
323
|
+
else if(ptr->rb_context != Qnil)
|
|
324
|
+
rkrb5_context_release(ptr->rb_context);
|
|
327
325
|
|
|
328
326
|
ptr->ccache = NULL;
|
|
329
327
|
ptr->ctx = NULL;
|
data/ext/rkerberos/config.c
CHANGED
|
@@ -4,6 +4,22 @@
|
|
|
4
4
|
VALUE cKadm5Config;
|
|
5
5
|
VALUE cKeySalt;
|
|
6
6
|
|
|
7
|
+
static void rkadm5_config_cleanup(RUBY_KADM5_CONFIG *ptr){
|
|
8
|
+
if(!ptr->ctx)
|
|
9
|
+
return;
|
|
10
|
+
|
|
11
|
+
kadm5_free_config_params(ptr->ctx, &ptr->config);
|
|
12
|
+
|
|
13
|
+
if(ptr->rb_context == Qnil)
|
|
14
|
+
krb5_free_context(ptr->ctx);
|
|
15
|
+
else
|
|
16
|
+
rkrb5_context_release(ptr->rb_context);
|
|
17
|
+
|
|
18
|
+
ptr->ctx = NULL;
|
|
19
|
+
ptr->rb_context = Qnil;
|
|
20
|
+
memset(&ptr->config, 0, sizeof(ptr->config));
|
|
21
|
+
}
|
|
22
|
+
|
|
7
23
|
|
|
8
24
|
// TypedData functions for RUBY_KADM5_CONFIG
|
|
9
25
|
static void rkadm5_config_typed_mark(void *ptr) {
|
|
@@ -16,11 +32,7 @@ static void rkadm5_config_typed_mark(void *ptr) {
|
|
|
16
32
|
static void rkadm5_config_typed_free(void *ptr) {
|
|
17
33
|
if (!ptr) return;
|
|
18
34
|
RUBY_KADM5_CONFIG *c = (RUBY_KADM5_CONFIG *)ptr;
|
|
19
|
-
|
|
20
|
-
kadm5_free_config_params(c->ctx, &c->config);
|
|
21
|
-
if (c->rb_context == Qnil)
|
|
22
|
-
krb5_free_context(c->ctx);
|
|
23
|
-
}
|
|
35
|
+
rkadm5_config_cleanup(c);
|
|
24
36
|
free(c);
|
|
25
37
|
}
|
|
26
38
|
|
|
@@ -85,17 +97,7 @@ static VALUE rkadm5_config_initialize(int argc, VALUE* argv, VALUE self){
|
|
|
85
97
|
v_context = kw_vals[0] == Qundef ? Qnil : kw_vals[0];
|
|
86
98
|
|
|
87
99
|
if(!NIL_P(v_context)){
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
if(!rb_obj_is_kind_of(v_context, cKrb5Context))
|
|
91
|
-
rb_raise(rb_eTypeError, "context must be a Kerberos::Krb5::Context object");
|
|
92
|
-
|
|
93
|
-
TypedData_Get_Struct(v_context, RUBY_KRB5_CONTEXT, &rkrb5_context_data_type, ctx_ptr);
|
|
94
|
-
|
|
95
|
-
if(!ctx_ptr->ctx)
|
|
96
|
-
rb_raise(cKrb5Exception, "context is closed");
|
|
97
|
-
|
|
98
|
-
ptr->ctx = ctx_ptr->ctx;
|
|
100
|
+
ptr->ctx = rkrb5_context_borrow(v_context);
|
|
99
101
|
ptr->rb_context = v_context;
|
|
100
102
|
}
|
|
101
103
|
else{
|
|
@@ -234,6 +236,10 @@ static VALUE rkadm5_config_initialize(int argc, VALUE* argv, VALUE self){
|
|
|
234
236
|
rb_iv_set(self, "@keysalts", Qnil);
|
|
235
237
|
}
|
|
236
238
|
|
|
239
|
+
// All configuration data has been copied into Ruby values, so this object
|
|
240
|
+
// no longer needs to retain its native context lease.
|
|
241
|
+
rkadm5_config_cleanup(ptr);
|
|
242
|
+
|
|
237
243
|
// This is read only data
|
|
238
244
|
rb_obj_freeze(self);
|
|
239
245
|
|
data/ext/rkerberos/context.c
CHANGED
|
@@ -15,6 +15,38 @@ static void rkrb5_context_typed_free(void *ptr) {
|
|
|
15
15
|
free(c);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
krb5_context rkrb5_context_borrow(VALUE v_context){
|
|
19
|
+
RUBY_KRB5_CONTEXT* ptr;
|
|
20
|
+
|
|
21
|
+
if(!rb_obj_is_kind_of(v_context, cKrb5Context))
|
|
22
|
+
rb_raise(rb_eTypeError, "context must be a Kerberos::Krb5::Context object");
|
|
23
|
+
|
|
24
|
+
TypedData_Get_Struct(v_context, RUBY_KRB5_CONTEXT, &rkrb5_context_data_type, ptr);
|
|
25
|
+
|
|
26
|
+
if(!ptr->ctx || ptr->closed)
|
|
27
|
+
rb_raise(cKrb5Exception, "context is closed");
|
|
28
|
+
|
|
29
|
+
ptr->borrowers++;
|
|
30
|
+
return ptr->ctx;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
void rkrb5_context_release(VALUE v_context){
|
|
34
|
+
RUBY_KRB5_CONTEXT* ptr;
|
|
35
|
+
|
|
36
|
+
if(NIL_P(v_context))
|
|
37
|
+
return;
|
|
38
|
+
|
|
39
|
+
ptr = (RUBY_KRB5_CONTEXT*)RTYPEDDATA_DATA(v_context);
|
|
40
|
+
|
|
41
|
+
if(ptr->borrowers > 0)
|
|
42
|
+
ptr->borrowers--;
|
|
43
|
+
|
|
44
|
+
if(ptr->closed && ptr->borrowers == 0 && ptr->ctx){
|
|
45
|
+
krb5_free_context(ptr->ctx);
|
|
46
|
+
ptr->ctx = NULL;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
18
50
|
static size_t rkrb5_context_typed_size(const void *ptr) {
|
|
19
51
|
return sizeof(RUBY_KRB5_CONTEXT);
|
|
20
52
|
}
|
|
@@ -34,19 +66,42 @@ static VALUE rkrb5_context_allocate(VALUE klass){
|
|
|
34
66
|
|
|
35
67
|
/*
|
|
36
68
|
* call-seq:
|
|
37
|
-
* context.close
|
|
69
|
+
* context.close(force: false)
|
|
38
70
|
*
|
|
39
|
-
* Closes the context object.
|
|
71
|
+
* Closes the context object. Raises if wrappers are still borrowing the
|
|
72
|
+
* context. With +force: true+, the context is closed to new operations and
|
|
73
|
+
* borrowers immediately, but its native resources are retained until the
|
|
74
|
+
* existing borrowers have closed.
|
|
40
75
|
*/
|
|
41
|
-
static VALUE rkrb5_context_close(VALUE self){
|
|
76
|
+
static VALUE rkrb5_context_close(int argc, VALUE* argv, VALUE self){
|
|
42
77
|
RUBY_KRB5_CONTEXT* ptr;
|
|
78
|
+
VALUE v_opts, v_force;
|
|
79
|
+
ID kw_table[1] = { rb_intern("force") };
|
|
80
|
+
VALUE kw_vals[1];
|
|
43
81
|
|
|
44
82
|
TypedData_Get_Struct(self, RUBY_KRB5_CONTEXT, &rkrb5_context_data_type, ptr);
|
|
45
83
|
|
|
46
|
-
|
|
47
|
-
|
|
84
|
+
rb_scan_args(argc, argv, "0:", &v_opts);
|
|
85
|
+
|
|
86
|
+
if(NIL_P(v_opts))
|
|
87
|
+
v_opts = rb_hash_new();
|
|
88
|
+
|
|
89
|
+
rb_get_kwargs(v_opts, kw_table, 0, 1, kw_vals);
|
|
90
|
+
v_force = kw_vals[0] == Qundef ? Qfalse : kw_vals[0];
|
|
48
91
|
|
|
49
|
-
ptr->
|
|
92
|
+
if(ptr->closed || !ptr->ctx)
|
|
93
|
+
return self;
|
|
94
|
+
|
|
95
|
+
if(ptr->borrowers > 0 && !RTEST(v_force))
|
|
96
|
+
rb_raise(cKrb5Exception, "context is in use by %lu dependent wrapper%s",
|
|
97
|
+
(unsigned long)ptr->borrowers, ptr->borrowers == 1 ? "" : "s");
|
|
98
|
+
|
|
99
|
+
ptr->closed = 1;
|
|
100
|
+
|
|
101
|
+
if(ptr->borrowers == 0){
|
|
102
|
+
krb5_free_context(ptr->ctx);
|
|
103
|
+
ptr->ctx = NULL;
|
|
104
|
+
}
|
|
50
105
|
|
|
51
106
|
return self;
|
|
52
107
|
}
|
|
@@ -147,7 +202,7 @@ static VALUE rkrb5_context_default_realm(VALUE self){
|
|
|
147
202
|
|
|
148
203
|
TypedData_Get_Struct(self, RUBY_KRB5_CONTEXT, &rkrb5_context_data_type, ptr);
|
|
149
204
|
|
|
150
|
-
if(!ptr->ctx)
|
|
205
|
+
if(!ptr->ctx || ptr->closed)
|
|
151
206
|
rb_raise(cKrb5Exception, "no context has been established");
|
|
152
207
|
|
|
153
208
|
kerror = krb5_get_default_realm(ptr->ctx, &realm);
|
|
@@ -175,7 +230,7 @@ static VALUE rkrb5_context_set_default_realm(VALUE self, VALUE v_realm){
|
|
|
175
230
|
|
|
176
231
|
TypedData_Get_Struct(self, RUBY_KRB5_CONTEXT, &rkrb5_context_data_type, ptr);
|
|
177
232
|
|
|
178
|
-
if(!ptr->ctx)
|
|
233
|
+
if(!ptr->ctx || ptr->closed)
|
|
179
234
|
rb_raise(cKrb5Exception, "no context has been established");
|
|
180
235
|
|
|
181
236
|
if(NIL_P(v_realm)){
|
|
@@ -205,7 +260,7 @@ void Init_context(void){
|
|
|
205
260
|
rb_define_method(cKrb5Context, "initialize", rkrb5_context_initialize, -1);
|
|
206
261
|
|
|
207
262
|
// Instance Methods
|
|
208
|
-
rb_define_method(cKrb5Context, "close", rkrb5_context_close,
|
|
263
|
+
rb_define_method(cKrb5Context, "close", rkrb5_context_close, -1);
|
|
209
264
|
rb_define_method(cKrb5Context, "default_realm", rkrb5_context_default_realm, 0);
|
|
210
265
|
rb_define_method(cKrb5Context, "default_realm=", rkrb5_context_set_default_realm, 1);
|
|
211
266
|
}
|
data/ext/rkerberos/kadm5.c
CHANGED
|
@@ -8,6 +8,7 @@ VALUE cKadm5PrincipalNotFoundException;
|
|
|
8
8
|
|
|
9
9
|
// Prototype
|
|
10
10
|
static VALUE rkadm5_close(VALUE);
|
|
11
|
+
static void rkadm5_check_open(RUBY_KADM5 *);
|
|
11
12
|
static void free_tl_data(krb5_tl_data *);
|
|
12
13
|
static void free_db_args(char**);
|
|
13
14
|
char** parse_db_args(VALUE v_db_args);
|
|
@@ -33,6 +34,8 @@ static void rkadm5_typed_free(void *ptr) {
|
|
|
33
34
|
krb5_free_principal(k->ctx, k->princ);
|
|
34
35
|
if (k->ctx && k->rb_context == Qnil)
|
|
35
36
|
krb5_free_context(k->ctx);
|
|
37
|
+
else if (k->rb_context != Qnil)
|
|
38
|
+
rkrb5_context_release(k->rb_context);
|
|
36
39
|
free_db_args(k->db_args);
|
|
37
40
|
free(k);
|
|
38
41
|
}
|
|
@@ -55,6 +58,11 @@ static VALUE rkadm5_allocate(VALUE klass){
|
|
|
55
58
|
return TypedData_Wrap_Struct(klass, &rkadm5_data_type, ptr);
|
|
56
59
|
}
|
|
57
60
|
|
|
61
|
+
static void rkadm5_check_open(RUBY_KADM5 *ptr){
|
|
62
|
+
if(!ptr->ctx || !ptr->handle)
|
|
63
|
+
rb_raise(cKadm5Exception, "no administrative context has been established");
|
|
64
|
+
}
|
|
65
|
+
|
|
58
66
|
/*
|
|
59
67
|
* call-seq:
|
|
60
68
|
* Kerberos::Kadm5.new(principal: 'name', password: 'xxxxx')
|
|
@@ -140,17 +148,14 @@ static VALUE rkadm5_initialize(int argc, VALUE* argv, VALUE self){
|
|
|
140
148
|
pass = StringValueCStr(v_password);
|
|
141
149
|
}
|
|
142
150
|
|
|
143
|
-
if(RTEST(
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
151
|
+
if(RTEST(v_keytab) && NIL_P(v_principal))
|
|
152
|
+
rb_raise(rb_eArgError, "principal must be specified when using a keytab");
|
|
153
|
+
|
|
154
|
+
if(RTEST(v_ccache) && !rb_obj_is_kind_of(v_ccache, cKrb5CCache))
|
|
155
|
+
rb_raise(rb_eTypeError, "ccache must be a Kerberos::Krb5::CredentialsCache object");
|
|
147
156
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
VALUE v_enum, v_first;
|
|
151
|
-
v_enum = rb_funcall(v_keytab, rb_intern("each"), 0);
|
|
152
|
-
v_first = rb_funcall(v_enum, rb_intern("first"), 0);
|
|
153
|
-
v_principal = rb_iv_get(v_first, "@principal");
|
|
157
|
+
if(RTEST(v_ccache) && NIL_P(v_principal)){
|
|
158
|
+
v_principal = rb_funcall(v_ccache, rb_intern("principal"), 0);
|
|
154
159
|
}
|
|
155
160
|
|
|
156
161
|
user = StringValueCStr(v_principal);
|
|
@@ -166,17 +171,7 @@ static VALUE rkadm5_initialize(int argc, VALUE* argv, VALUE self){
|
|
|
166
171
|
|
|
167
172
|
// Initialize or borrow the context
|
|
168
173
|
if(!NIL_P(v_context)){
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
if(!rb_obj_is_kind_of(v_context, cKrb5Context))
|
|
172
|
-
rb_raise(rb_eTypeError, "context must be a Kerberos::Krb5::Context object");
|
|
173
|
-
|
|
174
|
-
TypedData_Get_Struct(v_context, RUBY_KRB5_CONTEXT, &rkrb5_context_data_type, ctx_ptr);
|
|
175
|
-
|
|
176
|
-
if(!ctx_ptr->ctx)
|
|
177
|
-
rb_raise(cKrb5Exception, "context is closed");
|
|
178
|
-
|
|
179
|
-
ptr->ctx = ctx_ptr->ctx;
|
|
174
|
+
ptr->ctx = rkrb5_context_borrow(v_context);
|
|
180
175
|
ptr->rb_context = v_context;
|
|
181
176
|
}
|
|
182
177
|
else{
|
|
@@ -239,12 +234,9 @@ static VALUE rkadm5_initialize(int argc, VALUE* argv, VALUE self){
|
|
|
239
234
|
else if(RTEST(v_ccache)){
|
|
240
235
|
RUBY_KRB5_CCACHE* cc_ptr;
|
|
241
236
|
|
|
242
|
-
if(!rb_obj_is_kind_of(v_ccache, cKrb5CCache))
|
|
243
|
-
rb_raise(rb_eTypeError, "ccache must be a Kerberos::Krb5::CredentialsCache object");
|
|
244
|
-
|
|
245
237
|
TypedData_Get_Struct(v_ccache, RUBY_KRB5_CCACHE, &rkrb5_ccache_data_type, cc_ptr);
|
|
246
238
|
|
|
247
|
-
if(!cc_ptr->ccache)
|
|
239
|
+
if(!cc_ptr->ctx || !cc_ptr->ccache)
|
|
248
240
|
rb_raise(cKrb5Exception, "credentials cache is closed or destroyed");
|
|
249
241
|
|
|
250
242
|
kerror = kadm5_init_with_creds(
|
|
@@ -289,8 +281,7 @@ static VALUE rkadm5_set_password(VALUE self, VALUE v_user, VALUE v_pass){
|
|
|
289
281
|
user = StringValueCStr(v_user);
|
|
290
282
|
pass = StringValueCStr(v_pass);
|
|
291
283
|
|
|
292
|
-
|
|
293
|
-
rb_raise(cKadm5Exception, "no context has been established");
|
|
284
|
+
rkadm5_check_open(ptr);
|
|
294
285
|
|
|
295
286
|
if(ptr->princ){
|
|
296
287
|
krb5_free_principal(ptr->ctx, ptr->princ);
|
|
@@ -327,8 +318,7 @@ static VALUE rkadm5_set_pwexpire(VALUE self, VALUE v_user, VALUE v_pwexpire){
|
|
|
327
318
|
|
|
328
319
|
TypedData_Get_Struct(self, RUBY_KADM5, &rkadm5_data_type, ptr);
|
|
329
320
|
|
|
330
|
-
|
|
331
|
-
rb_raise(cKadm5Exception, "no context has been established");
|
|
321
|
+
rkadm5_check_open(ptr);
|
|
332
322
|
|
|
333
323
|
if(ptr->princ){
|
|
334
324
|
krb5_free_principal(ptr->ctx, ptr->princ);
|
|
@@ -398,6 +388,8 @@ static VALUE rkadm5_create_principal(int argc, VALUE* argv, VALUE self){
|
|
|
398
388
|
|
|
399
389
|
TypedData_Get_Struct(self, RUBY_KADM5, &rkadm5_data_type, ptr);
|
|
400
390
|
|
|
391
|
+
rkadm5_check_open(ptr);
|
|
392
|
+
|
|
401
393
|
rb_scan_args(argc, argv, "0:", &v_opts);
|
|
402
394
|
|
|
403
395
|
if(NIL_P(v_opts))
|
|
@@ -429,9 +421,6 @@ static VALUE rkadm5_create_principal(int argc, VALUE* argv, VALUE self){
|
|
|
429
421
|
add_db_args(&princ, db_args);
|
|
430
422
|
free_db_args(db_args);
|
|
431
423
|
|
|
432
|
-
if(!ptr->ctx)
|
|
433
|
-
rb_raise(cKadm5Exception, "no context has been established");
|
|
434
|
-
|
|
435
424
|
// Determine the principal name and populate mask from the principal object
|
|
436
425
|
if(RTEST(v_principal)){
|
|
437
426
|
VALUE v_princ_name, v_policy, v_expire, v_pw_expire, v_max_life, v_max_renew, v_attrs;
|
|
@@ -536,8 +525,7 @@ static VALUE rkadm5_delete_principal(VALUE self, VALUE v_user){
|
|
|
536
525
|
Check_Type(v_user, T_STRING);
|
|
537
526
|
user = StringValueCStr(v_user);
|
|
538
527
|
|
|
539
|
-
|
|
540
|
-
rb_raise(cKadm5Exception, "no context has been established");
|
|
528
|
+
rkadm5_check_open(ptr);
|
|
541
529
|
|
|
542
530
|
if(ptr->princ){
|
|
543
531
|
krb5_free_principal(ptr->ctx, ptr->princ);
|
|
@@ -579,6 +567,8 @@ static VALUE rkadm5_close(VALUE self){
|
|
|
579
567
|
|
|
580
568
|
if(ptr->ctx && ptr->rb_context == Qnil)
|
|
581
569
|
krb5_free_context(ptr->ctx);
|
|
570
|
+
else if(ptr->rb_context != Qnil)
|
|
571
|
+
rkrb5_context_release(ptr->rb_context);
|
|
582
572
|
|
|
583
573
|
free_db_args(ptr->db_args);
|
|
584
574
|
|
|
@@ -674,8 +664,7 @@ static VALUE rkadm5_find_principal(VALUE self, VALUE v_user){
|
|
|
674
664
|
|
|
675
665
|
memset(&ent, 0, sizeof(ent));
|
|
676
666
|
|
|
677
|
-
|
|
678
|
-
rb_raise(cKadm5Exception, "no context has been established");
|
|
667
|
+
rkadm5_check_open(ptr);
|
|
679
668
|
|
|
680
669
|
if(ptr->princ){
|
|
681
670
|
krb5_free_principal(ptr->ctx, ptr->princ);
|
|
@@ -735,8 +724,7 @@ static VALUE rkadm5_get_principal(VALUE self, VALUE v_user){
|
|
|
735
724
|
|
|
736
725
|
memset(&ent, 0, sizeof(ent));
|
|
737
726
|
|
|
738
|
-
|
|
739
|
-
rb_raise(cKadm5Exception, "no context has been established");
|
|
727
|
+
rkadm5_check_open(ptr);
|
|
740
728
|
|
|
741
729
|
if(ptr->princ){
|
|
742
730
|
krb5_free_principal(ptr->ctx, ptr->princ);
|
|
@@ -794,6 +782,8 @@ static VALUE rkadm5_create_policy(int argc, VALUE* argv, VALUE self){
|
|
|
794
782
|
|
|
795
783
|
TypedData_Get_Struct(self, RUBY_KADM5, &rkadm5_data_type, ptr);
|
|
796
784
|
|
|
785
|
+
rkadm5_check_open(ptr);
|
|
786
|
+
|
|
797
787
|
rb_scan_args(argc, argv, "01:", &v_policy, &v_kwargs);
|
|
798
788
|
|
|
799
789
|
if(!NIL_P(v_kwargs)){
|
|
@@ -871,6 +861,8 @@ static VALUE rkadm5_delete_policy(VALUE self, VALUE v_policy){
|
|
|
871
861
|
|
|
872
862
|
TypedData_Get_Struct(self, RUBY_KADM5, &rkadm5_data_type, ptr);
|
|
873
863
|
|
|
864
|
+
rkadm5_check_open(ptr);
|
|
865
|
+
|
|
874
866
|
policy = StringValueCStr(v_policy);
|
|
875
867
|
|
|
876
868
|
kerror = kadm5_delete_policy(ptr->handle, policy);
|
|
@@ -901,8 +893,7 @@ static VALUE rkadm5_get_policy(VALUE self, VALUE v_name){
|
|
|
901
893
|
TypedData_Get_Struct(self, RUBY_KADM5, &rkadm5_data_type, ptr);
|
|
902
894
|
memset(&ent, 0, sizeof(ent));
|
|
903
895
|
|
|
904
|
-
|
|
905
|
-
rb_raise(cKadm5Exception, "no context has been established");
|
|
896
|
+
rkadm5_check_open(ptr);
|
|
906
897
|
|
|
907
898
|
policy_name = StringValueCStr(v_name);
|
|
908
899
|
|
|
@@ -955,8 +946,7 @@ static VALUE rkadm5_find_policy(VALUE self, VALUE v_name){
|
|
|
955
946
|
TypedData_Get_Struct(self, RUBY_KADM5, &rkadm5_data_type, ptr);
|
|
956
947
|
memset(&ent, 0, sizeof(ent));
|
|
957
948
|
|
|
958
|
-
|
|
959
|
-
rb_raise(cKadm5Exception, "no context has been established");
|
|
949
|
+
rkadm5_check_open(ptr);
|
|
960
950
|
|
|
961
951
|
policy_name = StringValueCStr(v_name);
|
|
962
952
|
|
|
@@ -1001,34 +991,59 @@ static VALUE rkadm5_find_policy(VALUE self, VALUE v_name){
|
|
|
1001
991
|
* Example:
|
|
1002
992
|
*
|
|
1003
993
|
* policy = Kerberos::Kadm5::Policy.find('test')
|
|
1004
|
-
* policy.
|
|
994
|
+
* policy.max_life = 1024
|
|
1005
995
|
* kadm5.modify_policy(policy)
|
|
1006
996
|
*/
|
|
1007
997
|
static VALUE rkadm5_modify_policy(VALUE self, VALUE v_policy){
|
|
1008
998
|
RUBY_KADM5* ptr;
|
|
1009
|
-
RUBY_KADM5_POLICY* pptr;
|
|
1010
999
|
kadm5_ret_t kerror;
|
|
1011
|
-
|
|
1000
|
+
kadm5_policy_ent_rec ent;
|
|
1001
|
+
long mask = 0;
|
|
1002
|
+
VALUE v_name, v_min_classes, v_min_life, v_max_life, v_min_length, v_history_num;
|
|
1012
1003
|
|
|
1013
1004
|
TypedData_Get_Struct(self, RUBY_KADM5, &rkadm5_data_type, ptr);
|
|
1014
|
-
TypedData_Get_Struct(v_policy, RUBY_KADM5_POLICY, &rkadm5_policy_data_type, pptr);
|
|
1015
1005
|
|
|
1016
|
-
|
|
1017
|
-
|
|
1006
|
+
rkadm5_check_open(ptr);
|
|
1007
|
+
|
|
1008
|
+
if(!rb_obj_is_kind_of(v_policy, cKadm5Policy))
|
|
1009
|
+
rb_raise(rb_eTypeError, "expected a Kerberos::Kadm5::Policy object");
|
|
1010
|
+
|
|
1011
|
+
v_name = rb_iv_get(v_policy, "@policy");
|
|
1012
|
+
v_min_classes = rb_iv_get(v_policy, "@min_classes");
|
|
1013
|
+
v_min_length = rb_iv_get(v_policy, "@min_length");
|
|
1014
|
+
v_min_life = rb_iv_get(v_policy, "@min_life");
|
|
1015
|
+
v_max_life = rb_iv_get(v_policy, "@max_life");
|
|
1016
|
+
v_history_num = rb_iv_get(v_policy, "@history_num");
|
|
1017
|
+
|
|
1018
|
+
memset(&ent, 0, sizeof(ent));
|
|
1019
|
+
ent.policy = StringValueCStr(v_name);
|
|
1018
1020
|
|
|
1019
|
-
if(
|
|
1021
|
+
if(!NIL_P(v_min_classes)){
|
|
1020
1022
|
mask |= KADM5_PW_MIN_CLASSES;
|
|
1023
|
+
ent.pw_min_classes = NUM2LONG(v_min_classes);
|
|
1024
|
+
}
|
|
1021
1025
|
|
|
1022
|
-
if(
|
|
1026
|
+
if(!NIL_P(v_min_length)){
|
|
1023
1027
|
mask |= KADM5_PW_MIN_LENGTH;
|
|
1028
|
+
ent.pw_min_length = NUM2LONG(v_min_length);
|
|
1029
|
+
}
|
|
1024
1030
|
|
|
1025
|
-
if(
|
|
1031
|
+
if(!NIL_P(v_min_life)){
|
|
1026
1032
|
mask |= KADM5_PW_MIN_LIFE;
|
|
1033
|
+
ent.pw_min_life = NUM2LONG(v_min_life);
|
|
1034
|
+
}
|
|
1027
1035
|
|
|
1028
|
-
if(
|
|
1036
|
+
if(!NIL_P(v_max_life)){
|
|
1029
1037
|
mask |= KADM5_PW_MAX_LIFE;
|
|
1038
|
+
ent.pw_max_life = NUM2LONG(v_max_life);
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
if(!NIL_P(v_history_num)){
|
|
1042
|
+
mask |= KADM5_PW_HISTORY_NUM;
|
|
1043
|
+
ent.pw_history_num = NUM2LONG(v_history_num);
|
|
1044
|
+
}
|
|
1030
1045
|
|
|
1031
|
-
kerror = kadm5_modify_policy(ptr->handle, &
|
|
1046
|
+
kerror = kadm5_modify_policy(ptr->handle, &ent, mask);
|
|
1032
1047
|
|
|
1033
1048
|
if(kerror)
|
|
1034
1049
|
rb_raise(cKadm5Exception, "kadm5_modify_policy: %s (%li)", error_message(kerror), kerror);
|
|
@@ -1059,6 +1074,8 @@ static VALUE rkadm5_get_policies(int argc, VALUE* argv, VALUE self){
|
|
|
1059
1074
|
|
|
1060
1075
|
TypedData_Get_Struct(self, RUBY_KADM5, &rkadm5_data_type, ptr);
|
|
1061
1076
|
|
|
1077
|
+
rkadm5_check_open(ptr);
|
|
1078
|
+
|
|
1062
1079
|
rb_scan_args(argc, argv, "01", &v_expr);
|
|
1063
1080
|
|
|
1064
1081
|
if(NIL_P(v_expr))
|
|
@@ -1107,6 +1124,8 @@ static VALUE rkadm5_get_principals(int argc, VALUE* argv, VALUE self){
|
|
|
1107
1124
|
|
|
1108
1125
|
TypedData_Get_Struct(self, RUBY_KADM5, &rkadm5_data_type, ptr);
|
|
1109
1126
|
|
|
1127
|
+
rkadm5_check_open(ptr);
|
|
1128
|
+
|
|
1110
1129
|
rb_scan_args(argc, argv, "01", &v_expr);
|
|
1111
1130
|
|
|
1112
1131
|
if(NIL_P(v_expr))
|
|
@@ -1155,6 +1174,8 @@ static VALUE rkadm5_get_privs(int argc, VALUE* argv, VALUE self){
|
|
|
1155
1174
|
|
|
1156
1175
|
TypedData_Get_Struct(self, RUBY_KADM5, &rkadm5_data_type, ptr);
|
|
1157
1176
|
|
|
1177
|
+
rkadm5_check_open(ptr);
|
|
1178
|
+
|
|
1158
1179
|
rb_scan_args(argc, argv, "01", &v_strings);
|
|
1159
1180
|
|
|
1160
1181
|
kerror = kadm5_get_privs(ptr->handle, &privs);
|
|
@@ -1200,8 +1221,7 @@ static VALUE rkadm5_randkey_principal(VALUE self, VALUE v_user){
|
|
|
1200
1221
|
|
|
1201
1222
|
user = StringValueCStr(v_user);
|
|
1202
1223
|
|
|
1203
|
-
|
|
1204
|
-
rb_raise(cKadm5Exception, "no context has been established");
|
|
1224
|
+
rkadm5_check_open(ptr);
|
|
1205
1225
|
|
|
1206
1226
|
kerror = krb5_parse_name(ptr->ctx, user, &princ);
|
|
1207
1227
|
|
|
@@ -1240,10 +1260,13 @@ char** parse_db_args(VALUE v_db_args){
|
|
|
1240
1260
|
case T_ARRAY:
|
|
1241
1261
|
// Multiple arguments
|
|
1242
1262
|
array_length = RARRAY_LEN(v_db_args);
|
|
1263
|
+
|
|
1264
|
+
for(long i = 0; i < array_length; ++i)
|
|
1265
|
+
Check_Type(rb_ary_entry(v_db_args, i), T_STRING);
|
|
1266
|
+
|
|
1243
1267
|
db_args = (char **) malloc((array_length + 1) * sizeof(char *));
|
|
1244
1268
|
for(long i = 0; i < array_length; ++i){
|
|
1245
1269
|
VALUE elem = rb_ary_entry(v_db_args, i);
|
|
1246
|
-
Check_Type(elem, T_STRING);
|
|
1247
1270
|
db_args[i] = strdup(StringValueCStr(elem));
|
|
1248
1271
|
}
|
|
1249
1272
|
db_args[array_length] = NULL;
|