You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
176 lines
5.6 KiB
176 lines
5.6 KiB
import re
|
|
import socket
|
|
|
|
from email.header import Header
|
|
from email.mime.multipart import MIMEMultipart
|
|
from email.mime.text import MIMEText
|
|
import sendemail_common
|
|
|
|
import splunk.admin as admin
|
|
import splunk.entity as en
|
|
import splunk.mining.dcutils as dcu
|
|
import splunk.secure_smtplib as secure_smtplib
|
|
import splunk.ssl_context as ssl_context
|
|
|
|
logger = dcu.getLogger()
|
|
|
|
charset = "UTF-8"
|
|
EMAIL_DELIM = re.compile(r'\s*[,;]\s*')
|
|
|
|
def isASCII(str):
|
|
for i in str:
|
|
if ord(i) > 127:
|
|
return False
|
|
return True
|
|
|
|
def toBool(strVal):
|
|
if strVal == None:
|
|
return False
|
|
|
|
lStrVal = strVal.lower()
|
|
if lStrVal == "true" or lStrVal == "t" or lStrVal == "1" or lStrVal == "yes" or lStrVal == "y" :
|
|
return True
|
|
return False
|
|
|
|
|
|
class SendemailRestHandler(admin.MConfigHandler):
|
|
|
|
def __init__(self, scriptMode, ctxInfo):
|
|
admin.MConfigHandler.__init__(self, scriptMode, ctxInfo)
|
|
self.shouldAutoList = False
|
|
|
|
# get firs arg
|
|
def gfa(self, name, defaultVal=''):
|
|
if self.hasNonEmptyArg(name):
|
|
val = self.callerArgs.get(name, [defaultVal])[0]
|
|
if val != None: return val
|
|
return defaultVal
|
|
|
|
def hasNonEmptyArg(self, name):
|
|
return name in self.callerArgs and self.callerArgs.get(name) != None
|
|
|
|
def setup(self):
|
|
if self.requestedAction == admin.ACTION_CREATE or self.requestedAction == admin.ACTION_EDIT:
|
|
for arg in ['to', 'body']:
|
|
self.supportedArgs.addReqArg(arg)
|
|
|
|
for arg in ['cc', 'bcc', 'from', 'subject', 'format', 'username', 'password', 'server', 'use_ssl', 'use_tls']:
|
|
self.supportedArgs.addOptArg(arg)
|
|
|
|
userInfo = en.getEntity('/authentication/', 'current-context', sessionKey=self.getSessionKey())
|
|
if userInfo.get('username') != 'splunk-system-user':
|
|
raise admin.PermissionsException("This handler can only be called by the Splunk system user.")
|
|
|
|
def handleList(self, confInfo):
|
|
pass
|
|
|
|
def handleCreate(self, confInfo):
|
|
message = MIMEMultipart()
|
|
|
|
subject = self.gfa('subject')
|
|
body = self.gfa('body')
|
|
bodyformat = self.gfa('format', 'html')
|
|
|
|
server = self.gfa('server', 'localhost')
|
|
|
|
username = self.gfa('username')
|
|
password = self.gfa('password')
|
|
|
|
use_ssl = toBool(self.gfa('use_ssl'))
|
|
use_tls = toBool(self.gfa('use_tls'))
|
|
|
|
sessionKey = self.getSessionKey()
|
|
|
|
sslSettings = self.getAlertActions(sessionKey)
|
|
|
|
# Open debate whether we should get user and password from alert actions
|
|
# username = sslSettings.get('auth_username', '')
|
|
# password = sslSettings.get('clear_password', '')
|
|
|
|
if isASCII(subject):
|
|
message['Subject'] = subject
|
|
else:
|
|
message['Subject'] = Header(subject, charset)
|
|
|
|
recipients = []
|
|
for t in self.callerArgs.get('to'):
|
|
recipients.extend(EMAIL_DELIM.split(t))
|
|
message['To'] = ', '.join(self.callerArgs.get('to'))
|
|
|
|
if self.hasNonEmptyArg('cc') :
|
|
cc = [x for x in self.callerArgs.get('cc') if x != None]
|
|
if len(cc) > 0:
|
|
message['Cc'] = ', '.join(cc)
|
|
for t in cc:
|
|
recipients.extend(EMAIL_DELIM.split(t))
|
|
|
|
if self.hasNonEmptyArg('bcc'):
|
|
bcc = [x for x in self.callerArgs.get('bcc') if x != None]
|
|
if len(bcc) > 0:
|
|
message['Bcc'] = ', '.join(bcc)
|
|
for t in bcc:
|
|
recipients.extend(EMAIL_DELIM.split(t))
|
|
|
|
sender = 'splunk'
|
|
if self.hasNonEmptyArg('from'):
|
|
sender = self.gfa('from')
|
|
|
|
if sender.find("@") == -1:
|
|
sender = sender + '@' + socket.gethostname()
|
|
if sender.endswith("@"):
|
|
sender = sender + 'localhost'
|
|
|
|
message['From'] = sender
|
|
|
|
message.attach(MIMEText(body, bodyformat, _charset=charset))
|
|
|
|
if use_ssl or use_tls:
|
|
sslHelper = ssl_context.SSLHelper()
|
|
serverConfJSON = sslHelper.getServerSettings(sessionKey)
|
|
# Pass in settings from alert_actions.conf into context
|
|
ctx = sslHelper.createSSLContextFromSettings(
|
|
sslConfJSON=sslSettings,
|
|
serverConfJSON=serverConfJSON,
|
|
isClientContext=True)
|
|
|
|
# send the mail
|
|
if not use_ssl:
|
|
smtp = secure_smtplib.SecureSMTP(host=server)
|
|
else:
|
|
smtp = secure_smtplib.SecureSMTP_SSL(host=server, sslContext=ctx)
|
|
|
|
if use_tls:
|
|
smtp.starttls(ctx)
|
|
if len(username) > 0 and len(password) > 0:
|
|
smtp.login(username, password)
|
|
|
|
# Installed SMTP daemon may not support UTF8.
|
|
# This can only be determined if SMTPNotSupportedError is raised.
|
|
# Try without SMTPUTF8 option if raised.
|
|
audit_msg = 'Sending email for backgrounded search job: subject="%s", sender="%s", recipients="%s", server="%s"'
|
|
logger.info(audit_msg, message['Subject'], sender, str(recipients), server)
|
|
|
|
# Installed SMTP daemon may not support UTF8 as well as
|
|
# it may throw other exceptions also.
|
|
error = sendemail_common.sendEmailWithUTF8(smtp, sender, recipients, message.as_string())
|
|
|
|
if (error is not None):
|
|
logger.debug('send mail with utf8 failed. retrying without utf8 option. Error: %s', str(error))
|
|
smtp.sendmail(sender, recipients, message.as_string())
|
|
|
|
smtp.quit()
|
|
|
|
def getAlertActions(self, sessionKey):
|
|
settings = None
|
|
try:
|
|
settings = en.getEntity('/configs/conf-alert_actions', 'email', sessionKey=sessionKey)
|
|
logger.debug("sendemail_handler.getAlertActions conf file settings %s" % settings)
|
|
except Exception as e:
|
|
logger.error("Could not access or parse email stanza of alert_actions.conf. Error=%s" % str(e))
|
|
|
|
return settings
|
|
|
|
# initialize the handler
|
|
admin.init(SendemailRestHandler, admin.CONTEXT_APP_AND_USER)
|
|
|