From 87a372e119e648a922784ba95e3850c6078542f7 Mon Sep 17 00:00:00 2001 From: Marco Iannacone Date: Fri, 15 May 2026 15:37:41 +0200 Subject: [PATCH] fix(samba): compatibility with Samba 4.22+ and add CanarySMB alias The SMB module had two issues that prevented it from working on modern Samba installations: 1. Regex fix: the original anchored regex (^.*smbd_audit) failed when syslog prepends a timestamp before the smbd_audit token, as seen with rsyslog on Debian 12+ and Samba 4.x. Changed to use re.search() with unanchored pattern to match anywhere in the line. 2. Field parsing: Samba 4.22+ with vfs_full_audit prefix '%U|%I|%S' produces only 6 pipe-separated fields instead of the 13+ expected by the original code, causing IndexError. Added format detection to handle both the short format (Samba 4.22+) and the legacy long format transparently. 3. CanarySMB alias: opencanary.tac imports CanarySMB but the module only defines CanarySamba, causing ImportError on startup. Added CanarySMB = CanarySamba alias for backward compatibility. Tested on: Debian 13 Trixie, Samba 4.22.8, Python 3.13 Reported-by: Marco Iannacone --- opencanary/modules/samba.py | 72 ++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 24 deletions(-) diff --git a/opencanary/modules/samba.py b/opencanary/modules/samba.py index 0c4967f0..e57c27e0 100644 --- a/opencanary/modules/samba.py +++ b/opencanary/modules/samba.py @@ -10,40 +10,61 @@ def __init__(self, logFile=None, logger=None): FileSystemWatcher.__init__(self, fileName=logFile) def handleLines(self, lines=None): - audit_re = re.compile(r"^.*smbd_audit.*: (.*$)") + # Updated regex to match anywhere in the line (not just at start). + # Samba 4.x may prepend a syslog timestamp before the smbd_audit token, + # causing the original anchored regex (^.*smbd_audit) to fail. + audit_re = re.compile(r"smbd_audit.*:\s*(.*$)") for line in lines: - matches = audit_re.match(line) + matches = audit_re.search(line) # Skip lines that do not match the correct RegEx pattern if matches is None: continue - data = matches.groups()[0].split("|") + raw_data = matches.groups()[0].split("|") - user = data[0] + # Samba 4.22+ with vfs_full_audit prefix "%U|%I|%S" produces + # 6 fields: user|srcHost|shareName|action|status|path + # Older Samba with extended prefix produces 13+ fields. + # Pad to 13 elements so existing field indices remain valid. + data = raw_data + [""] * max(0, 13 - len(raw_data)) + + user = data[0] if data[0] else "anonymous" srcHost = data[1] - dstHost = data[2] - srcHostName = data[3] - shareName = data[4] - dstHostName = data[5] - smbVersion = data[6] - smbArch = data[7] - domainName = data[9] - auditAction = data[10] - auditStatus = data[11] - path = data[12] - if user == "": - user = "anonymous" + if len(raw_data) <= 6: + # Short format (Samba 4.22+): user|srcHost|shareName|action|status|path + shareName = data[2] + auditAction = data[3] + auditStatus = data[4] + path = data[5] if len(raw_data) > 5 else "" + dstHost = "" + srcHostName = "" + dstHostName = "" + smbVersion = "" + smbArch = "" + domainName = "" + else: + # Long format (older Samba) + dstHost = data[2] + srcHostName = data[3] + shareName = data[4] + dstHostName = data[5] + smbVersion = data[6] + smbArch = data[7] + domainName = data[9] + auditAction = data[10] + auditStatus = data[11] + path = data[12] - data = {} - data["src_host"] = srcHost - data["src_port"] = "-1" - data["dst_host"] = dstHost - data["dst_port"] = 445 - data["logtype"] = self.logger.LOG_SMB_FILE_OPEN - data["logdata"] = { + log_entry = {} + log_entry["src_host"] = srcHost + log_entry["src_port"] = "-1" + log_entry["dst_host"] = dstHost + log_entry["dst_port"] = 445 + log_entry["logtype"] = self.logger.LOG_SMB_FILE_OPEN + log_entry["logdata"] = { "USER": user, "REMOTENAME": srcHostName, "SHARENAME": shareName, @@ -55,7 +76,7 @@ def handleLines(self, lines=None): "STATUS": auditStatus, "FILENAME": path, } - self.logger.log(data) + self.logger.log(log_entry) class CanarySamba(CanaryService): NAME = "smb" @@ -76,3 +97,6 @@ def startYourEngines(self, reactor=None): fs = SambaLogWatcher(logFile=self.audit_file, logger=self.logger) fs.start() + + # Alias for backward compatibility and explicit import in opencanary.tac + CanarySMB = CanarySamba