Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NAS-132657 / 25.04 / Remove explicit calls to syslog.syslog module #15039

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
166 changes: 79 additions & 87 deletions src/freenas/etc/find_alias_for_smtplib.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,133 +2,125 @@
import email
import email.parser
import json
import os
import re
import requests
import sys
import syslog

from truenas_api_client import Client

ALIASES = re.compile(r'^(?P<from>[^#]\S*?):\s*(?P<to>\S+)$')


def do_sendmail(msg, to_addrs=None, parse_recipients=False):
to_addrs = ["root"] if to_addrs is None else to_addrs
if to_addrs is None and not parse_recipients:
raise ValueError("Do not know who to send the message to.")

if to_addrs is None:
if not parse_recipients:
syslog.syslog('Do not know who to send the message to.' + msg[0:140])
raise ValueError('Do not know who to send the message to.')
to_addrs = []

# XXX: this should probably be a FeedParser because reading from sys.stdin
# is blocking.
em_parser = email.parser.Parser()
em = em_parser.parsestr(msg)
em = email.parser.Parser().parsestr(msg)
if parse_recipients:
# Strip away the comma based delimiters and whitespace.
to_addrs = list(map(str.strip, em.get('To').split(',')))

if not to_addrs or not to_addrs[0]:
to_addrs = ['root']
for addr in map(str.strip, em.get("To", "").split(",")):
if addr:
to_addrs.append(addr)

to_addrs_repl = []
if to_addrs:
aliases = get_aliases()
for to_addr in to_addrs:
for to_addr in to_addr.split(','):
if to_addr.find('@') != -1:
to_addrs_repl.append(to_addr)
elif to_addr.find('@') == -1 and to_addr in aliases:
to_addrs_repl.append(aliases[to_addr])
aliases = get_aliases()
for i in to_addrs:
for to_addr in i.split(","):
if "@" in to_addr:
to_addrs_repl.append(to_addr)
elif to_addr in aliases:
to_addrs_repl.append(aliases[to_addr])

if not to_addrs_repl:
syslog.syslog(f'No aliases found to send email to {", ".join(to_addrs)}')
print(
f'No aliases found to send email to {", ".join(to_addrs)}', file=sys.stderr
)
sys.exit(1)

with Client() as c:
sw_name = 'TrueNAS'

margs = {}
margs['extra_headers'] = dict(em)
margs['extra_headers'].update({
'X-Mailer': sw_name,
f'X-{sw_name}-Host': c.call('system.hostname'),
'To': ', '.join(to_addrs_repl),
})
margs['subject'] = em.get('Subject')

sw_name = "TrueNAS"
margs = dict()
margs["extra_headers"] = dict(em)
margs["extra_headers"].update(
{
"X-Mailer": sw_name,
f"X-{sw_name}-Host": c.call("system.hostname"),
"To": ", ".join(to_addrs_repl),
}
)
margs["subject"] = em.get("Subject")
if em.is_multipart():
attachments = [part for part in em.walk() if part.get_content_maintype() != 'multipart']
margs['attachments'] = True if attachments else False
margs['text'] = (
'This is a MIME formatted message. If you see '
'this text it means that your email software '
'does not support MIME formatted messages.')
margs['html'] = None
attachments = [
part for part in em.walk() if part.get_content_maintype() != "multipart"
]
margs["attachments"] = True if attachments else False
margs["text"] = (
"This is a MIME formatted message. If you see "
"this text it means that your email software "
"does not support MIME formatted messages."
)
margs["html"] = None
else:
margs['text'] = ''.join(email.iterators.body_line_iterator(em))

margs['to'] = to_addrs_repl
margs["text"] = "".join(email.iterators.body_line_iterator(em))

if not margs.get('attachments'):
c.call('mail.send', margs)
margs["to"] = to_addrs_repl
if not margs.get("attachments"):
c.call("mail.send", margs)
else:
token = c.call('auth.generate_token')
token = c.call("auth.generate_token")
files = []
for attachment in attachments:
entry = {'headers': []}
entry = {"headers": []}
for k, v in attachment.items():
entry['headers'].append({'name': k, 'value': v})
entry['content'] = attachment.get_payload()
entry["headers"].append({"name": k, "value": v})
entry["content"] = attachment.get_payload()
files.append(entry)

requests.post(
f'http://localhost:6000/_upload?auth_token={token}',
f"http://localhost:6000/_upload?auth_token={token}",
files={
'data': json.dumps({'method': 'mail.send', 'params': [margs]}),
'file': json.dumps(files),
"data": json.dumps({"method": "mail.send", "params": [margs]}),
"file": json.dumps(files),
},
)


