ardecy 0.0.2 → 0.0.3

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