// Copyright (c) 2014-2015 IONU Security, Inc. All rights reserved. // // Logging and auditing services #ifndef eyelog_h #define eyelog_h #include #include #include #include #include #include #if defined(__APPLE__) #include #endif #include "eyering.h" #ifdef WIN32 # ifdef DLLEXPORT # define LIBEYE_DLL __declspec(dllexport) # else # define LIBEYE_DLL __declspec(dllimport) # endif #else #define LIBEYE_DLL #endif // Linux and OSX use syslog #if defined (LIN64) || defined (Darwin) || defined (__MACH__) #define LOG_TO_SYSLOG #endif #define IONULOG sequencelogic::LogWrapper #if (defined(ANDROID) || defined(DEBUG) || (defined(WIN32) && defined(_DEBUG))) #define IONUDEBUG(...) IONULOG (EyeLog::IONU_DEBUG, __VA_ARGS__) #define IONUTRACE(...) IONULOG (EyeLog::IONU_TRACE, __VA_ARGS__) #else #define IONUDEBUG(...) #define IONUTRACE(...) #endif #define IONUFATAL(...) IONULOG (EyeLog::IONU_FATAL, __VA_ARGS__) #define IONUERROR(...) IONULOG (EyeLog::IONU_ERROR, __VA_ARGS__) #define IONUWARN(...) IONULOG (EyeLog::IONU_WARN, __VA_ARGS__) #define IONUINFO(...) IONULOG (EyeLog::IONU_INFO, __VA_ARGS__) #define IONUAUDIT(code,...) sequencelogic::AuditWrapper (code, __VA_ARGS__) #define IONUCONFIGLOG EyeLog::GetInstance()->ConfigLogger #define IONUCONFIGFILELOG EyeLog::GetInstance()->ConfigFileLogger #define IONUCLOSELOG EyeLog::GetInstance()->CloseLogger #define IONUBEGINAUDIT EyeLog::GetInstance()->BeginAudit #define IONU_AUDIT_CODES \ X (AUDIT_START, 0, AuditStart) \ X (ACCOUNT_CHANGE, 1, AccountChange) \ X (ACCOUNT_CONTACT, 2, AccountContact) \ X (ACCOUNT_CREATE, 3, AccountCreate) \ X (ACCOUNT_DELETE, 4, AccountDelete) \ X (ACCOUNT_LOCKOUT, 5, AccountLockout) \ X (ACCOUNT_LOGIN, 6, AccountLogin) \ X (ACCOUNT_LOGOUT, 7, AccountLogout) \ X (ACCOUNT_PASSWORD, 8, AccountPassword) \ X (CONNECT_VPN, 10, ConnectVPN) \ X (CONNECT_SSL, 11, ConnectSSL) \ X (CONNECT_PROXY, 12, ConnectProxy) \ X (CONNECT_RELAY, 13, ConnectRelay) \ X (DEVICE_DELETE, 20, DeviceDelete) \ X (DEVICE_PROVISION, 21, DeviceProvision) \ X (DEVICE_RESET, 22, DeviceReset) \ X (DEVICE_WIPE, 23, DeviceWipe) \ X (DOCUMENT_ACCESS, 30, DocumentAccess) \ X (DOCUMENT_ADD, 31, DocumentAdd) \ X (DOCUMENT_DELETE, 32, DocumentDelete) \ X (DOCUMENT_DOWNLOAD, 33, DocumentDownload) \ X (DOCUMENT_EXPORT, 34, DocumentExport) \ X (DOCUMENT_IMPORT, 35, DocumentImport) \ X (DOCUMENT_MODIFY, 36, DocumentModify) \ X (DOCUMENT_RECEIVE, 37, DocumentReceive) \ X (DOCUMENT_SEND, 38, DocumentSend) \ X (DOCUMENT_UPLOAD, 39, DocumentUpload) \ X (GROUP_CREATE, 40, GroupCreate) \ X (GROUP_DELETE, 41, GroupDelete) \ X (GROUP_MODIFY, 42, GroupUpdate) \ X (POLICY_CHANGE, 50, PolicyChange) \ X (STORAGE_BACKUP, 60, StorageBackup) \ X (STORAGE_LISTING, 61, StorageListing) \ X (STORAGE_RESTORE, 62, StorageRestore) \ // Defaults #define IONU_MAX_LOG_FILES 3 #define IONU_MAX_LOG_FILE_SIZE (1024*1024) // 1MB #define IONU_MAX_AUDIT_ERRORS 10 namespace sequencelogic { class EyeLog { public: enum LOG_LEVEL { IONU_AUDIT = 0, // Lowest level, audit messages can never be suppressed IONU_FATAL = 1, // Severe errors that cause the app to terminate IONU_ERROR = 2, // Runtime errors reported to user IONU_WARN = 3, // Runtime warnings optionally reported to user IONU_INFO = 4, // Interesting runtime events that the user may choose to see IONU_DEBUG = 5, // Debug information for developers, not in production code IONU_TRACE = 6 // More detailed information for developers }; enum LOG_SINK { IONU_SYSLOG, // uses platform specific system logging facility IONU_CONSOLE, // stdout IONU_FILE // file based log //IONU_NETWORK // network based log }; enum LOG_FORMAT { IONU_LEVEL, // %l Error, Warn, Debug IONU_ULEVEL, // %L ERROR, WARN, DEBUG IONU_CLIENT, // %c client identifier IONU_ETIME, // %e milliseconds elapsed time IONU_TIME, // %t time IONU_MESSAGE, // %m log message IONU_TERMINAL // end }; enum AUDIT_CODE { #define X(code,value,description) \ code = value, IONU_AUDIT_CODES #undef X }; LIBEYE_DLL static EyeLog* GetInstance (); /** * Configure logging settings * @param client identifier * @param device identifier * @param level to log * @param sink to console, file, syslog... * @param format string to use for messages * @return true for success */ LIBEYE_DLL bool ConfigLogger (const std::string& client, const std::string& device, LOG_LEVEL level, LOG_SINK sink = IONU_CONSOLE, const std::string& format = ""); /** * Configure logging settings for file based logging * @param client identifier * @param device identifier * @param level to log * @param file to log to * @param sink to console, file, syslog... * @param format string to use for messages * @return true for success */ LIBEYE_DLL bool ConfigFileLogger (const char* client, const char* device, LOG_LEVEL level, const char* logfile, LOG_SINK sink = IONU_FILE, const char* format = ""); LIBEYE_DLL bool ConfigFileLogger (const std::string& client, const std::string& device, LOG_LEVEL level, const std::string& logfile, LOG_SINK sink = IONU_FILE, const std::string& format = ""); LIBEYE_DLL bool CloseLogger (void); LIBEYE_DLL bool CloseLogger (const std::string& logFile); void SetMaxLogFile (size_t bytes) { maxLogFileSize = bytes; } // Maximum size before we roll over to a new file void SetLogFiles (int files) { if (files > 1 && files < 100) maxLogFiles = files; } // Maximum number of logfiles to keep void SetLogLevel (LOG_LEVEL level) { logLevel = level; } // Client side methods /** * Start a new audit log * @param auditor public key * @param cache directory * @param callback to upload audit logs to server */ LIBEYE_DLL bool BeginAudit (const Key& auditorPublicKey, const std::string& auditCacheDir /*, uploadcallback() */); LIBEYE_DLL bool BeginAudit (const std::string& auditorPublicKey, const std::string& auditCacheDir /*, uploadcallback() */); /** * Log a message * @param level to log * @param msg to log * @return true for success */ LIBEYE_DLL bool Log (LOG_LEVEL level, std::string& msg); /** * Log an audit message * @param code to log * @param msg to log * @return true for success */ LIBEYE_DLL bool Audit (AUDIT_CODE code, std::string& msg); // Server side methods LIBEYE_DLL bool ReviewAudit (const Key& auditorPrivateKey, const std::string& auditFile); LIBEYE_DLL bool ReviewAudit (const std::string& auditorPrivateKey, const std::string& auditFile); LIBEYE_DLL bool ConsolidateAudit (const Key& auditorPrivateKey, const std::string& auditFile1, const std::string& auditFile2); protected: EyeLog (); ~EyeLog(); private: static EyeLog* _instance; // Singleton long long startTime; // Log creation time in mS for elapsed time (%e) format std::string clientId; // Short identfier, per message: "cgws", "sgws", "im", etc. for system and audit logs std::string deviceId; // Long identifier, per log file: device URN, device type (ipad/iphone), build #, etc. // Client control over logging LOG_LEVEL logLevel; // all log output (but not audit) omitted when > this level LOG_SINK localSink; // local device log sink LOG_FORMAT formatargs[6]; // arguments for log message format string std::string format; #ifdef WIN32 std::string sysLogFilename; // Windows has no system logger std::fstream sysLogFile; #endif // Local log file variables, used when localSink == LOG_FILE LOG_LEVEL logFileLevel; // all log output (but not audit) omitted when > this level std::string logFilename; // Base filename for LOG_FILE logging std::ofstream logFile; // Current logfile size_t maxLogFileSize; // Maximum size before we roll over to a new file int maxLogFiles; // maximum number of logfiles to keep size_t logFileSize; // Current logfile size // Auditing variables int auditId; // Audit message sequence number std::vector ids; // Usually just one client id, audit files may have multiple std::string auditCachePath; // local filesystem path for batch/caching of audit data std::fstream auditFile; // current audit cache file std::vector queue; // Queue of audit messages for verification Keyring* auditKeyring; // Public and/or private key plus AESHMAC key for encrypting this session Key* auditKey; // AESHMAC key #ifdef __APPLE__ aslclient aslClientHandle; // Apple system logger handle #endif void ProcessFormat (const std::string& fmt); const char* AuditCodeString (int auditcode); bool GetAuditKey (const Key& pk, const std::string& auditFilename); #ifdef LOG_TO_SYSLOG void SafeSyslog (int priority, std::string msg); #endif }; void logsprintf(std::string& msg, const char *s); #ifdef WIN32 // VS 2012 does not support variadic templates so use old dangerous va style code #define LOG_USE_VA_STYLE #endif #ifdef LOG_USE_VA_STYLE // VS 2012 does not support variadic templates so use old dangerous va style code #include void logvasprintf (std::string& msg, const char *fmt, va_list args); void logsprintf (std::string& msg, const char *fmt, ...); LIBEYE_DLL void LogWrapper (EyeLog::LOG_LEVEL level, const char *s, ...); LIBEYE_DLL void AuditWrapper (EyeLog::AUDIT_CODE code, const char *s, ...); #else template void logsprintf(std::string& msg, const char *s, T value, Args... args) { while (*s) { if (*s == '%' && *++s != '%') { std::stringstream stream; stream << value; msg += stream.str(); if (*s) logsprintf(msg, s + 1, args...); // peel of first argument return; } msg += *s++; } // Ignore extra arguments //printf ("extra arguments provided to EyeLog::Log\n"); } template void LogWrapper (EyeLog::LOG_LEVEL level, const char *s, Args... args) { if (s == NULL) return; std::string msg = ""; logsprintf (msg, s, args...); EyeLog::GetInstance()->Log (level, msg); } template void AuditWrapper (EyeLog::AUDIT_CODE code, const char *s, Args... args) { if (s == NULL) return; std::string msg = ""; logsprintf (msg, s, args...); EyeLog::GetInstance()->Audit (code, msg); } #endif } //namespace sequencelogic #endif