ardecy 0.0.2 → 0.0.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dfee812e31a5a1dc6f31eaa70fb6837459732157ef174fd215eb215ea299f0c7
4
- data.tar.gz: 5933831912f0b6770be89ba4bf9821aa12503600ca9e4e23d90df35837d453d6
3
+ metadata.gz: 4c8c6a3f88a5c4b22a77af705bc9e05c4b384d71c5b9b05de8d8437d6d58faf8
4
+ data.tar.gz: 698148322c56fadf979171e1bcc4f79fdc148ef0da01153e0b8605e9ba87c32b
5
5
  SHA512:
6
- metadata.gz: 3d2145fe504aa730c778092360531ec37da9e72c12e7c1edfcf66f8a459dd7b02188defe1fa3572c1931e7422bad12bdba19ca124f7164025c336c4c340c7f2f
7
- data.tar.gz: 9032e9a78441de631fb46bd03ad47fb3770815f229a8c2b2200e161bb12581f95f49e623e7a6d7ef2e69bdd0b18f7034c116f8f9b92b9a58fcc2b9cf51a27637
6
+ metadata.gz: 82bd529f6a10201ac3440836f04c98a533db3537238f172387a14d94df59cf632e1794dd36a301a3baeacaaf99e304e5165c9de39bec3df60c54f78a780247f1
7
+ data.tar.gz: 2f7bf24bfc3923eda049c5fb58d921696b03cccdaa37f11291e1f37e0eff7fc1fafa1c65ecda1d53ddc7c9a5267b354265682af0e6af48454e3c2c7a476a1ab4
checksums.yaml.gz.sig CHANGED
Binary file
data.tar.gz.sig CHANGED
Binary file
data/README.md CHANGED
@@ -2,8 +2,12 @@
2
2
 
3
3
  <div align="center">
4
4
  <br/>
