//
#include <security_utilities/errors.h>
#include <security_utilities/debugging.h>
+#include <security_utilities/utility_config.h>
+#include <security_utilities/debugging_internal.h>
#include <typeinfo>
#include <stdio.h>
#include <Security/SecBase.h>
+#include <Security/CSCommon.h>
+#include <execinfo.h>
+#include <cxxabi.h>
//@@@
// From cssmapple.h - layering break
//
// The base of the exception hierarchy.
-// Note that the debug output here depends on a particular
-// implementation feature of gcc; to wit, that the exception object
-// is created and then copied (at least once) via its copy constructor.
-// If your compiler does not invoke the copy constructor, you won't get
-// debug output, but nothing worse should happen.
//
-CommonError::CommonError()
+CommonError::CommonError() : whatBuffer("CommonError")
{
}
//
// We strongly encourage catching all exceptions by const reference, so the copy
// constructor of our exceptions should never be called.
-// We trace a copy to help catch violations of this rule.
//
CommonError::CommonError(const CommonError &source)
{
- SECURITY_EXCEPTION_COPY(this, &source);
+ strlcpy(whatBuffer, source.whatBuffer, whatBufferSize);
}
CommonError::~CommonError() throw ()
{
- SECURITY_EXCEPTION_HANDLED(this);
}
+void CommonError::LogBacktrace() {
+ // Only do this work if we're actually going to log things
+ if(secinfoenabled("security_exception")) {
+ const size_t maxsize = 32;
+ void* callstack[maxsize];
+
+ int size = backtrace(callstack, maxsize);
+ char** names = backtrace_symbols(callstack, size);
+
+ // C++ symbolicate the callstack
+
+ const char* delim = " ";
+ string build;
+ char * token = NULL;
+ char * line = NULL;
+
+ for(int i = 0; i < size; i++) {
+ build = "";
+
+ line = names[i];
+
+ while((token = strsep(&line, delim))) {
+ if(*token == '\0') {
+ build += " ";
+ } else {
+ int status = 0;
+ char * demangled = abi::__cxa_demangle(token, NULL, NULL, &status);
+ if(status == 0) {
+ build += demangled;
+ } else {
+ build += token;
+ }
+ build += " ";
+
+ if(demangled) {
+ free(demangled);
+ }
+ }
+ }
+
+ secinfo("security_exception", "%s", build.c_str());
+ }
+ free(names);
+ }
+}
+
+
//
// UnixError exceptions
//
UnixError::UnixError() : error(errno)
{
- SECURITY_EXCEPTION_THROW_UNIX(this, errno);
+ SECURITY_EXCEPTION_THROW_UNIX(this, errno);
+
+ snprintf(whatBuffer, whatBufferSize, "UNIX errno exception: %d", this->error);
+ secnotice("security_exception", "%s", what());
+ LogBacktrace();
}
-UnixError::UnixError(int err) : error(err)
+UnixError::UnixError(int err, bool suppresslogging) : error(err)
{
- SECURITY_EXCEPTION_THROW_UNIX(this, err);
+ SECURITY_EXCEPTION_THROW_UNIX(this, err);
+
+ if(!suppresslogging || secinfoenabled("security_exception")) {
+ snprintf(whatBuffer, whatBufferSize, "UNIX error exception: %d", this->error);
+ secnotice("security_exception", "%s", what());
+ LogBacktrace();
+ }
}
const char *UnixError::what() const throw ()
-{ return "UNIX error exception"; }
+{
+ return whatBuffer;
+}
OSStatus UnixError::osStatus() const
int UnixError::unixError() const
{ return error; }
-void UnixError::throwMe(int err) { throw UnixError(err); }
+void UnixError::throwMe(int err) { throw UnixError(err, false); }
+void UnixError::throwMeNoLogging(int err) { throw UnixError(err, true); }
+
// @@@ This is a hack for the Network protocol state machine
-UnixError UnixError::make(int err) { return UnixError(err); }
+UnixError UnixError::make(int err) { return UnixError(err, false); }
//
//
MacOSError::MacOSError(int err) : error(err)
{
- SECURITY_EXCEPTION_THROW_OSSTATUS(this, err);
+ SECURITY_EXCEPTION_THROW_OSSTATUS(this, err);
+
+ snprintf(whatBuffer, whatBufferSize, "MacOS error: %d", this->error);
+ switch (err) {
+ case errSecCSReqFailed:
+ // This 'error' isn't an actual error and doesn't warrant being logged.
+ break;
+ default:
+ secnotice("security_exception", "%s", what());
+ LogBacktrace();
+ }
}
const char *MacOSError::what() const throw ()
-{ return "MacOS error"; }
+{
+ return whatBuffer;
+}
OSStatus MacOSError::osStatus() const
{ return error; }
void MacOSError::throwMe(int error)
{ throw MacOSError(error); }
+void MacOSError::throwMe(int error, char const *message, ...)
+{
+ // Ignoring the message for now, will do something with it later.
+ throw MacOSError(error);
+}
+
MacOSError MacOSError::make(int error)
{ return MacOSError(error); }
//
CFError::CFError()
{
- SECURITY_EXCEPTION_THROW_CF(this);
+ SECURITY_EXCEPTION_THROW_CF(this);
+ secnotice("security_exception", "CFError");
+ LogBacktrace();
}
const char *CFError::what() const throw ()