#include <list>
#include <security_utilities/globalizer.h>
#include <security_utilities/threading.h>
#include "eventlistener.h"
#include "SharedMemoryClient.h"
#include <notify.h>
#include "sscommon.h"
#include <sys/syslog.h>
using namespace MachPlusPlus;
namespace Security {
namespace SecurityServer {
typedef RefPointer<EventListener> EventPointer;
typedef std::list<EventPointer> EventListenerList;
static char* GetNotificationName ()
{
char* name = getenv (SECURITYSERVER_BOOTSTRAP_ENV);
if (name == NULL)
{
name = SECURITY_MESSAGES_NAME;
}
return name;
}
class SharedMemoryClientMaker
{
private:
SharedMemoryClient mClient;
public:
SharedMemoryClientMaker ();
SharedMemoryClient* Client ();
};
SharedMemoryClientMaker::SharedMemoryClientMaker () : mClient (GetNotificationName (), kSharedMemoryPoolSize)
{
}
SharedMemoryClient* SharedMemoryClientMaker::Client ()
{
return &mClient;
}
ModuleNexus<EventListenerList> gEventListeners;
ModuleNexus<Mutex> gNotificationLock;
ModuleNexus<SharedMemoryClientMaker> gMemoryClient;
class NotificationPort : public MachPlusPlus::CFAutoPort
{
protected:
SharedMemoryClient *mClient;
public:
NotificationPort (mach_port_t port);
virtual ~NotificationPort ();
virtual void receive(const MachPlusPlus::Message &msg);
};
NotificationPort::NotificationPort (mach_port_t mp) : CFAutoPort (mp)
{
mClient = gMemoryClient ().Client ();
}
NotificationPort::~NotificationPort ()
{
}
const int
kDomainOffset = 0,
kEventTypeOffset = kDomainOffset + sizeof (SegmentOffsetType),
kHeaderLength = kEventTypeOffset + sizeof (SegmentOffsetType);
void NotificationPort::receive (const MachPlusPlus::Message &msg)
{
u_int8_t buffer[kSharedMemoryPoolSize];
SegmentOffsetType length;
UnavailableReason ur;
while (mClient->ReadMessage (buffer, length, ur))
{
SecurityServer::NotificationDomain domain = (SecurityServer::NotificationDomain) OSSwapBigToHostInt32 (*(u_int32_t*) (buffer + kDomainOffset));
SecurityServer::NotificationEvent event = (SecurityServer::NotificationEvent) OSSwapBigToHostInt32 (*(u_int32_t*) (buffer + kEventTypeOffset));
CssmData data (buffer + kHeaderLength, length - kHeaderLength);
EventListenerList tempList;
{
StLock<Mutex> lock (gNotificationLock ());
tempList = gEventListeners();
}
EventListenerList::iterator it = tempList.begin ();
while (it != tempList.end ())
{
EventPointer ep = *it++;
if (ep->GetDomain () == domain &&
(ep->GetMask () & (1 << event)) != 0)
{
ep->consume (domain, event, data);
}
}
}
switch (ur)
{
case kURMessageDropped:
syslog(LOG_WARNING | LOG_AUTH, "Security message buffer overflowed.");
break;
case kURMessagePending:
syslog(LOG_DEBUG | LOG_AUTH, "Security message was pending (this may be normal)");
break;
case kURBufferCorrupt:
syslog(LOG_WARNING | LOG_AUTH, "Security message had an invalid length");
break;
default:
break;
}
}
class ThreadNotifier
{
protected:
NotificationPort *mNotificationPort;
int mNotifyToken;
public:
ThreadNotifier();
~ThreadNotifier();
};
ThreadNotifier::ThreadNotifier()
{
mach_port_t mp;
notify_register_mach_port (GetNotificationName (), &mp, 0, &mNotifyToken);
mNotificationPort = new NotificationPort (mp);
mNotificationPort->enable ();
}
ThreadNotifier::~ThreadNotifier()
{
notify_cancel (mNotifyToken);
delete mNotificationPort;
}
ModuleNexus<ThreadNexus<ThreadNotifier> > threadInfo;
static void InitializeNotifications ()
{
threadInfo()(); }
EventListener::EventListener (NotificationDomain domain, NotificationMask eventMask)
: mDomain (domain), mMask (eventMask)
{
StLock<Mutex> lock (gNotificationLock ());
InitializeNotifications ();
gEventListeners().push_back (this);
}
EventListener::~EventListener ()
{
StLock<Mutex> lock (gNotificationLock ());
EventListenerList::iterator it = std::find (gEventListeners ().begin (),
gEventListeners ().end (),
this);
if (it != gEventListeners ().end ())
{
gEventListeners ().erase (it);
}
}
} }