bsdcontrol.rb 0.2.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 90a98e28b884d5183cefa9e1edc521feca8a6a2b36244deb3cebd3832cc0ca88
4
+ data.tar.gz: bdb8514fce915c367f8750ee20de5106c7f0e54ad437c55af8895f4123cae4a3
5
+ SHA512:
6
+ metadata.gz: 179433d4c7fb138be1a572b732a17062375f3153b069459e1fe75dee7db9f8a3c6737d82d5709bd8f91f220380ec429c5f75d99183f0f6d1558a28c0932bf1e4
7
+ data.tar.gz: 45384e9aee1f2b8ddb12376049611a83769e9b4c7b78086eb5927a41e7b50abce29fdc56aa14cd17734b5c7efd2aa0ff99a7c3c04db67d44a57cc894b08287af
data/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ Copyright (C) 2023 by 0x1eef <0x1eef@protonmail.com>
2
+
3
+ Permission to use, copy, modify, and/or distribute this
4
+ software for any purpose with or without fee is hereby
5
+ granted.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS
8
+ ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
9
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
10
+ EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
12
+ RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
14
+ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
15
+ OF THIS SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,81 @@
1
+ ## About
2
+
3
+ bsdcontrol.rb provides Ruby bindings for libhbsdcontrol from the
4
+ [HardenedBSD](https://HardenedBSD.org) project.
5
+
6
+ ## Examples
7
+
8
+ __Features__
9
+
10
+ The first example prints a list of HardenedBSD features that
11
+ can be enabled, disabled or restored to the system default
12
+ setting:
13
+
14
+ ``` ruby
15
+ #!/usr/bin/env ruby
16
+ # Required privileges: user, superuser
17
+ require "bsdcontrol"
18
+ BSD::Control
19
+ .available_features
20
+ .each do
21
+ print "The ", _1.name, " feature is available", "\n"
22
+ end
23
+ ```
24
+
25
+ __Enable__
26
+
27
+ The following example enables the mprotect feature for the emacs binary. When
28
+ a feature is enabled for a given file, that setting takes precendence
29
+ over the system default. The system default can be restored with
30
+ [BSD::Control::Feature#sysdef!](http://0x1eef.github.io/x/bsdcontrol.rb/BSD/Control/Feature.html#sysdef!-instance_method):
31
+
32
+ ``` ruby
33
+ #!/usr/bin/env ruby
34
+ # Required privileges: superuser
35
+ require "bsdcontrol"
36
+ BSD::Control
37
+ .feature(:mprotect)
38
+ .enable!("/usr/local/bin/emacs-29.2")
39
+ ```
40
+
41
+ __Status__
42
+
43
+ There are five recognized statuses: `unknown`, `enabled`, `disabled`,
44
+ `sysdef`, and `invalid`. The `sysdef` status indicates that a feature
45
+ is configured to use the system default, and it is the most common
46
+ status:
47
+
48
+ ``` ruby
49
+ #!/usr/bin/env ruby
50
+ # Required privileges: superuser
51
+ require "bsdcontrol"
52
+ BSD::Control
53
+ .feature(:mprotect)
54
+ .status("/bin/ls") # => :sysdef
55
+ ```
56
+
57
+ ## Documentation
58
+
59
+ A complete API reference is available at
60
+ [0x1eef.github.io/x/bsdcontrol.rb](https://0x1eef.github.io/x/bsdcontrol.rb).
61
+
62
+ ## Install
63
+
64
+ **Rubygems.org**
65
+
66
+ bsdcontrol.rb can be installed via rubygems.org:
67
+
68
+ gem install bsdcontrol.rb
69
+
70
+ ## Sources
71
+
72
+ * [GitHub](https://github.com/0x1eef/bsdcontrol.rb)
73
+ * [GitLab](https://gitlab.com/0x1eef/bsdcontrol.rb)
74
+ * [git.HardenedBSD.org](https://git.HardenedBSD.org/0x1eef/bsdcontrol.rb)
75
+
76
+ ## License
77
+
78
+ [BSD Zero Clause](https://choosealicense.com/licenses/0bsd/).
79
+ <br>
80
+ See [LICENSE](./LICENSE).
81
+
@@ -0,0 +1,24 @@
1
+ #include <ruby.h>
2
+ #include "context.h"
3
+ #include "feature.h"
4
+
5
+ void
6
+ Init_bsdcontrol(void)
7
+ {
8
+ VALUE rb_mBSD = rb_const_get(rb_cObject, rb_intern("BSD")),
9
+ rb_mControl = rb_const_get(rb_mBSD, rb_intern("Control")),
10
+ rb_cFeature = rb_const_get(rb_mControl, rb_intern("Feature")),
11
+ rb_cContext = rb_const_get(rb_mControl, rb_intern("Context"));
12
+ rb_define_alloc_func(rb_cContext, bsdcontrol_context_alloc);
13
+ rb_define_method(
14
+ rb_cContext, "library_version", bsdcontrol_context_library_version, 0);
15
+ rb_define_method(rb_cContext,
16
+ "available_features",
17
+ bsdcontrol_context_available_features,
18
+ 0);
19
+ rb_define_method(rb_cFeature, "status", bsdcontrol_feature_status, 1);
20
+ rb_define_method(rb_cFeature, "sysdef!", bsdcontrol_feature_sysdef, 1);
21
+ rb_define_private_method(rb_cFeature, "set!", bsdcontrol_feature_set, 2);
22
+ rb_define_const(rb_cFeature, "ENABLED", INT2NUM(HBSDCTRL_STATE_ENABLED));
23
+ rb_define_const(rb_cFeature, "DISABLED", INT2NUM(HBSDCTRL_STATE_DISABLED));
24
+ }
@@ -0,0 +1,64 @@
1
+ #include <ruby.h>
2
+ #include <libhbsdcontrol.h>
3
+ #include "context.h"
4
+ #include "glue.h"
5
+
6
+ static int FLAGS = HBSDCTRL_FEATURE_STATE_FLAG_NONE;
7
+ static const char *NAMESPACE = LIBHBSDCONTROL_DEFAULT_NAMESPACE;
8
+ static void bsdcontrol_context_free(hbsdctrl_ctx_t *);
9
+
10
+ VALUE
11
+ bsdcontrol_context_alloc(VALUE klass)
12
+ {
13
+ hbsdctrl_ctx_t *ctx;
14
+ ctx = hbsdctrl_ctx_new(FLAGS, NAMESPACE);
15
+ if (ctx == NULL)
16
+ {
17
+ rb_raise(rb_eSystemCallError, "hbsdctrl_ctx_new");
18
+ }
19
+ return Data_Wrap_Struct(klass, NULL, bsdcontrol_context_free, ctx);
20
+ }
21
+
22
+ static void
23
+ bsdcontrol_context_free(hbsdctrl_ctx_t *ctx)
24
+ {
25
+ hbsdctrl_ctx_free(&ctx);
26
+ }
27
+
28
+ /*
29
+ * BSD::Control::Context#available_features
30
+ * BSD::Control.available_features
31
+ * BSD::Control::Feature.available
32
+ */
33
+ VALUE
34
+ bsdcontrol_context_available_features(VALUE self)
35
+ {
36
+ VALUE rb_mBSD = rb_const_get(rb_cObject, rb_intern("BSD")),
37
+ rb_mControl = rb_const_get(rb_mBSD, rb_intern("Control")),
38
+ rb_cFeature = rb_const_get(rb_mControl, rb_intern("Feature")),
39
+ feature = 0, features = rb_ary_new();
40
+ hbsdctrl_ctx_t *ctx;
41
+ char **name;
42
+ ctx = bsdcontrol_unwrap(self);
43
+ name = hbsdctrl_ctx_all_feature_names(ctx);
44
+ while (*name != NULL)
45
+ {
46
+ feature = rb_funcall(
47
+ rb_cFeature, rb_intern("new"), 2, rb_str_new2(*name), self);
48
+ rb_ary_push(features, feature);
49
+ name++;
50
+ }
51
+ return features;
52
+ }
53
+
54
+ /*
55
+ * BSD::Control::Context#library_version
56
+ * BSD::Control.library_version
57
+ */
58
+ VALUE
59
+ bsdcontrol_context_library_version(VALUE self)
60
+ {
61
+ hbsdctrl_ctx_t *ctx;
62
+ ctx = bsdcontrol_unwrap(self);
63
+ return ULONG2NUM(ctx->hc_version);
64
+ }
@@ -0,0 +1,6 @@
1
+ #include <ruby.h>
2
+ #include <libhbsdcontrol.h>
3
+
4
+ VALUE bsdcontrol_context_alloc(VALUE);
5
+ VALUE bsdcontrol_context_library_version(VALUE);
6
+ VALUE bsdcontrol_context_available_features(VALUE);
@@ -0,0 +1,3 @@
1
+ require 'mkmf'
2
+ $LIBS << ' -lhbsdcontrol'
3
+ create_makefile("bsdcontrol.rb")
@@ -0,0 +1,96 @@
1
+ #include <ruby.h>
2
+ #include <libhbsdcontrol.h>
3
+ #include <fcntl.h>
4
+ #include <errno.h>
5
+ #include "feature.h"
6
+ #include "context.h"
7
+ #include "glue.h"
8
+
9
+ /*
10
+ * BSD::Control::Feature#status
11
+ */
12
+ VALUE
13
+ bsdcontrol_feature_status(VALUE self, VALUE path)
14
+ {
15
+ int fd;
16
+ VALUE rbcontext;
17
+ hbsdctrl_feature_t *feature;
18
+ hbsdctrl_feature_state_t state;
19
+ hbsdctrl_ctx_t *ctx;
20
+ rbcontext = rb_funcall(self, rb_intern("context"), 0);
21
+ fd = bsdcontrol_open(path);
22
+ ctx = bsdcontrol_unwrap(rbcontext);
23
+ feature = bsdcontrol_find_feature(ctx, self);
24
+ errno = 0;
25
+ if (feature->hf_get(ctx, feature, &fd, &state) == RES_FAIL)
26
+ {
27
+ close(fd);
28
+ errno == 0 ? rb_raise(rb_eSystemCallError, "hf_get")
29
+ : rb_syserr_fail(errno, "hf_get");
30
+ }
31
+ else
32
+ {
33
+ const char *str;
34
+ close(fd);
35
+ str = hbsdctrl_feature_state_to_string(&state);
36
+ return ID2SYM(rb_intern(str));
37
+ }
38
+ }
39
+
40
+ /*
41
+ * BSD::Control::Feature#set!
42
+ */
43
+ VALUE
44
+ bsdcontrol_feature_set(VALUE self, VALUE path, VALUE rbstate)
45
+ {
46
+ int fd;
47
+ VALUE rbcontext;
48
+ hbsdctrl_feature_t *feature;
49
+ hbsdctrl_ctx_t *ctx;
50
+ int state;
51
+ rbcontext = rb_funcall(self, rb_intern("context"), 0);
52
+ fd = bsdcontrol_open(path);
53
+ ctx = bsdcontrol_unwrap(rbcontext);
54
+ feature = bsdcontrol_find_feature(ctx, self);
55
+ state = NUM2INT(rbstate);
56
+ errno = 0;
57
+ if (feature->hf_apply(ctx, feature, &fd, &state) == RES_FAIL)
58
+ {
59
+ close(fd);
60
+ errno == 0 ? rb_raise(rb_eSystemCallError, "hf_apply")
61
+ : rb_syserr_fail(errno, "hf_apply");
62
+ }
63
+ else
64
+ {
65
+ close(fd);
66
+ return Qtrue;
67
+ }
68
+ }
69
+
70
+ /*
71
+ * BSD::Control::Feature#sysdef!
72
+ */
73
+ VALUE
74
+ bsdcontrol_feature_sysdef(VALUE self, VALUE path)
75
+ {
76
+ int fd;
77
+ VALUE rbcontext;
78
+ hbsdctrl_feature_t *feature;
79
+ hbsdctrl_ctx_t *ctx;
80
+ rbcontext = rb_funcall(self, rb_intern("context"), 0);
81
+ fd = bsdcontrol_open(path);
82
+ ctx = bsdcontrol_unwrap(rbcontext);
83
+ feature = bsdcontrol_find_feature(ctx, self);
84
+ errno = 0;
85
+ if (feature->hf_unapply(ctx, feature, &fd, NULL) == RES_FAIL)
86
+ {
87
+ close(fd);
88
+ errno == 0 ? rb_raise(rb_eSystemCallError, "hf_unapply")
89
+ : rb_syserr_fail(errno, "hf_unapply");
90
+ }
91
+ else
92
+ {
93
+ close(fd);
94
+ return Qtrue;
95
+ }
96
+ }
@@ -0,0 +1,4 @@
1
+ #include <ruby.h>
2
+ VALUE bsdcontrol_feature_status(VALUE, VALUE);
3
+ VALUE bsdcontrol_feature_set(VALUE,VALUE,VALUE);
4
+ VALUE bsdcontrol_feature_sysdef(VALUE, VALUE);
@@ -0,0 +1,35 @@
1
+ #include <ruby.h>
2
+ #include <libhbsdcontrol.h>
3
+ #include <fcntl.h>
4
+ #include "glue.h"
5
+ #include "context.h"
6
+
7
+ int
8
+ bsdcontrol_open(VALUE path)
9
+ {
10
+ int fd;
11
+ Check_Type(path, T_STRING);
12
+ fd = open(RSTRING_PTR(path), O_PATH);
13
+ if (fd == -1)
14
+ {
15
+ rb_syserr_fail(errno, "open");
16
+ }
17
+ return fd;
18
+ }
19
+
20
+ hbsdctrl_ctx_t *
21
+ bsdcontrol_unwrap(VALUE rbcontext)
22
+ {
23
+ hbsdctrl_ctx_t *ctx;
24
+ Data_Get_Struct(rbcontext, hbsdctrl_ctx_t, ctx);
25
+ return ctx;
26
+ }
27
+
28
+ hbsdctrl_feature_t *
29
+ bsdcontrol_find_feature(hbsdctrl_ctx_t *ctx, VALUE rbfeature)
30
+ {
31
+ VALUE name;
32
+ name = rb_funcall(rbfeature, rb_intern("name"), 0);
33
+ Check_Type(name, T_STRING);
34
+ return hbsdctrl_ctx_find_feature_by_name(ctx, RSTRING_PTR(name));
35
+ }
@@ -0,0 +1,7 @@
1
+ #pragma once
2
+ #include <ruby.h>
3
+ #include <libhbsdcontrol.h>
4
+
5
+ int bsdcontrol_open(VALUE);
6
+ hbsdctrl_ctx_t* bsdcontrol_unwrap(VALUE);
7
+ hbsdctrl_feature_t* bsdcontrol_find_feature(hbsdctrl_ctx_t*, VALUE);
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BSD::Control
4
+ ##
5
+ # The {BSD::Control::Context BSD::Control::Context} class encapsulates
6
+ # and persists a clang data structure (hbsdctrl_ctx_t).
7
+ class Context
8
+ end
9
+ end
@@ -0,0 +1,187 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BSD::Control
4
+ class Feature < Struct.new(:name, :context)
5
+ ##
6
+ # @return [Array<BSD::Control::Feature>]
7
+ # Returns an array of available features
8
+ def self.available
9
+ BSD::Control.available_features
10
+ end
11
+
12
+ ##
13
+ # @group Actions
14
+
15
+ ##
16
+ # Enables a feature for a given file
17
+ #
18
+ # @param [String] path
19
+ # The path to a file
20
+ #
21
+ # @raise [SystemCallError]
22
+ # Might raise a number of Errno exceptions
23
+ #
24
+ # @return [Boolean]
25
+ # Returns true on success
26
+ def enable!(path)
27
+ set!(path, ENABLED)
28
+ end
29
+
30
+ ##
31
+ # Disables a feature for a given file
32
+ #
33
+ # @param [String] path
34
+ # The path to a file
35
+ #
36
+ # @raise [SystemCallError]
37
+ # Might raise a number of Errno exceptions
38
+ #
39
+ # @return [Boolean]
40
+ # Returns true on success
41
+ def disable!(path)
42
+ set!(path, DISABLED)
43
+ end
44
+
45
+ ##
46
+ # @!method sysdef!(path)
47
+ # Restores the system default for a given file
48
+ #
49
+ # @param [String] path
50
+ # The path to a file
51
+ #
52
+ # @raise [SystemCallError]
53
+ # Might raise a number of Errno exceptions
54
+ #
55
+ # @return [Boolean]
56
+ # Returns true on success
57
+
58
+ # @endgroup
59
+
60
+ ##
61
+ # @group Queries
62
+
63
+ ##
64
+ # @param [String] path
65
+ # The path to a file
66
+ #
67
+ # @return [Boolean]
68
+ # Returns true when a feature is enabled
69
+ def enabled?(path)
70
+ status(path) == :enabled
71
+ end
72
+
73
+ ##
74
+ # @param [String] path
75
+ # The path to a file.
76
+ #
77
+ # @return [Boolean]
78
+ # Returns true when a feature is disabled
79
+ def disabled?(path)
80
+ status(path) == :disabled
81
+ end
82
+
83
+ ##
84
+ # @param [String] path
85
+ # The path to a file
86
+ #
87
+ # @return [Boolean]
88
+ # Returns true when the system default setting is used
89
+ def sysdef?(path)
90
+ status(path) == :sysdef
91
+ end
92
+
93
+ ##
94
+ # @param [String] path
95
+ # The path to a file
96
+ #
97
+ # @return [Boolean]
98
+ # Returns true when a feature is in an invalid state
99
+ # (eg: the feature is both enabled and disabled at the same time)
100
+ def invalid?(path)
101
+ status(path) == :invalid
102
+ end
103
+
104
+ ##
105
+ # @!method status(path)
106
+ # @param [String] path
107
+ # The path to a file
108
+ #
109
+ # @raise [SystemCallError]
110
+ # Might raise a number of Errno exceptions
111
+ #
112
+ # @return [Symbol]
113
+ # Returns the status of a feature for a given file.
114
+ # Status could be: `:unknown`, `:enabled`, `:disabled`,
115
+ # `:sysdef`, or `:invalid`.
116
+
117
+ # @endgroup
118
+
119
+ ##
120
+ # @group Predicates
121
+
122
+ ##
123
+ # @return [Boolean]
124
+ # Returns true for `pageexec`
125
+ def pageexec?
126
+ name == "pageexec"
127
+ end
128
+
129
+ ##
130
+ # @return [Boolean]
131
+ # Returns true for `mprotect`
132
+ def mprotect?
133
+ name == "mprotect"
134
+ end
135
+
136
+ ##
137
+ # @return [Boolean]
138
+ # Returns true for `segvguard`
139
+ def segvguard?
140
+ name == "segvguard"
141
+ end
142
+
143
+ ##
144
+ # @return [Boolean]
145
+ # Returns true for `aslr`
146
+ def aslr?
147
+ name == "aslr"
148
+ end
149
+
150
+ ##
151
+ # @return [Boolean]
152
+ # Returns true for `shlibrandom`
153
+ def shlibrandom?
154
+ name == "shlibrandom"
155
+ end
156
+
157
+ ##
158
+ # @return [Boolean]
159
+ # Returns true for `disallow_map32bit`
160
+ def disallow_map32bit?
161
+ name == "disallow_map32bit"
162
+ end
163
+
164
+ ##
165
+ # @return [Boolean]
166
+ # Returns true for `insecure_kmod`
167
+ def insecure_kmod?
168
+ name == "insecure_kmod"
169
+ end
170
+
171
+ ##
172
+ # @return [Boolean]
173
+ # Returns true for `harden_shm`
174
+ def harden_shm?
175
+ name == "harden_shm"
176
+ end
177
+
178
+ ##
179
+ # @return [Boolean]
180
+ # Returns true for `prohibit_ptrace_capsicum`
181
+ def prohibit_ptrace_capsicum?
182
+ name == "prohibit_ptrace_capsicum"
183
+ end
184
+
185
+ # @endgroup
186
+ end
187
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BSD
4
+ module Control
5
+ VERSION = "0.2.0"
6
+ end
7
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BSD
4
+ end unless defined?(BSD)
5
+
6
+ module BSD::Control
7
+ Error = Class.new(RuntimeError)
8
+
9
+ ##
10
+ # @return [BSD::Control::Context]
11
+ # Returns an instance of {BSD::Control::Context BSD::Control::Context}
12
+ def self.context
13
+ @context ||= BSD::Control::Context.new
14
+ end
15
+
16
+ ##
17
+ # @return [String]
18
+ # Returns the version of libhbsdcontrol
19
+ def self.library_version
20
+ context.library_version
21
+ end
22
+
23
+ ##
24
+ # @return [Array<BSD::Control::Feature>]
25
+ # Returns an array of available features
26
+ def self.available_features
27
+ context.available_features
28
+ end
29
+
30
+ ##
31
+ # @example
32
+ # BSD::Control
33
+ # .feature(:mprotect)
34
+ # .enable!("/usr/local/bin/emacs-29.2")
35
+ #
36
+ # @param [String] name
37
+ # The name of a feature
38
+ #
39
+ # @raise [BSD::Control::Error]
40
+ # When a feature wasn't found
41
+ #
42
+ # @return [BSD::Control::Feature]
43
+ # Returns an instance of {BSD::Control::Feature BSD::Control::Feature}
44
+ def self.feature(name)
45
+ feature = available_features.find { _1.name == name.to_s }
46
+ feature || raise(Error, "'#{name}' wasn't found")
47
+ end
48
+
49
+ require_relative "control/context"
50
+ require_relative "control/feature"
51
+ require_relative "../bsdcontrol.rb.so"
52
+ end
data/lib/bsdcontrol.rb ADDED
@@ -0,0 +1,2 @@
1
+ # frozen_string_literal: true
2
+ require_relative "bsd/control"
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Required privileges: user, superuser
5
+ require "bsdcontrol"
6
+ BSD::Control
7
+ .available_features
8
+ .each do
9
+ print "The ", _1.name, " feature is available", "\n"
10
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bsdcontrol.rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - '0x1eef'
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-05-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake-compiler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.2'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: standard
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.35'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.35'
41
+ - !ruby/object:Gem::Dependency
42
+ name: test-cmd.rb
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.8'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.8'
55
+ - !ruby/object:Gem::Dependency
56
+ name: test-unit
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.6'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.6'
69
+ description: Ruby bindings for libhbsdcontrol
70
+ email:
71
+ - 0x1eef@protonmail.com
72
+ executables: []
73
+ extensions:
74
+ - ext/bsdcontrol.rb/extconf.rb
75
+ extra_rdoc_files: []
76
+ files:
77
+ - "./ext/bsdcontrol.rb/bsdcontrol.c"
78
+ - "./ext/bsdcontrol.rb/context.c"
79
+ - "./ext/bsdcontrol.rb/context.h"
80
+ - "./ext/bsdcontrol.rb/extconf.rb"
81
+ - "./ext/bsdcontrol.rb/feature.c"
82
+ - "./ext/bsdcontrol.rb/feature.h"
83
+ - "./ext/bsdcontrol.rb/glue.c"
84
+ - "./ext/bsdcontrol.rb/glue.h"
85
+ - "./lib/bsd/control.rb"
86
+ - "./lib/bsd/control/context.rb"
87
+ - "./lib/bsd/control/feature.rb"
88
+ - "./lib/bsd/control/version.rb"
89
+ - "./lib/bsdcontrol.rb"
90
+ - "./share/bsdcontrol.rb/examples/1_available_features.rb"
91
+ - LICENSE
92
+ - README.md
93
+ - ext/bsdcontrol.rb/extconf.rb
94
+ homepage: https://git.hardenedbsd.org/0x1eef/bsdcontrol.rb#readme
95
+ licenses:
96
+ - 0BSD
97
+ metadata: {}
98
+ post_install_message:
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ requirements: []
113
+ rubygems_version: 3.5.9
114
+ signing_key:
115
+ specification_version: 4
116
+ summary: Ruby bindings for libhbsdcontrol
117
+ test_files: []