def get_aliases():
with open('/etc/aliases', 'r') as f:
aliases = {}

for line in f.readlines():
search = ALIASES.search(line)
if search:
_from, _to = search.groups()
aliases[_from] = _to

while True:
oldaliases = set(aliases.items())
for key, val in aliases.items():
if key == val:
syslog.syslog(syslog.LOG_ERR, f'Found a recursive dependency for {key}')
elif val in aliases:
aliases[key] = aliases[val]
if set(aliases.items()) == oldaliases:
break
return aliases
aliases = {}
with open("/etc/aliases", "r") as f:
for line in f:
# looks like
# admin1: [email protected], [email protected]
# admin2: [email protected]
try:
name, addresses = line.strip().split(":")
if name != addresses:
aliases[name] = addresses
except ValueError:
continue
return aliases


def main():
syslog.openlog(logoption=syslog.LOG_PID, facility=syslog.LOG_MAIL)
parser = argparse.ArgumentParser(description='Process email')
parser.add_argument('-i', dest='strip_leading_dot', action='store_false',
default=True, help='see sendmail(8) -i')
parser.add_argument('-t', dest='parse_recipients', action='store_true',
default=False,
help='parse recipients from message')
parser.usage = ' '.join(parser.format_usage().split(' ')[1:-1])
parser.usage += ' [email_addr|user] ..'
parser = argparse.ArgumentParser(description="Process email")
parser.add_argument(
"-i",
dest="strip_leading_dot",
action="store_false",
default=True,
help="see sendmail(8) -i",
)
parser.add_argument(
"-t",
dest="parse_recipients",
action="store_true",
default=False,
help="parse recipients from message",
)
parser.usage = " ".join(parser.format_usage().split(" ")[1:-1])
parser.usage += " [email_addr|user] .."
args, to = parser.parse_known_args()
if not to and not args.parse_recipients:
parser.exit(message=parser.format_usage())
msg = sys.stdin.read()
syslog.syslog("sending mail to " + ', '.join(to) + '\n' + msg[0:140])
do_sendmail(msg, to_addrs=to, parse_recipients=args.parse_recipients)


Expand Down
26 changes: 3 additions & 23 deletions src/middlewared/middlewared/plugins/cron.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import contextlib
import errno
import syslog

from middlewared.schema import accepts, Bool, Cron, Dict, Int, Patch, returns, Str
from middlewared.service import CallError, CRUDService, job, private, ValidationErrors
Expand Down Expand Up @@ -209,10 +208,6 @@ def run(self, job, id_, skip_disabled):
"""
Job to run cronjob task of `id`.
"""
def __cron_log(line):
job.logs_fd.write(line)
syslog.syslog(syslog.LOG_INFO, line.decode())

cron_task = self.middleware.call_sync('cronjob.get_instance', id_)
if skip_disabled and not cron_task['enabled']:
raise CallError('Cron job is disabled', errno.EINVAL)
Expand All @@ -224,26 +219,11 @@ def __cron_log(line):
)[7:]
)

job.set_progress(
10,
'Executing Cron Task'
)

syslog.openlog('cron', facility=syslog.LOG_CRON)

syslog.syslog(syslog.LOG_INFO, f'({cron_task["user"]}) CMD ({cron_cmd})')

cp = run_command_with_user_context(
cron_cmd, cron_task['user'], callback=__cron_log,
)

syslog.closelog()
job.set_progress(10, 'Executing Cron Task')

job.set_progress(
85,
'Executed Cron Task'
)
cp = run_command_with_user_context(cron_cmd, cron_task['user'], callback=job.logs_fd.write)

