/* * Copyright (c) 2015 EMC Corporation * All Rights Reserved */ package com.emc.storageos.systemservices.impl.audit; import java.io.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.regex.Pattern; import java.util.regex.Matcher; import java.util.Enumeration; import java.sql.Timestamp; import java.net.NetworkInterface; import java.net.InetAddress; import com.emc.storageos.security.audit.AuditLogManager; import com.emc.storageos.coordinator.client.service.CoordinatorClient; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.services.OperationTypeEnum; public class SystemAudit implements Runnable { private static final Logger _log = LoggerFactory.getLogger(SystemAudit.class); private static final String EVENT_SERVICE_TYPE = "SystemAudit"; private static String _auditlogfile = "/var/log/auth"; private static String _auditlogCPfile = "/var/log/auth.checkpoint"; private static int _scanInterval = 120 * 1000; // 2m /* * Here are pattern of system logs we are going to audit. * There are only one kind of auditlog we recorded for now. * 1. ssh login/execution log. Format is like following. * For password failure: * "2013-03-05 04:47:52 [auth] err sshd[8824]: error: PAM: Authentication failure for root from localhost" * For incorrect pkcs key * "2013-08-01 05:12:04 [auth] err sshd[22030]: error: key_read: uudecode aaaAAAAB3NzaC1yc2EAA...BMQfrbasOGYeu1Kjv root@lglw2020\n failed" */ private static Pattern auditlogPattern = Pattern .compile("([0-9-:\\s]{19}) (\\[auth\\]) (info|err) (sshd.*:|logger.*:) (Accepted.*|error.*|[0-9-:\\s]{19}.*) (for|key_read: uudecode \\S+) (.*)( from |@)([\\p{Alnum}\\.]+)[\\p{Alnum}\\s]*"); private AuditLogManager _auditMgr = null; public SystemAudit(DbClient dbClient, CoordinatorClient coordinatorClient) { _log.info("SystemAudit initialized"); _auditMgr = new AuditLogManager(); _auditMgr.setDbClient(dbClient); _auditMgr.setCoordinator(coordinatorClient); } public void setScanInterval(int interval) { _scanInterval = interval; } public void run() { // Endlessly monitor system logs (only "auth" for now) and // persistent them into cassandra db for audit while (true) { String host = null; try { Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces(); while (interfaces.hasMoreElements()) { NetworkInterface current = interfaces.nextElement(); if (!current.isUp() || current.isLoopback() || current.isVirtual()) { continue; } Enumeration<InetAddress> addresses = current.getInetAddresses(); while (addresses.hasMoreElements()) { InetAddress current_addr = addresses.nextElement(); if (current_addr.isLoopbackAddress()) { continue; } host = current_addr.getHostAddress(); } } } catch (Exception e) { _log.error("can not get system ip address, using default localhost"); host = "localhost"; } RandomAccessFile logCPfile = null; BufferedReader br = null; try { _log.info("Scanning log message for system audit in {} seconds ...", _scanInterval / 1000); Thread.sleep(_scanInterval); // 1. read last audited log from checkpoint file logCPfile = new RandomAccessFile(_auditlogCPfile, "rw"); long lastAuditedlogTime = 0; String lastAuditedlog = logCPfile.readLine(); if (lastAuditedlog != null) { Matcher m = auditlogPattern.matcher(lastAuditedlog); if (m.find()) { Timestamp lastAuditedlogTimestamp = Timestamp.valueOf(m.group(1)); lastAuditedlogTime = lastAuditedlogTimestamp.getTime(); } } // 2. scan auditlog file to insert qualified logs to cassandra br = new BufferedReader(new FileReader(_auditlogfile)); String line = null; Matcher m = null; Timestamp currlogTimestamp = null; while (lastAuditedlog != null && (line = br.readLine()) != null) { if (line.equals(lastAuditedlog)) { break; } } while ((line = br.readLine()) != null) { m = auditlogPattern.matcher(line); if (m.find()) { currlogTimestamp = Timestamp.valueOf(m.group(1)); if (currlogTimestamp.getTime() < lastAuditedlogTime) { continue; } else if (currlogTimestamp.getTime() == lastAuditedlogTime) { if (line.equals(lastAuditedlog)) { continue; } } if (m.group(4).startsWith("sshd")) { if (m.group(3).equals("err")) { recordSysAuditLog(OperationTypeEnum.SSH_LOGIN, currlogTimestamp.getTime(), AuditLogManager.AUDITLOG_FAILURE, null, m.group(7), m.group(9), host); } else { recordSysAuditLog(OperationTypeEnum.SSH_LOGIN, currlogTimestamp.getTime(), AuditLogManager.AUDITLOG_SUCCESS, null, m.group(7), m.group(9), host); } } // update audited log into checkpoint file logCPfile.seek(0); logCPfile.writeBytes(line); logCPfile.setLength(line.length()); } } } catch (FileNotFoundException e) { _log.error("Failed to open system log file: {}", e.toString()); } catch (Exception e) { _log.error("Problem scanning system log file: {}", e.toString()); } finally { try { br.close(); logCPfile.close(); } catch (Exception e) { _log.warn("Problem while releasing file resources", e.toString()); } } } } public void recordSysAuditLog(OperationTypeEnum auditType, long logTime, String operationalStatus, String description, Object... descparams) { _auditMgr.recordAuditLog(null, null, EVENT_SERVICE_TYPE, auditType, logTime, operationalStatus, description, descparams); } }