5
- [![Ruby Style Guide](https://img.shields.io/badge/code_style-rubocop-brightgreen.svg)](https://github.com/rubocop/rubocop)
5
+
6
6
  [![Gem Version](https://badge.fury.io/rb/ardecy.svg)](https://badge.fury.io/rb/ardecy)
7
+ ![GitHub Workflow Status (branch)](https://img.shields.io/github/workflow/status/szorfein/ardecy/Rubocop/main)
8
+ [![Ruby Style Guide](https://img.shields.io/badge/code_style-rubocop-brightgreen.svg)](https://github.com/rubocop/rubocop)
9
+ ![GitHub](https://img.shields.io/github/license/szorfein/ardecy)
10
+
7
11
  </div>
8
12
 
9
13
  Ardecy is a security, privacy auditing, fixing and hardening tool for Linux.
@@ -13,7 +17,7 @@ Ardecy is a security, privacy auditing, fixing and hardening tool for Linux.
13
17
  With gem:
14
18
 
15
19
  gem cert --add <(curl -Ls https://raw.githubusercontent.com/szorfein/ardecy/master/certs/szorfein.pem)
16
- gem install ardecy-0.0.1.gem -P HighSecurity
20
+ gem install ardecy -P HighSecurity
17
21
  ardecy -h
18
22
 
19
23
  With github:
data/lib/ardecy.rb CHANGED
@@ -15,10 +15,11 @@ module Ardecy
15
15
  end
16
16
 
17
17
  def scan
18
- Harden.sysctl({
19
- audit: @cli[:audit],
20
- fix: @cli[:fix]
21
- })
18
+ Harden.sysctl(@cli)
19
+ Harden.modules(@cli)
20
+ Harden.permissions(@cli)
21
+ Harden.mountpoint(@cli)
22
+ Harden.cmdline(@cli)
22
23
  end
23
24
 
24
25
  def bye
data/lib/ardecy/harden.rb CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  require 'display'
4
4
  require_relative 'harden/sysctl'
5
+ require_relative 'harden/modules'
6
+ require_relative 'harden/perms'
7
+ require_relative 'harden/mountpoint'
8
+ require_relative 'harden/cmdline'
5
9
 
6
10
  module Ardecy
7
11
  module Harden
@@ -13,39 +17,59 @@ module Ardecy
13
17
  sysctl_network(args)
14
18
  end
15
19
 
16
- def self.sysctl_kernel(args)
17
- title 'Kernel Hardening'
20
+ def self.modules(args)
21
+ puts
22
+ title 'Kernel Modules'
23
+ Modules::Blacklist.exec(args)
24
+ return unless args[:fix]
25
+
26
+ if Dir.exist? '/etc/modprobe.d/'
27
+ conf = '/etc/modprobe.d/ardecy_blacklist.conf'
28
+ writing(conf, Modules::BLACKLIST, args[:audit])
29
+ else
30
+ puts "[-] Directory /etc/modprobe.d/ no found..."
31
+ end
32
+ end
18
33
 
19
- Sysctl::Kernel::KPointer.new(args).x
20
- Sysctl::Kernel::Dmesg.new(args).x
21
- Sysctl::Kernel::Printk.new(args).x
22
- Sysctl::Kernel::BpfDisabled.new(args).x
23
- Sysctl::Kernel::BpfJitHarden.new(args).x
24
- Sysctl::Kernel::LdiskAutoload.new(args).x
25
- Sysctl::Kernel::UserFaultFd.new(args).x
26
- Sysctl::Kernel::KExecLoadDisabled.new(args).x
27
- Sysctl::Kernel::SysRQ.new(args).x
28
- Sysctl::Kernel::UsernsClone.new(args).x
29
- Sysctl::Kernel::MaxUserNameSpace.new(args).x
30
- Sysctl::Kernel::PerfEventParanoid.new(args).x
31
- Sysctl::Kernel::YamaPtrace.new(args).x
32
- Sysctl::Kernel::VmMmapRndBits.new(args).x
33
- Sysctl::Kernel::VmMmapRndCompatBits.new(args).x
34
- Sysctl::Kernel::FsProtectedSymlinks.new(args).x
35
- Sysctl::Kernel::FsProtectedHardlinks.new(args).x
36
- Sysctl::Kernel::FsProtectedFifos.new(args).x
37
- Sysctl::Kernel::FsProtectedRegular.new(args).x
34
+ def self.permissions(args)
35
+ puts
36
+ title 'Directory Permissions'
37
+ Perms::Directory.exec(args)
38
+ end
38
39
 
39
- return unless args[:fix]
40
+ def self.mountpoint(args)
41
+ puts
42
+ title 'Mountpoint'
43
+ Mountpoint.exec(args)
44
+ end
40
45
 
41
- conf = '/etc/sysctl.d/ardecy_kernel.conf'
42
- puts if args[:audit]
43
- puts " ===> Applying at #{conf}..."
46
+ def self.cmdline(args)
44
47
  puts
45
- kernel_correct_show Sysctl::KERNEL
46
- Sysctl::KERNEL << "\n"
48
+ title 'Kernel Cmdline'
49
+ CmdLine.exec(args)
50
+ end
51
+
52
+ def self.writing(file, list, audit = false)
53
+ return unless list.length >= 1
54
+
55
+ puts if audit
56
+ puts " ===> Applying at #{file}..."
57
+ display_fix_list list
58
+
59
+ list << "\n"
60
+ list_f = list.freeze
61
+
62
+ File.write(file, list_f.join("\n"), mode: 'w', chmod: 644)
63
+ end
64
+
65
+ def self.sysctl_kernel(args)
66
+ title 'Kernel Hardening'
67
+ Sysctl::Kernel.exec(args)
68
+ return unless args[:fix]
69
+
47
70
  if Dir.exist? '/etc/sysctl.d/'
48
- File.write(conf, Sysctl::KERNEL.join("\n"), mode: 'w', chmod: 0644)
71
+ conf = '/etc/sysctl.d/ardecy_kernel.conf'
72
+ writing(conf, Sysctl::KERNEL, args[:audit])
49
73
  else
50
74
  puts '[-] Directory /etc/sysctl.d/ no found.'
51
75
  end
@@ -53,40 +77,12 @@ module Ardecy
53
77
 
54
78
  def self.sysctl_network(args)
55
79
  title 'Network Hardening'
56
-
57
- Sysctl::Network::TcpSynCookie.new(args).x
58
- Sysctl::Network::RFC1337.new(args).x
59
- Sysctl::Network::AllRpFilter.new(args).x
60
- Sysctl::Network::DefaultRpFilter.new(args).x
61
- Sysctl::Network::AllAcceptRedirects.new(args).x
62
- Sysctl::Network::DefaultAcceptRedirects.new(args).x
63
- Sysctl::Network::AllSecureRedirects.new(args).x
64
- Sysctl::Network::DefaultSecureRedirects.new(args).x
65
- Sysctl::Network::Ipv6AllAcceptRedirects.new(args).x
66
- Sysctl::Network::Ipv6DefaultAcceptRedirects.new(args).x
67
- Sysctl::Network::AllSendRedirects.new(args).x
68
- Sysctl::Network::DefaultSendRedirects.new(args).x
69
- Sysctl::Network::IcmpEchoIgnoreAll.new(args).x
70
- Sysctl::Network::AllAcceptSourceRoute.new(args).x
71
- Sysctl::Network::DefaultAcceptSourceRoute.new(args).x
72
- Sysctl::Network::Ipv6AllAcceptSourceRoute.new(args).x
73
- Sysctl::Network::Ipv6DefaultAcceptSourceRoute.new(args).x
74
- Sysctl::Network::Ipv6ConfAllAcceptRa.new(args).x
75
- Sysctl::Network::Ipv6ConfDefaultAcceptRa.new(args).x
76
- Sysctl::Network::TcpSack.new(args).x
77
- Sysctl::Network::TcpDSack.new(args).x
78
- Sysctl::Network::TcpFack.new(args).x
79
-
80
+ Sysctl::Network.exec(args)
80
81
  return unless args[:fix]
81
82
 
82
- conf = '/etc/sysctl.d/ardecy_network.conf'
83
- puts if args[:audit]
84
- puts " ===> Applying at #{conf}..."
85
- puts
86
- kernel_correct_show Sysctl::NETWORK
87
- Sysctl::NETWORK << "\n"
88
83
  if Dir.exist? '/etc/sysctl.d/'
89
- File.write(conf, Sysctl::NETWORK.join("\n"), mode: 'w', chmod: 0644)
84
+ conf = '/etc/sysctl.d/ardecy_network.conf'
85
+ writing(conf, Sysctl::NETWORK, args[:audit])
90
86
  else
91
87
  puts '[-] Directory /etc/sysctl.d/ no found.'
92
88
  end
@@ -0,0 +1,222 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'display'
4
+ require 'nito'
5
+
6
+ module Ardecy
7
+ module Harden
8
+ module CmdLine
9
+ def self.exec(args)
10
+ SlabNoMerge.new(args).x
11
+ SlubDebug.new(args).x
12
+ InitOnAlloc.new(args).x
13
+ InitOnFree.new(args).x
14
+ PageAllocShuffle.new(args).x
15
+ PtiOn.new(args).x
16
+ VSyscall.new(args).x
17
+ DebugFS.new(args).x
18
+ ModuleSig.new(args).x
19
+ LockdownConfident.new(args).x
20
+ Quiet.new(args).x
21
+ LogLevel.new(args).x
22
+ end
23
+
24
+ class LineInc
25
+ include Display
26
+ include NiTo
27
+
28
+ def initialize(args)
29
+ @name = 'pti=on'
30
+ @res = 'FAIL'
31
+ @tab = 4
32
+ @args = args
33
+ end
34
+
35
+ def x
36
+ scan
37
+ fix
38
+ end
39
+
40
+ def scan
41
+ curr_line = File.readlines('/proc/cmdline')
42
+ curr_line.each { |l| @res = 'OK' if l =~ /#{@name}/ }
43
+ print " - include #{@name}" if @args[:audit]
44
+ @tab ? result(@res, @tab) : result(@res) if @args[:audit]
45
+ end
46
+
47
+ def fix
48
+ return unless @args[:fix]
49
+ return if @res =~ /OK/
50
+
51
+ if File.exist? '/etc/default/grub'
52
+ apply_grub '/etc/default/grub'
53
+ elsif @args[:syslinux]
54
+ apply_syslinux @args[:syslinux]
55
+ elsif File.exist? '/boot/syslinux/syslinux.cfg'
56
+ apply_syslinux '/boot/syslinux/syslinux.cfg'
57
+ elsif @args[:bootctl]
58
+ apply_bootctl @args[:bootctl]
59
+ else
60
+ puts
61
+ puts "[-] No config file supported yet to applying #{@name}."
62
+ end
63
+ end
64
+
65
+ # conf path can be something like:
66
+ # /efi/loader/entries/gentoo.conf
67
+ def apply_bootctl(conf)
68
+ line = get_bootctl_line(conf)
69
+ args = []
70
+ line.split(' ').each { |a| args << a if a =~ /[a-z0-9=]+/ }
71
+ args << @name
72
+ args = args.uniq()
73
+ args.delete('options')
74
+ @final_line = 'options ' + args.join(' ')
75
+ print " ===> Adding #{@name} \n\n"
76
+ sed(/^options/, "#{@final_line}", conf)
77
+ end
78
+
79
+ def get_bootctl_line(conf)
80
+ File.readlines(conf).each { |l| return l if l =~ /^options/ }
81
+ 'options'
82
+ end
83
+
84
+ def apply_syslinux(conf)
85
+ line = get_syslinux_line(conf)
86
+ args = []
87
+ line.split(' ').each { |a| args << a if a =~ /[a-z0-9=]+/ }
88
+ args << @name
89
+ args = args.uniq()
90
+ @final_line = 'APPEND ' + args.join(' ')
91
+ print " ===> Adding #{@name} \n\n"
92
+ sed(/\s+APPEND/, " #{@final_line}", conf) # with 4 spaces
93
+ end
94
+
95
+ # apply_grub
96
+ # Get all the current arguments from config file
97
+ # And reinject them with new @name
98
+ # Build the variable @final_line
99
+ def apply_grub(conf)
100
+ line = get_grub_line(conf)
101
+ args = []
102
+
103
+ line_split = line.split("GRUB_CMDLINE_LINUX_DEFAULT=\"")
104
+ args_split = line_split[1].split(' ')
105
+ args_split.each { |a| args << a.tr('"', '') if a =~ /[a-z0-9=]+/ }
106
+ args << @name
107
+ args = args.uniq()
108
+
109
+ @final_line = "GRUB_CMDLINE_LINUX_DEFAULT=\"" + args.join(' ') + "\""
110
+ print " ===> Adding #{@name} \n\n"
111
+ write_to_grub(conf)
112
+ end
113
+
114
+ def write_to_grub(conf)
115
+ sed(/^GRUB_CMDLINE_LINUX_DEFAULT/, @final_line, conf)
116
+ end
117
+
118
+ def get_grub_line(conf)
119
+ File.readlines(conf).each { |l| return l if l =~ /^GRUB_CMDLINE_LINUX_DEFAULT/ }
120
+ "GRUB_CMDLINE_LINUX_DEFAULT=\"\""
121
+ end
122
+
123
+ def get_syslinux_line(conf)
124
+ File.readlines(conf).each { |l| return l if l =~ /\s+APPEND/ }
125
+ 'APPEND'
126
+ end
127
+ end
128
+
129
+ class SlabNoMerge < CmdLine::LineInc
130
+ def initialize(args)
131
+ super
132
+ @name = 'slab_nomerge'
133
+ end
134
+ end
135
+
136
+ class SlubDebug < CmdLine::LineInc
137
+ def initialize(args)
138
+ super
139
+ @name = 'slub_debug=ZF'
140
+ end
141
+ end
142
+
143
+ class InitOnAlloc < CmdLine::LineInc
144
+ def initialize(args)
145
+ super
146
+ @name = 'init_on_alloc=1'
147
+ end
148
+ end
149
+
150
+ class InitOnFree < CmdLine::LineInc
151
+ def initialize(args)
152
+ super
153
+ @name = 'init_on_free=1'
154
+ end
155
+ end
156
+
157
+ class PageAllocShuffle < CmdLine::LineInc
158
+ def initialize(args)
159
+ super
160
+ @name = 'page_alloc.shuffle=1'
161
+ @tab = 3
162
+ end
163
+ end
164
+
165
+ class PtiOn < CmdLine::LineInc
166
+ def initialize(args)
167
+ super
168
+ @name = 'pti=on'
169
+ @tab = 5
170
+ end
171
+ end
172
+
173
+ class VSyscall < CmdLine::LineInc
174
+ def initialize(args)
175
+ super
176
+ @name = 'vsyscall=none'
177
+ @tab = 4
178
+ end
179
+ end
180
+
181
+ class DebugFS < CmdLine::LineInc
182
+ def initialize(args)
183
+ super
184
+ @name = 'debugfs=off'
185
+ @tab = 5
186
+ end
187
+ end
188
+
189
+ class ModuleSig < CmdLine::LineInc
190
+ def initialize(args)
191
+ super
192
+ @name = 'module.sig_enforce=1'
193
+ @tab = 3
194
+ end
195
+ end
196
+
197
+ class LockdownConfident < CmdLine::LineInc
198
+ def initialize(args)
199
+ super
200
+ @name = 'lockdown=confidentiality'
201
+ @tab = 3
202
+ end
203
+ end
204
+
205
+ class Quiet < CmdLine::LineInc
206
+ def initialize(args)
207
+ super
208
+ @name = 'quiet'
209
+ @tab = 5
210
+ end
211
+ end
212
+
213
+ class LogLevel < CmdLine::LineInc
214
+ def initialize(args)
215
+ super
216
+ @name = 'loglevel=0'
217
+ @tab = 5
218
+ end
219
+ end
220
+ end
221
+ end
222
+ end
@@ -0,0 +1,290 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'display'
4
+
5
+ module Ardecy
6
+ module Harden
7
+ module Modules
8
+ BLACKLIST = []
9
+
10
+ class Drop
11
+ include Display
12
+
13
+ def initialize(args)
14
+ @res = 'OK'
15
+ @args = args
16
+ end
17
+
18
+ def quit_unless_modules
19
+ unless File.exist? '/proc/modules'
20
+ warn '/proc/modules no found'
21
+ exit 1
22
+ end
23
+ end
24
+
25
+ def research_found
26
+ quit_unless_modules
27
+
28
+ File.readlines('/proc/modules').each do |l|
29
+ return true if l =~ /^#{@name}/
30
+ end
31
+ false
32
+ end
33
+
34
+ def x
35
+ @res = 'FAIL' if research_found
36
+ if @args[:audit]
37
+ show_bad_mod(@name)
38
+ @tab ? result(@res, @tab) : result(@res)
39
+ end
40
+ fix
41
+ end
42
+
43
+ def fix
44
+ return if @res =~ /OK/
45
+
46
+ BLACKLIST << "install #{@name} /bin/false"
47
+ end
48
+ end
49
+
50
+ module Blacklist
51
+ def self.exec(args)
52
+ Blacklist::Dccp.new(args).x
53
+ Blacklist::Sctp.new(args).x
54
+ Blacklist::Rds.new(args).x
55
+ Blacklist::Tipc.new(args).x
56
+ Blacklist::NHdlc.new(args).x
57
+ Blacklist::Ax25.new(args).x
58
+ Blacklist::Netrom.new(args).x
59
+ Blacklist::X25.new(args).x
60
+ Blacklist::Rose.new(args).x
61
+ Blacklist::Decnet.new(args).x
62
+ Blacklist::Econet.new(args).x
63
+ Blacklist::Af802154.new(args).x
64
+ Blacklist::Ipx.new(args).x
65
+ Blacklist::Appletalk.new(args).x
66
+ Blacklist::Psnap.new(args).x
67
+ Blacklist::P8023.new(args).x
68
+ Blacklist::P8022.new(args).x
69
+ Blacklist::Can.new(args).x
70
+ Blacklist::Atm.new(args).x
71
+
72
+ # Filesystem
73
+ Blacklist::CramFs.new(args).x
74
+ Blacklist::FreevxFs.new(args).x
75
+ Blacklist::Jffs2.new(args).x
76
+ Blacklist::HFs.new(args).x
77
+ Blacklist::HFsplus.new(args).x
78
+ Blacklist::SquashFs.new(args).x
79
+ Blacklist::Udf.new(args).x
80
+
81
+ Blacklist::Vivid.new(args).x
82
+ Blacklist::UvcVideo.new(args).x
83
+ end
84
+
85
+ class Dccp < Modules::Drop
86
+ def initialize(args)
87
+ @name = 'dccp'
88
+ super
89
+ end
90
+ end
91
+
92
+ class Sctp < Modules::Drop
93
+ def initialize(args)
94
+ @name = 'sctp'
95
+ super
96
+ end
97
+ end
98
+
99
+ class Rds < Modules::Drop
100
+ def initialize(args)
101
+ @name = 'rds'
102
+ super
103
+ end
104
+ end
105
+
106
+ class Tipc < Modules::Drop
107
+ def initialize(args)
108
+ @name = 'tipc'
109
+ super
110
+ end
111
+ end
112
+
113
+ class NHdlc < Modules::Drop
114
+ def initialize(args)
115
+ @name = 'n-hdlc'
116
+ super
117
+ end
118
+ end
119
+
120
+ class Ax25 < Modules::Drop
121
+ def initialize(args)
122
+ @name = 'ax25'
123
+ super
124
+ end
125
+ end
126
+
127
+ class Netrom < Modules::Drop
128
+ def initialize(args)
129
+ @name = 'netrom'
130
+ super
131
+ end
132
+ end
133
+
134
+ class X25 < Modules::Drop
135
+ def initialize(args)
136
+ @name = 'x25'
137
+ super
138
+ end
139
+ end
140
+
141
+ class Rose < Modules::Drop
142
+ def initialize(args)
143
+ @name = 'rose'
144
+ super
145
+ end
146
+ end
147
+
148
+ class Decnet < Modules::Drop
149
+ def initialize(args)
150
+ @name = 'decnet'
151
+ super
152
+ end
153
+ end
154
+
155
+ class Econet < Modules::Drop
156
+ def initialize(args)
157
+ @name = 'econet'
158
+ super
159
+ end
160
+ end
161
+
162
+ class Af802154 < Modules::Drop
163
+ def initialize(args)
164
+ @name = 'af_802154'
165
+ @tab = 2
166
+ super
167
+ end
168
+ end
169
+
170
+ class Ipx < Modules::Drop
171
+ def initialize(args)
172
+ @name = 'ipx'
173
+ super
174
+ end
175
+ end
176
+
177
+ class Appletalk < Modules::Drop
178
+ def initialize(args)
179
+ @name = 'appletalk'
180
+ @tab = 2
181
+ super
182
+ end
183
+ end
184
+
185
+ class Psnap < Modules::Drop
186
+ def initialize(args)
187
+ @name = 'psnap'
188
+ super
189
+ end
190
+ end
191
+
192
+ class P8023 < Modules::Drop
193
+ def initialize(args)
194
+ @name = 'p8023'
195
+ super
196
+ end
197
+ end
198
+
199
+ class P8022 < Modules::Drop
200
+ def initialize(args)
201
+ @name = 'p8022'
202
+ super
203
+ end
204
+ end
205
+
206
+ class Can < Modules::Drop
207
+ def initialize(args)
208
+ @name = 'can'
209
+ super
210
+ end
211
+ end
212
+
213
+ class Atm < Modules::Drop
214
+ def initialize(args)
215
+ @name = 'atm'
216
+ super
217
+ end
218
+ end
219
+
220
+ class CramFs < Modules::Drop
221
+ def initialize(args)
222
+ @name = 'cramfs'
223
+ super
224
+ end
225
+ end
226
+
227
+ class FreevxFs < Modules::Drop
228
+ def initialize(args)
229
+ @name = 'freevxfs'
230
+ @tab = 2
231
+ super
232
+ end
233
+ end
234
+
235
+ class Jffs2 < Modules::Drop
236
+ def initialize(args)
237
+ @name = 'jffs2'
238
+ super
239
+ end
240
+ end
241
+
242
+ class HFs < Modules::Drop
243
+ def initialize(args)
244
+ @name = 'hfs'
245
+ super
246
+ end
247
+ end
248
+
249
+ class HFsplus < Modules::Drop
250
+ def initialize(args)
251
+ @name = 'hfsplus'
252
+ @tab = 2
253
+ super
254
+ end
255
+ end
256
+
257
+ class SquashFs < Modules::Drop
258
+ def initialize(args)
259
+ @name = 'spuashfs'
260
+ @tab = 2
261
+ super
262
+ end
263
+ end
264
+
265
+ class Udf < Modules::Drop
266
+ def initialize(args)
267
+ @name = 'udf'
268
+ super
269
+ end
270
+ end
271
+
272
+ class Vivid < Modules::Drop
273
+ def initialize(args)
274
+ @name = 'vivid'
275
+ super
276
+ end
277
+ end
278
+
279
+ # Webcam
280
+ class UvcVideo < Modules::Drop
281
+ def initialize(args)
282
+ @name = 'uvcvideo'
283
+ @tab = 2
284
+ super
285
+ end
286
+ end
287
+ end
288
+ end
289
+ end
290
+ end