Skip to content

Commit ebae301

Browse files
author
Sebastian Wagner
committed
Merge branch 'maintenance' into develop
2 parents 6526f0a + 958ffef commit ebae301

File tree

3 files changed

+156
-9
lines changed

3 files changed

+156
-9
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ Update allowed classification fields to 2020-01-28 version (#1409, #1476). Old n
104104
### Tools
105105
- `intelmqsetup`:
106106
- Also cover required directory layout and file permissions for `intelmq-api` (PR#1787 by Sebastian Wagner, fixes #1783).
107+
- Also cover webserver and sudoers configuration for `intelmq-api` and `intelmq-manger` (PR#1805 by Sebastian Wagner, fixes #1803).
107108
- `intelmqctl`:
108109
- Do not log an error message if logging to file is explicitly disabled, e.g. in calls from `intelmsetup`. The error message would not be useful for the user and is not necessary.
109110

debian/rules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ override_dh_auto_install: $(BOTDOCS)
6161
# remove program not needed for packages
6262
rm debian/intelmq/usr/bin/intelmqsetup
6363
# create directory layout and empty state file
64-
ROOT_DIR=debian/intelmq/ PYTHONPATH=. python3 intelmq/bin/intelmqsetup.py --skip-ownership --state-file debian/intelmq/var/lib/intelmq/state.json
64+
ROOT_DIR=debian/intelmq/ PYTHONPATH=. python3 intelmq/bin/intelmqsetup.py --skip-ownership --state-file debian/intelmq/var/lib/intelmq/state.json --skip-api
6565

6666
override_dh_install:
6767
dh_install

intelmq/bin/intelmqsetup.py

Lines changed: 154 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,21 +28,31 @@
2828
from grp import getgrnam
2929
from pathlib import Path
3030
from pwd import getpwnam
31+
from subprocess import run, CalledProcessError
32+
from tempfile import NamedTemporaryFile
3133
from typing import Optional
3234

3335
try:
3436
import intelmq_api
3537
except ImportError:
3638
intelmq_api = None
3739

40+
try:
41+
import intelmq_manager
42+
except ImportError:
43+
intelmq_manager = None
44+
3845
from termstyle import red
3946
from intelmq import (CONFIG_DIR, DEFAULT_LOGGING_PATH, ROOT_DIR, VAR_RUN_PATH,
4047
VAR_STATE_PATH, BOTS_FILE, STATE_FILE_PATH)
4148
from intelmq.bin.intelmqctl import IntelMQController
4249

4350

44-
MANAGER_CONFIG_DIR = Path(CONFIG_DIR) / 'manager/'
4551
FILE_OUTPUT_PATH = Path(VAR_STATE_PATH) / 'file-output/'
52+
ETC_INTELMQ = Path('/etc/intelmq/')
53+
ETC_INTELMQ_MANAGER = ETC_INTELMQ / 'manager/'
54+
WEBSERVER_CONFIG_DIR = None # "cache" for the webserver configuration directory
55+
NOTE_WEBSERVER_RELOAD = False # if the webserver needs to be reloaded
4656

4757

4858
def basic_checks(skip_ownership):
@@ -77,7 +87,7 @@ def create_directory(directory: str, octal_mode: int):
7787
directory.chmod(octal_mode)
7888

7989

80-
def change_owner(file: str, owner=None, group=None, log: bool = True):
90+
def change_owner(file: str, owner: Optional[str] = None, group: Optional[str] = None, log: bool = True):
8191
if owner and Path(file).owner() != owner:
8292
if log:
8393
print(f'Fixing owner of {file!s}.')
@@ -96,8 +106,39 @@ def find_webserver_user():
96106
except KeyError:
97107
pass
98108
else:
99-
print(f'Detected webserver username {candidate!r}.')
109+
print(f'Detected Apache username {candidate!r}.')
100110
return candidate
111+
else:
112+
sys.exit(red("Unable to detect Apache user name. "
113+
"Please re-run this program and give the Apache user name with '--webserver-user'."))
114+
115+
116+
def find_webserver_configuration_directory():
117+
global WEBSERVER_CONFIG_DIR
118+
if WEBSERVER_CONFIG_DIR:
119+
return WEBSERVER_CONFIG_DIR
120+
webserver_configuration_dir_candidates = (Path('/etc/apache2/conf-available/'),
121+
Path('/etc/apache2/conf.d/'),
122+
Path('/etc/httpd/conf.d/'))
123+
for webserver_configuration_dir_candidate in webserver_configuration_dir_candidates:
124+
if webserver_configuration_dir_candidate.exists():
125+
print(f'Detected Apache configuration directory {webserver_configuration_dir_candidate!s}.')
126+
WEBSERVER_CONFIG_DIR = webserver_configuration_dir_candidate
127+
webserver_configuration_dir_candidate.as_posix
128+
return webserver_configuration_dir_candidate
129+
else:
130+
sys.exit(red("Unable to detect Apache configuration directory. "
131+
"Please re-run this program and give the Apache configuration directory with '--webserver-configuration-directory'."))
132+
133+
134+
def debian_activate_apache_config(config_name: str):
135+
if 'available' not in WEBSERVER_CONFIG_DIR.as_posix():
136+
return # not a Debian system
137+
available = WEBSERVER_CONFIG_DIR / config_name
138+
enabled = Path(WEBSERVER_CONFIG_DIR.as_posix().replace('available', 'enabled')) / config_name
139+
if not enabled.exists():
140+
enabled.symlink_to(available)
141+
print('Created symbolic link {enabled!s} pointing to {available!s}.')
101142

102143

103144
def intelmqsetup_core(ownership=True, state_file=STATE_FILE_PATH):
@@ -140,23 +181,109 @@ def intelmqsetup_core(ownership=True, state_file=STATE_FILE_PATH):
140181

141182

142183
def intelmqsetup_api(ownership: bool = True, webserver_user: Optional[str] = None):
184+
intelmq_group = getgrnam('intelmq')
185+
webserver_user = webserver_user or find_webserver_user()
186+
187+
create_directory(ETC_INTELMQ, 0o40775)
143188
if ownership:
144189
change_owner(CONFIG_DIR, group='intelmq')
190+
change_owner(ETC_INTELMQ, owner='intelmq', group='intelmq')
145191

146192
# Manager configuration directory
147-
create_directory(MANAGER_CONFIG_DIR, 0o40775)
193+
create_directory(ETC_INTELMQ_MANAGER, 0o40775)
148194
if ownership:
149-
change_owner(MANAGER_CONFIG_DIR, group='intelmq')
195+
change_owner(ETC_INTELMQ_MANAGER, group='intelmq')
196+
197+
base = Path(pkg_resources.resource_filename('intelmq_api', '')).parent
198+
api_config = base / 'etc/intelmq/api-config.json'
199+
etc_intelmq_config = ETC_INTELMQ / 'api-config.json'
200+
api_sudoers = base / 'etc/intelmq/api-sudoers.conf'
201+
etc_sudoers_api = Path('/etc/sudoers.d/01_intelmq-api') # same path as used in the packages
202+
api_manager_positions = base / 'etc/intelmq/manager/positions.conf'
203+
etc_intelmq_manager_positions = ETC_INTELMQ_MANAGER / 'positions.conf'
204+
205+
if not base.as_posix().startswith('/usr/'):
206+
# Paths differ in editable installations
207+
print(red("Detected an editable (egg-link) pip-installation of 'intelmq-api'. Some feature of this program may not work."))
208+
209+
if api_config.exists() and not etc_intelmq_config.exists():
210+
shutil.copy(api_config, etc_intelmq_config)
211+
print(f'Copied {api_config!s} to {ETC_INTELMQ!s}.')
212+
elif not api_config.exists() and not etc_intelmq_config.exists():
213+
print(red(f'Unable to install api-config.json: Neither {api_config!s} nor {etc_intelmq_config!s} exists.'))
214+
if api_sudoers.exists() and not etc_sudoers_api.exists():
215+
with open(api_sudoers) as sudoers:
216+
original_sudoers = sudoers.read()
217+
sudoers = original_sudoers.replace('www-data', webserver_user)
218+
with NamedTemporaryFile(mode='w') as tmp_file:
219+
tmp_file.write(sudoers)
220+
tmp_file.flush()
221+
try:
222+
run(('visudo', '-c', tmp_file.name))
223+
except CalledProcessError:
224+
sys.exit(red('Fatal error: Validation of adapted sudoers-file failed. Please report this bug.'))
225+
change_owner(tmp_file.name, owner='root', group='root', log=False)
226+
Path(tmp_file.name).chmod(0o440)
227+
shutil.copy(tmp_file.name, etc_sudoers_api)
228+
print(f'Copied {api_sudoers!s} to {etc_sudoers_api!s}.')
229+
elif not api_sudoers.exists() and not etc_sudoers_api.exists():
230+
print(red(f'Unable to install api-sudoers.conf: Neither {api_sudoers!s} nor {etc_sudoers_api!s} exists.'))
231+
if api_manager_positions.exists() and not etc_intelmq_manager_positions.exists():
232+
shutil.copy(api_manager_positions, etc_intelmq_manager_positions)
233+
print(f'Copied {api_manager_positions!s} to {etc_intelmq_manager_positions!s}.')
234+
etc_intelmq_manager_positions.chmod(0o664)
235+
change_owner(etc_intelmq_manager_positions, owner='intelmq', group='intelmq', log=False)
236+
elif not api_manager_positions.exists() and not etc_intelmq_manager_positions.exists():
237+
print(red(f'Unable to install positions.conf: Neither {api_manager_positions!s} nor {etc_intelmq_manager_positions!s} exists.'))
150238

151-
intelmq_group = getgrnam('intelmq')
152-
webserver_user = webserver_user or find_webserver_user()
153239
if webserver_user not in intelmq_group.gr_mem:
154240
sys.exit(red(f"Webserver user {webserver_user} is not a member of the 'intelmq' group. "
155241
f"Please add it with: 'usermod -aG intelmq {webserver_user}'."))
156242

243+
244+
def intelmqsetup_api_webserver_configuration(webserver_configuration_directory: Optional[str] = None):
245+
webserver_configuration_dir = webserver_configuration_directory or find_webserver_configuration_directory()
246+
api_config = Path(pkg_resources.resource_filename('intelmq_api', '')).parent / 'etc/intelmq/api-apache.conf'
247+
apache_api_config = webserver_configuration_dir / 'api-apache.conf'
248+
if api_config.exists() and not apache_api_config.exists():
249+
shutil.copy(api_config, apache_api_config)
250+
print(f'Copied {api_config!s} to {ETC_INTELMQ!s}.')
251+
debian_activate_apache_config('api-apache.conf')
252+
253+
global NOTE_WEBSERVER_RELOAD
254+
NOTE_WEBSERVER_RELOAD = True
255+
elif not api_config.exists() and not apache_api_config.exists():
256+
print(red(f'Unable to install webserver configuration api-config.conf: Neither {api_config!s} nor {apache_api_config!s} exists.'))
257+
157258
print('Setup of intelmq-api successful.')
158259

159260

261+
def intelmqsetup_manager_webserver_configuration(webserver_configuration_directory: Optional[str] = None):
262+
html_dir = Path(pkg_resources.resource_filename('intelmq_manager', '')).parent / '/usr/share/intelmq-manager/html'
263+
html_dir_destination = Path('/usr/share/intelmq-manager/html')
264+
265+
if not html_dir_destination.as_posix().startswith('/usr/'):
266+
# Paths differ in editable installations
267+
print(red("Detected an editable (egg-link) pip-installation of intelmq-manager. Some feature of this program may not work."))
268+
269+
webserver_configuration_dir = webserver_configuration_directory or find_webserver_configuration_directory()
270+
manager_config = Path(pkg_resources.resource_filename('intelmq_manager', '')).parent / 'etc/intelmq/manager-apache.conf'
271+
apache_manager_config = webserver_configuration_dir / 'manager-apache.conf'
272+
if manager_config.exists() and not apache_manager_config.exists():
273+
shutil.copy(manager_config, apache_manager_config)
274+
print(f'Copied {manager_config!s} to {apache_manager_config!s}.')
275+
debian_activate_apache_config('manager-apache.conf')
276+
277+
global NOTE_WEBSERVER_RELOAD
278+
NOTE_WEBSERVER_RELOAD = True
279+
elif not manager_config.exists() and not apache_manager_config.exists():
280+
print(red(f'Unable to install webserver configuration manager-config.conf: Neither {manager_config!s} nor {apache_manager_config!s} exists.'))
281+
282+
if html_dir.exists():
283+
shutil.copy(html_dir, '/')
284+
print(f'Copied {html_dir!s} to {html_dir_destination!s}.')
285+
286+
160287
def main():
161288
parser = argparse.ArgumentParser("Set's up directories and example "
162289
"configurations for IntelMQ.")
@@ -167,15 +294,34 @@ def main():
167294
default=STATE_FILE_PATH)
168295
parser.add_argument('--webserver-user',
169296
help='The webserver to use instead of auto-detection.')
297+
parser.add_argument('--webserver-configuration-directory',
298+
help='The webserver configuration directory to use instead of auto-detection.')
299+
parser.add_argument('--skip-api',
300+
help='Skip set-up of intelmq-api.',
301+
action='store_true')
170302
args = parser.parse_args()
171303

172304
basic_checks(skip_ownership=args.skip_ownership)
173305
intelmqsetup_core(ownership=not args.skip_ownership,
174306
state_file=args.state_file)
175-
if intelmq_api:
307+
if intelmq_api and not args.skip_api:
176308
print('Running setup for intelmq-api.')
177309
intelmqsetup_api(ownership=not args.skip_ownership,
178310
webserver_user=args.webserver_user)
311+
print('Running webserver setup for intelmq-api.')
312+
intelmqsetup_api_webserver_configuration(webserver_configuration_directory=args.webserver_configuration_directory)
313+
else:
314+
print('Skipping set-up of intelmq-api.')
315+
if intelmq_manager and not args.skip_api:
316+
print('Running webserver setup for intelmq-manager.')
317+
intelmqsetup_manager_webserver_configuration(webserver_configuration_directory=args.webserver_configuration_directory)
318+
else:
319+
print('Skipping set-up of intelmq-manager.')
320+
321+
if NOTE_WEBSERVER_RELOAD:
322+
print('Reload the webserver to make the changes effective.')
323+
324+
print("'intelmqsetup' completed.")
179325

180326

181327
if __name__ == '__main__':

0 commit comments

Comments
 (0)