-
Notifications
You must be signed in to change notification settings - Fork 44
/
security_settings.rb
272 lines (230 loc) · 8.12 KB
/
security_settings.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
# Copyright (c) [2017-2021] SUSE LLC
#
# All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of version 2 of the GNU General Public License as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, contact SUSE LLC.
#
# To contact SUSE LLC about this file by physical or electronic mail, you may
# find current contact information at www.suse.com.
require "yast"
require "y2users"
require "y2security/lsm"
module Installation
# Class that stores the security proposal settings during installation.
class SecuritySettings
include Yast::Logger
include Yast::I18n
# [Boolean] Whether the firewalld service will be enable
attr_accessor :enable_firewall
# [Boolean] Whether the sshd service will be enable
attr_accessor :enable_sshd
# [Boolean] Whether the ssh port will be opened
attr_accessor :open_ssh
# [Boolean] Whether the vnc port will be opened
attr_accessor :open_vnc
# [String] Name of the default zone where perform the changes
attr_accessor :default_zone
# [String, nil] Setting for policy kit default privileges
# For more info see /etc/sysconfig/security#POLKIT_DEFAULT_PRIVS
attr_accessor :polkit_default_privileges
# Constructor
def initialize
textdomain "installation"
Yast.import "PackagesProposal"
Yast.import "ProductFeatures"
Yast.import "Linuxrc"
load_features
enable_firewall! if @enable_firewall
enable_sshd! if wanted_enable_sshd?
open_ssh! if wanted_open_ssh?
open_vnc! if wanted_open_vnc?
propose_lsm_config
# FIXME: obtain from Y2Firewall::Firewalld, control file or allow to
# chose a different one in the proposal
@default_zone = "public"
end
# Load the default values defined in the control file
def load_features
load_feature(:enable_firewall, :enable_firewall)
load_feature(:firewall_enable_ssh, :open_ssh)
load_feature(:enable_sshd, :enable_sshd)
load_feature(:polkit_default_privs, :polkit_default_privileges)
end
# When Linux Security Module is declared as configurable and there is no Module selected yet
# it will select the desired LSM and the needed patterns for it accordingly
def propose_lsm_config
return unless lsm_config.configurable?
return if lsm_config.selected
lsm_config.propose_default
# It will be set even if the proposal is not shown (e.g. configurable but not selectable)
Yast::PackagesProposal.SetResolvables("LSM", :pattern, lsm_config.needed_patterns)
end
# Make a one-time proposal for the security settings:
#
# If only public key authentication is configured, and no root password is set,
# open the SSH port and enable SSHD so at least SSH access can be used.
#
# This should be called AFTER the user was prompted for the root password, e.g.
# when the security proposal is made during installation.
#
# This is done only once. Use 'reset_proposal' to do do it again.
def propose
return if @proposal_done
@proposal_done = true
log.info("Making security settings proposal")
return unless only_public_key_auth?
log.info("Only public key auth")
open_ssh! unless @open_ssh
enable_sshd! unless @enable_sshd
end
# Reset the proposal; i.e. the next call to 'propose' will do a fresh
# proposal.
def reset_proposal
@proposal_done = false
end
# Services
# Add the firewall package to be installed and sets the firewalld service
# to be enabled
def enable_firewall!
Yast::PackagesProposal.AddResolvables("firewall", :package, ["firewalld"])
log.info "Enabling firewall"
self.enable_firewall = true
end
# Remove the firewalld package from being installed and sets the firewalld
# service to be disabled
def disable_firewall!
Yast::PackagesProposal.RemoveResolvables("firewall", :package, ["firewalld"])
log.info "Disabling firewall"
self.enable_firewall = false
end
# Add the openssh package to be installed and sets the sshd service
# to be enabled
def enable_sshd!
Yast::PackagesProposal.AddResolvables("firewall", :package, ["openssh"])
log.info "Enabling SSHD"
self.enable_sshd = true
end
# Remove the openssh package from being installed and sets the sshd service
# to be disabled
def disable_sshd!
Yast::PackagesProposal.RemoveResolvables("firewall", :package, ["openssh"])
log.info "Disabling SSHD"
self.enable_sshd = false
end
# Set the ssh port to be opened
def open_ssh!
log.info "Opening SSH port"
self.open_ssh = true
end
# Set the ssh port to be closed
def close_ssh!
log.info "Closing SSH port"
self.open_ssh = false
end
# Set the vnc port to be opened
def open_vnc!
log.info "Opening VNC port"
self.open_vnc = true
end
# Set the vnc port to be closed
def close_vnc!
log.info "Closing VNC port"
self.open_vnc = false
end
# Return whether the current settings could be a problem for the user to
# login
#
# @return [Boolean] true if the root user uses only public key
# authentication and the system is not accesible through ssh
def access_problem?
# public key is not the only way
return false unless only_public_key_auth?
# without running sshd it is useless
return true unless @enable_sshd
# firewall is up and port for ssh is not open
@enable_firewall && !@open_ssh
end
def human_polkit_privileges
{
"" => _("Default"),
# TRANSLATORS: restrictive in sense the most restrictive policy
"restrictive" => _("Restrictive"),
"standard" => _("Standard"),
# TRANSLATORS: easy in sense the least restrictive policy
"easy" => _("Easy")
}
end
# @return [Y2Security::LSM::Config] the LSM config handler
def lsm_config
Y2Security::LSM::Config.instance
end
private
def load_feature(feature, to, source: global_section)
value = Yast::Ops.get(source, feature.to_s)
public_send("#{to}=", value) unless value.nil?
end
def global_section
Yast::ProductFeatures.GetSection("globals")
end
def wanted_enable_sshd?
Yast::Linuxrc.usessh || @enable_sshd
end
def wanted_open_ssh?
Yast::Linuxrc.usessh || @open_ssh
end
def wanted_open_vnc?
Yast::Linuxrc.vnc
end
# Determines whether only public key authentication is supported.
#
# Do not call this prematurely before the user was even prompted for a root password;
# in particular, do not call this from the constructor of this class.
#
# @note If the root user does not have a password, we assume that we will use a public
# key in order to log into the system. In such a case, we need to enable the SSH
# service (including opening the port).
def only_public_key_auth?
if root_user.nil?
log.warn("No root user created yet; can't check root password!")
return false
end
password = root_user.password_content || ""
password.empty?
end
# Root user from the target config
#
# @return [Y2Users::User, nil]
def root_user
config = Y2Users::ConfigManager.instance.target
return nil unless config
config.users.root
end
class << self
def run
instance.run
end
# Singleton instance
def instance
create_instance unless @instance
@instance
end
# Enforce a new clean instance
def create_instance
@instance = new
end
# Make sure only .instance and .create_instance can be used to
# create objects
private :new, :allocate
end
end
end