job.set_progress(85, 'Executed Cron Task')
if cp.stdout:
email = (
self.middleware.call_sync('user.query', [['username', '=', cron_task['user']]], {'get': True})
Expand Down
7 changes: 0 additions & 7 deletions src/middlewared/middlewared/plugins/mail.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import json
import os
import smtplib
import syslog


class DenyNetworkActivity(Exception):
Expand Down Expand Up @@ -369,7 +368,6 @@ def read_json():
else:
msg[key] = val

syslog.openlog(logoption=syslog.LOG_PID, facility=syslog.LOG_MAIL)
try:
if config['oauth']:
self.middleware.call_sync('mail.gmail_send', msg, config)
Expand All @@ -383,20 +381,15 @@ def read_json():
# This is because FreeNAS doesn't run a full MTA.
# else:
# server.connect()
headers = '\n'.join([f'{k}: {v}' for k, v in msg._headers])
syslog.syslog(f"sending mail to {', '.join(to)}\n{headers}")
server.sendmail(from_addr.encode(), to, msg.as_string())
server.quit()
except DenyNetworkActivity:
self.logger.warning('Sending email denied')
return False
except Exception as e:
# Don't spam syslog with these messages. They should only end up in the
# test-email pane.
# We are only interested in ValueError, not subclasses.
if e.__class__ is ValueError:
raise CallError(str(e))
syslog.syslog(f'Failed to send email to {", ".join(to)}: {str(e)}')
if isinstance(e, smtplib.SMTPAuthenticationError):
raise CallError(
f'Authentication error ({e.smtp_code}): {e.smtp_error}', errno.EPERM
Expand Down
14 changes: 0 additions & 14 deletions src/middlewared/middlewared/plugins/ssh.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import base64
import hashlib
import os
import subprocess
import syslog

import middlewared.sqlalchemy as sa

Expand Down Expand Up @@ -163,18 +161,6 @@ async def do_update(self, data):

await self._update_service(old, new)

keyfile = "/usr/local/etc/ssh/ssh_host_ecdsa_key.pub"
if os.path.exists(keyfile):
with open(keyfile, "rb") as f:
pubkey = f.read().strip().split(None, 3)[1]
decoded_key = base64.b64decode(pubkey)
key_digest = hashlib.sha256(decoded_key).digest()
ssh_fingerprint = (b"SHA256:" + base64.b64encode(key_digest).replace(b"=", b"")).decode("utf-8")

syslog.openlog(logoption=syslog.LOG_PID, facility=syslog.LOG_USER)
syslog.syslog(syslog.LOG_ERR, 'ECDSA Fingerprint of the SSH KEY: ' + ssh_fingerprint)
syslog.closelog()

return await self.config()

keys = [
Expand Down
7 changes: 0 additions & 7 deletions src/middlewared/middlewared/plugins/system_general/update.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import asyncio
import syslog

import middlewared.sqlalchemy as sa

Expand Down Expand Up @@ -181,18 +180,12 @@ async def validate_general_settings(self, data, old_config, schema):
'Please specify a valid certificate which exists in the system'
)
else:
cert = cert[0]
verrors.extend(
await self.middleware.call(
'certificate.cert_services_validation', certificate_id, f'{schema}.ui_certificate', False
)
)

if cert['fingerprint']:
syslog.openlog(logoption=syslog.LOG_PID, facility=syslog.LOG_USER)
syslog.syslog(syslog.LOG_ERR, 'Fingerprint of the certificate used in UI : ' + cert['fingerprint'])
syslog.closelog()

return verrors

@accepts(
Expand Down
7 changes: 2 additions & 5 deletions src/middlewared/middlewared/plugins/ups.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import io
import os
import re
import syslog

from middlewared.schema import accepts, Bool, Dict, Int, List, Patch, returns, Str
from middlewared.service import private, SystemServiceService, ValidationErrors
Expand Down Expand Up @@ -313,13 +312,11 @@ async def upssched_event(self, notify_type):
# first and then shut the active node down
if await self.middleware.call('failover.licensed'):
if await self.middleware.call('failover.status') == 'MASTER':
syslog.syslog(syslog.LOG_NOTICE, 'upssched-cmd "issuing shutdown" for passive node')
try:
await self.middleware.call('failover.call_remote', 'ups.upssched_event', ['shutdown'])
except Exception as e:
syslog.syslog(syslog.LOG_ERR, f'failed shutting down passive node with error {e}')
except Exception:
self.logger.error('failed shutting down passive node', exc_info=True)

syslog.syslog(syslog.LOG_NOTICE, 'upssched-cmd "issuing shutdown"')
await run('upsmon', '-c', 'fsd', check=False)

elif 'notify' in notify_type.lower():
Expand Down
7 changes: 0 additions & 7 deletions src/middlewared/middlewared/utils/syslog.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,12 @@
import os
import syslog
import uuid

from middlewared.utils.time_utils import utc_now


def syslog_message(message):
data = f'<{syslog.LOG_USER | syslog.LOG_INFO}>'

data += f'{utc_now().strftime("%b %d %H:%M:%S")} '

data += 'TNAUDIT_MIDDLEWARE: '

data += message

data = data.encode('ascii', 'ignore')

return data