diff --git a/security/manager/ssl/src/nsNSSEvent.cpp b/security/manager/ssl/src/nsNSSEvent.cpp new file mode 100644 index 00000000000..8c9ac26b977 --- /dev/null +++ b/security/manager/ssl/src/nsNSSEvent.cpp @@ -0,0 +1,97 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 2001 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Javier Delgadillo + * Bob Relyea + */ +#include "nsCOMPtr.h" +#include "nsIServiceManager.h" +#include "nsNSSEvent.h" +#include "plevent.h" +#include "nsIRunnable.h" +#include "nsIEventQueueService.h" +#include "nsIEventQueue.h" + +// +// This is the class we'll use to post ui events +// +struct nsNSSEventRunnable : PLEvent { + nsNSSEventRunnable(nsIRunnable* runnable); + ~nsNSSEventRunnable(); + + nsCOMPtr mRunnable; +}; + +//Grab the UI event queue so that we can post some events to it. +already_AddRefed +nsNSSEventGetUIEventQueue() +{ + nsresult rv; + nsCOMPtr service = + do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) + return nsnull; + + nsIEventQueue* result = nsnull; + rv = service->GetThreadEventQueue(NS_UI_THREAD, &result); + if (NS_FAILED(rv)) + return nsnull; + + return result; +} + +// post something to it +nsresult +nsNSSEventPostToUIEventQueue(nsIRunnable *event) +{ + nsNSSEventRunnable *runnable = new nsNSSEventRunnable(event); + if (!runnable) { + return NS_ERROR_OUT_OF_MEMORY; + } + nsCOMPtruiQueue = nsNSSEventGetUIEventQueue(); + uiQueue->PostEvent(runnable); + return NS_OK; +} + +//A wrapper for PLEvent that we can use to post +//our nsIRunnable Events. +static void PR_CALLBACK +handleNSSEventRunnable(nsNSSEventRunnable* aEvent) +{ + aEvent->mRunnable->Run(); +} + +static void PR_CALLBACK +destroyNSSEventRunnable(nsNSSEventRunnable* aEvent) +{ + delete aEvent; +} + +nsNSSEventRunnable::nsNSSEventRunnable(nsIRunnable* runnable) + : mRunnable(runnable) +{ + PL_InitEvent(this, nsnull, PLHandleEventProc(handleNSSEventRunnable), + PLDestroyEventProc(&destroyNSSEventRunnable)); +} + +nsNSSEventRunnable::~nsNSSEventRunnable() +{ +} + diff --git a/security/manager/ssl/src/nsNSSEvent.h b/security/manager/ssl/src/nsNSSEvent.h new file mode 100644 index 00000000000..9c29f1c584c --- /dev/null +++ b/security/manager/ssl/src/nsNSSEvent.h @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Javier Delgadillo + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + * Contributor(s): + * Javier Delgadillo + * Bob Relyea + */ + +#ifndef NSS_EVENT_ +#define NSS_EVENT_ + +#include "nsIRunnable.h" +#include "nsIEventQueueService.h" +#include "nsIEventQueue.h" + + +//Grab the UI event queue so that we can post some events to it. +already_AddRefed nsNSSEventGetUIEventQueue(); + +// post something to it +nsresult nsNSSEventPostToUIEventQueue(nsIRunnable *event); + +#endif + diff --git a/security/manager/ssl/src/nsSmartCardEvent.cpp b/security/manager/ssl/src/nsSmartCardEvent.cpp new file mode 100644 index 00000000000..b9c4f6f5de3 --- /dev/null +++ b/security/manager/ssl/src/nsSmartCardEvent.cpp @@ -0,0 +1,245 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the NPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsSmartCardEvent.h" +#include "nsIDOMSmartCardEvent.h" +#include "nsIDOMClassInfo.h" +#include "nsIDOMNSEvent.h" +#include "nsIDOMEvent.h" +#include "nsXPCOM.h" + +// DOM event class to handle progress notifications +nsSmartCardEvent::nsSmartCardEvent(const nsAString &aTokenName) + : mTokenName(aTokenName), mInner(nsnull), mPrivate(nsnull) +{ +} + +nsSmartCardEvent::~nsSmartCardEvent() +{} + +//NS_DECL_DOM_CLASSINFO(SmartCardEvent) + +// QueryInterface implementation for nsXMLHttpRequest +NS_INTERFACE_MAP_BEGIN(nsSmartCardEvent) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMSmartCardEvent) + NS_INTERFACE_MAP_ENTRY(nsIDOMSmartCardEvent) + NS_INTERFACE_MAP_ENTRY(nsIDOMNSEvent) + NS_INTERFACE_MAP_ENTRY(nsIDOMEvent) + NS_INTERFACE_MAP_ENTRY(nsIPrivateDOMEvent) + NS_INTERFACE_MAP_ENTRY_DOM_CLASSINFO(SmartCardEvent) +NS_INTERFACE_MAP_END + +NS_IMPL_ADDREF(nsSmartCardEvent) +NS_IMPL_RELEASE(nsSmartCardEvent) + +// +// Init must be called before we do anything with the event. +// +NS_IMETHODIMP nsSmartCardEvent::Init(nsIDOMEvent * aInner) +{ + nsresult rv; + + NS_ASSERTION(aInner, "SmartCardEvent initialized with a null Event"); + mInner = aInner; + mPrivate = do_QueryInterface(mInner, &rv); + if (NS_FAILED(rv)) { + return rv; + } + mNSEvent = do_QueryInterface(mInner, &rv); + if (NS_FAILED(rv)) { + return rv; + } + return mPrivate->SetTrusted(PR_TRUE); +} + +// nsSmartCard Specific methods +NS_IMETHODIMP nsSmartCardEvent::GetTokenName(nsAString &aTokenName) +{ + aTokenName = mTokenName; + return NS_OK; +} + +// nsIPrivateDOMEvent maps +NS_IMETHODIMP nsSmartCardEvent::DuplicatePrivateData(void) +{ + NS_ASSERTION(mPrivate, "SmartCardEvent called without Init"); + return mPrivate->DuplicatePrivateData(); +} + +NS_IMETHODIMP nsSmartCardEvent::SetTarget(nsIDOMEventTarget *aTarget) +{ + NS_ASSERTION(mPrivate, "SmartCardEvent called without Init"); + return mPrivate->SetTarget(aTarget); +} + +NS_IMETHODIMP nsSmartCardEvent::SetCurrentTarget(nsIDOMEventTarget *aTarget) +{ + NS_ASSERTION(mPrivate, "SmartCardEvent called without Init"); + return mPrivate->SetCurrentTarget(aTarget); +} + +NS_IMETHODIMP nsSmartCardEvent::SetOriginalTarget(nsIDOMEventTarget *aTarget) +{ + NS_ASSERTION(mPrivate, "SmartCardEvent called without Init"); + return mPrivate->SetOriginalTarget(aTarget); +} + +NS_IMETHODIMP nsSmartCardEvent::IsDispatchStopped(PRBool *aIsDispatchPrevented) +{ + NS_ASSERTION(mPrivate, "SmartCardEvent called without Init"); + return mPrivate->IsDispatchStopped(aIsDispatchPrevented); +} + +NS_IMETHODIMP nsSmartCardEvent::GetInternalNSEvent(nsEvent** aNSEvent) +{ + NS_ASSERTION(mPrivate, "SmartCardEvent called without Init"); + return mPrivate->GetInternalNSEvent(aNSEvent); +} + +NS_IMETHODIMP nsSmartCardEvent::HasOriginalTarget(PRBool *aResult) +{ + NS_ASSERTION(mPrivate, "SmartCardEvent called without Init"); + return mPrivate->HasOriginalTarget(aResult); +} + +NS_IMETHODIMP nsSmartCardEvent::SetTrusted(PRBool aResult) +{ + NS_ASSERTION(mPrivate, "SmartCardEvent called without Init"); + return mPrivate->SetTrusted(aResult); +} + + +// IDOMNSEvent maps +NS_IMETHODIMP nsSmartCardEvent::GetOriginalTarget(nsIDOMEventTarget * *aOriginalTarget) +{ + NS_ASSERTION(mNSEvent, "SmartCardEvent called without Init"); + return mNSEvent->GetOriginalTarget(aOriginalTarget); +} + +NS_IMETHODIMP nsSmartCardEvent::GetExplicitOriginalTarget(nsIDOMEventTarget * *aTarget) +{ + NS_ASSERTION(mNSEvent, "SmartCardEvent called without Init"); + return mNSEvent->GetExplicitOriginalTarget(aTarget); +} + +NS_IMETHODIMP nsSmartCardEvent::GetTmpRealOriginalTarget(nsIDOMEventTarget * *aTarget) +{ + NS_ASSERTION(mNSEvent, "SmartCardEvent called without Init"); + return mNSEvent->GetTmpRealOriginalTarget(aTarget); +} + +NS_IMETHODIMP nsSmartCardEvent::PreventBubble(void) +{ + NS_ASSERTION(mNSEvent, "SmartCardEvent called without Init"); + return mNSEvent->PreventBubble(); +} + +NS_IMETHODIMP nsSmartCardEvent::PreventCapture(void) +{ + NS_ASSERTION(mNSEvent, "SmartCardEvent called without Init"); + return mNSEvent->PreventCapture(); +} + +NS_IMETHODIMP nsSmartCardEvent::GetIsTrusted(PRBool *aIsTrusted) +{ + NS_ASSERTION(mNSEvent, "SmartCardEvent called without Init"); + return mNSEvent->GetIsTrusted(aIsTrusted); +} + + +// IDOMEvent maps +NS_IMETHODIMP nsSmartCardEvent::GetType(nsAString & aType) +{ + NS_ASSERTION(mInner, "SmartCardEvent called without Init"); + return mInner->GetType(aType); +} + +NS_IMETHODIMP nsSmartCardEvent::GetTarget(nsIDOMEventTarget * *aTarget) +{ + NS_ASSERTION(mInner, "SmartCardEvent called without Init"); + return mInner->GetTarget(aTarget); +} + +NS_IMETHODIMP nsSmartCardEvent::GetCurrentTarget(nsIDOMEventTarget * *aCurrentTarget) +{ + NS_ASSERTION(mInner, "SmartCardEvent called without Init"); + return mInner->GetCurrentTarget(aCurrentTarget); +} + +NS_IMETHODIMP nsSmartCardEvent::GetEventPhase(PRUint16 *aEventPhase) +{ + NS_ASSERTION(mInner, "SmartCardEvent called without Init"); + return mInner->GetEventPhase(aEventPhase); +} + +NS_IMETHODIMP nsSmartCardEvent::GetBubbles(PRBool *aBubbles) +{ + NS_ASSERTION(mInner, "SmartCardEvent called without Init"); + return mInner->GetBubbles(aBubbles); +} + +NS_IMETHODIMP nsSmartCardEvent::GetCancelable(PRBool *aCancelable) +{ + NS_ASSERTION(mInner, "SmartCardEvent called without Init"); + return mInner->GetCancelable(aCancelable); +} + +NS_IMETHODIMP nsSmartCardEvent::GetTimeStamp(DOMTimeStamp *aTimeStamp) +{ + NS_ASSERTION(mInner, "SmartCardEvent called without Init"); + return mInner->GetTimeStamp(aTimeStamp); +} + +NS_IMETHODIMP nsSmartCardEvent::StopPropagation() +{ + NS_ASSERTION(mInner, "SmartCardEvent called without Init"); + return mInner->StopPropagation(); +} + +NS_IMETHODIMP nsSmartCardEvent::PreventDefault() +{ + NS_ASSERTION(mInner, "SmartCardEvent called without Init"); + return mInner->PreventDefault(); +} + +NS_IMETHODIMP nsSmartCardEvent::InitEvent(const nsAString & eventTypeArg, PRBool canBubbleArg, PRBool cancelableArg) +{ + NS_ASSERTION(mInner, "SmartCardEvent called without Init"); + return mInner->InitEvent(eventTypeArg, canBubbleArg, cancelableArg); +} + diff --git a/security/manager/ssl/src/nsSmartCardEvent.h b/security/manager/ssl/src/nsSmartCardEvent.h new file mode 100644 index 00000000000..02e91e308f7 --- /dev/null +++ b/security/manager/ssl/src/nsSmartCardEvent.h @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the NPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsSmartCardEvent_h_ +#define nsSmartCardEvent_h_ + +#include "nsIDOMSmartCardEvent.h" +#include "nsIDOMEvent.h" +#include "nsIDOMNSEvent.h" +#include "nsIPrivateDOMEvent.h" +#include "nsCOMPtr.h" +#include "nsString.h" +#include "nsXPCOM.h" + +// Expose SmartCard Specific paramenters to smart card events. +class nsSmartCardEvent : public nsIDOMSmartCardEvent, + public nsIDOMNSEvent, + public nsIPrivateDOMEvent +{ +public: + nsSmartCardEvent(const nsAString &aTokenName); + virtual ~nsSmartCardEvent(); + + + NS_DECL_ISUPPORTS + NS_DECL_NSIDOMSMARTCARDEVENT + NS_DECL_NSIDOMNSEVENT + + //NS_DECL_NSIPRIVATEDOMEEVENT + NS_IMETHOD DuplicatePrivateData(); + NS_IMETHOD SetTarget(nsIDOMEventTarget *aTarget); + NS_IMETHOD SetCurrentTarget(nsIDOMEventTarget *aTarget); + NS_IMETHOD SetOriginalTarget(nsIDOMEventTarget *aTarget); + NS_IMETHOD GetInternalNSEvent(nsEvent** aNSEvent); + NS_IMETHOD IsDispatchStopped(PRBool *aIsDispatchPrevented); + NS_IMETHOD HasOriginalTarget(PRBool *aResult); + NS_IMETHOD SetTrusted(PRBool aResult); + + NS_DECL_NSIDOMEVENT + +protected: + nsCOMPtr mInner; + nsCOMPtr mPrivate; + nsCOMPtr mNSEvent; + nsString mTokenName; +}; + +#define SMARTCARDEVENT_INSERT "smartcard-insert" +#define SMARTCARDEVENT_REMOVE "smartcard-remove" + +#endif diff --git a/security/manager/ssl/src/nsSmartCardMonitor.cpp b/security/manager/ssl/src/nsSmartCardMonitor.cpp new file mode 100644 index 00000000000..0cd904591c3 --- /dev/null +++ b/security/manager/ssl/src/nsSmartCardMonitor.cpp @@ -0,0 +1,358 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Contributed by Red Hat Inc. + * + * The Initial Developer of the Original Code is + * Red Hat, Inc. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#include "nspr.h" + +#include "pk11func.h" +#include "nsNSSComponent.h" +#include "nsSmartCardMonitor.h" +#include "nsSmartCardEvent.h" + +// +// The SmartCard monitoring thread should start up for each module we load +// that has removable tokens. This code calls an NSS function which waits +// until there is a change in the token state. NSS uses the +// C_WaitForSlotEvent() call in PKCS #11 if the module implements the call, +// otherwise NSS will poll the token in a loop with a delay of 'latency' +// between polls. Note that the C_WaitForSlotEvent() may wake up on any type +// of token event, so it's necessary to filter these events down to just the +// insertion and removal events we are looking for. +// +// Once the event is found, It is passed to nsNSSComponent for dispatching +// on the UI thread, and forwarding to any interested listeners (including +// javascript). +// + + +static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); + +#include + +// self linking and removing double linked entry +// adopts the thread it is passed. +class SmartCardThreadEntry { +public: + SmartCardThreadEntry *next; + SmartCardThreadEntry *prev; + SmartCardThreadEntry **head; + SmartCardMonitoringThread *thread; + SmartCardThreadEntry(SmartCardMonitoringThread *thread_, + SmartCardThreadEntry *next_, SmartCardThreadEntry *prev_, + SmartCardThreadEntry **head_) : + next(next_), prev(prev_), head(head_), thread(thread_) { + if (prev) { prev->next = this; } else { *head = this; } + if (next) { next->prev = this; } + } + ~SmartCardThreadEntry() { + if (prev) { prev->next = next; } else { *head = next; } + if (next) { next->prev = prev; } + // NOTE: automatically stops the thread + delete thread; + } +}; + +// +// SmartCardThreadList is a class to help manage the running threads. +// That way new threads could be started and old ones terminated as we +// load and unload modules. +// +SmartCardThreadList::SmartCardThreadList() : head(0) +{ +} + +SmartCardThreadList::~SmartCardThreadList() +{ + // the head is self linking and unlinking, the following + // loop removes all entries on the list. + // it will also stop the thread if it happens to be running + while (head) { + delete head; + } +} + +void +SmartCardThreadList::Remove(SECMODModule *aModule) +{ + SmartCardThreadEntry *current; + for (current = head; current; current=current->next) { + if (current->thread->GetModule() == aModule) { + // NOTE: automatically stops the thread and dequeues it from the list + delete current; + return; + } + } +} + +// adopts the thread passwd to it. Starts the thread as well +nsresult +SmartCardThreadList::Add(SmartCardMonitoringThread *thread) +{ + SmartCardThreadEntry *current = new SmartCardThreadEntry(thread, head, nsnull, + &head); + if (current) { + // OK to forget current here, it's on the list + return thread->Start(); + } + return NS_ERROR_OUT_OF_MEMORY; +} + + +// We really should have a Unity PL Hash function... +static PR_CALLBACK PLHashNumber +unity(const void *key) { return (PLHashNumber)key; } + +SmartCardMonitoringThread::SmartCardMonitoringThread(SECMODModule *module_) + : mThread(nsnull) +{ + mModule = SECMOD_ReferenceModule(module_); + // simple hash functions, most modules have less than 3 slots, so 10 buckets + // should be plenty + mHash = PL_NewHashTable(10, unity, PL_CompareValues, + PL_CompareStrings, nsnull, 0); +} + +// +// when we shutdown the thread, be sure to stop it first. If not, it just might +// crash when the mModule it is looking at disappears. +// +SmartCardMonitoringThread::~SmartCardMonitoringThread() +{ + Stop(); + SECMOD_DestroyModule(mModule); + if (mHash) { + PL_HashTableDestroy(mHash); + } +} + +nsresult +SmartCardMonitoringThread::Start() +{ + if (!mThread) { + mThread = PR_CreateThread(PR_SYSTEM_THREAD, LaunchExecute, this, + PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, + PR_JOINABLE_THREAD, 0); + } + return mThread ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +// +// Should only stop if we are through with the module. +// CancelWait has the side effect of losing all the keys and +// current operations on the module!. (See the comment in +// SECMOD_CancelWait for why this is so..). +// +void SmartCardMonitoringThread::Stop() +{ + SECStatus rv; + + rv = SECMOD_CancelWait(mModule); + if (rv != SECSuccess) { + // we didn't wake up the Wait, so don't try to join the thread + // otherwise we will hang forever... + return; + } + + // confused about the memory model here? NSPR owns the memory for + // threads. non-joinable threads are freed when the thread dies. + // joinable threads are freed after the call to PR_JoinThread. + // That means if SECMOD_CancelWait fails, we'll leak the mThread + // structure. this is considered preferable to hanging (which is + // what will happen if we try to join a thread that blocked). + if (mThread) { + PR_JoinThread(mThread); + mThread = 0; + } +} + +// +// remember the name and series of a token in a particular slot. +// This is important because the name is no longer available when +// the token is removed. If listeners depended on this information, +// They would be out of luck. It also is a handy way of making sure +// we don't generate spurious insertion and removal events as the slot +// cycles through various states. +// +void +SmartCardMonitoringThread::SetTokenName(CK_SLOT_ID slotid, + const char *tokenName, PRUint32 series) +{ + if (mHash) { + if (tokenName) { + int len = strlen(tokenName) + 1; + char *entry = (char *)malloc(len+sizeof(PRUint32)); + + if (entry) { + memcpy(entry,&series,sizeof(PRUint32)); + memcpy(&entry[sizeof(PRUint32)],tokenName,len); + + PL_HashTableAdd(mHash,(void *)slotid, entry); /* adopt */ + return; + } + } + // if tokenName was not provided, remove the old one (implicit delete) + PL_HashTableRemove(mHash,(void *)slotid); + } +} + +// retrieve the name saved above +const char * +SmartCardMonitoringThread::GetTokenName(CK_SLOT_ID slotid) +{ + const char *tokenName = nsnull; + const char *entry; + + if (mHash) { + entry = (const char *)PL_HashTableLookupConst(mHash,(void *)slotid); + if (entry) { + tokenName = &entry[sizeof(PRUint32)]; + } + } + return tokenName; +} + +// retrieve the series saved in SetTokenName above +PRUint32 +SmartCardMonitoringThread::GetTokenSeries(CK_SLOT_ID slotid) +{ + PRUint32 series = 0; + const char *entry; + + if (mHash) { + entry = (const char *)PL_HashTableLookupConst(mHash,(void *)slotid); + if (entry) { + memcpy(&series,entry,sizeof(PRUint32)); + } + } + return series; +} + +// +// helper function to pass the event off to nsNSSComponent. +// +nsresult +SmartCardMonitoringThread::SendEvent(const nsAString &eventType, + const char *tokenName) +{ + nsresult rv; + nsCOMPtr + nssComponent(do_GetService(kNSSComponentCID, &rv)); + if (NS_FAILED(rv)) + return rv; + + // NSS returns actual UTF8, not ASCII + nssComponent->PostEvent(eventType, NS_ConvertUTF8toUTF16(tokenName)); + return NS_OK; +} + +// +// This is the main loop. +// +void SmartCardMonitoringThread::Execute() +{ + PK11SlotInfo *slot; + const char *tokenName = nsnull; + + // + // populate token names for already inserted tokens. + // + PK11SlotList *sl = + PK11_FindSlotsByNames(mModule->dllName, nsnull, nsnull, PR_TRUE); + PK11SlotListElement *sle; + + if (sl) { + for (sle=PK11_GetFirstSafe(sl); sle; + sle=PK11_GetNextSafe(sl,sle,PR_FALSE)) { + SetTokenName(PK11_GetSlotID(sle->slot), + PK11_GetTokenName(sle->slot), PK11_GetSlotSeries(sle->slot)); + } + PK11_FreeSlotList(sl); + } + + // loop starts.. + do { + slot = SECMOD_WaitForAnyTokenEvent(mModule, 0, PR_SecondsToInterval(1) ); + if (slot == nsnull) { + break; + } + + // now we have a potential insertion or removal event, see if the slot + // is present to determine which it is... + if (PK11_IsPresent(slot)) { + // insertion + CK_SLOT_ID slotID = PK11_GetSlotID(slot); + PRUint32 series = PK11_GetSlotSeries(slot); + + // skip spurious insertion events... + if (series != GetTokenSeries(slotID)) { + // if there's a token name, then we have not yet issued a remove + // event for the previous token, do so now... + tokenName = GetTokenName(slotID); + if (tokenName) { + SendEvent(NS_LITERAL_STRING(SMARTCARDEVENT_REMOVE), tokenName); + } + tokenName = PK11_GetTokenName(slot); + // save the token name and series + SetTokenName(slotID, tokenName, series); + SendEvent(NS_LITERAL_STRING(SMARTCARDEVENT_INSERT), tokenName); + } + } else { + // retrieve token name + CK_SLOT_ID slotID = PK11_GetSlotID(slot); + tokenName = GetTokenName(slotID); + // if there's not a token name, then the software isn't expecting + // a (or another) remove event. + if (tokenName) { + SendEvent(NS_LITERAL_STRING(SMARTCARDEVENT_REMOVE), tokenName); + // clear the token name (after we send it) + SetTokenName(slotID, nsnull, 0); + } + } + PK11_FreeSlot(slot); + + } while (1); +} + +// accessor to help searching active Monitoring threads +const SECMODModule * SmartCardMonitoringThread::GetModule() +{ + return mModule; +} + +// C-like calling sequence to glue into PR_CreateThread. +void SmartCardMonitoringThread::LaunchExecute(void *arg) +{ + ((SmartCardMonitoringThread*)arg)->Execute(); +} + diff --git a/security/manager/ssl/src/nsSmartCardMonitor.h b/security/manager/ssl/src/nsSmartCardMonitor.h new file mode 100644 index 00000000000..6ad2f88bf40 --- /dev/null +++ b/security/manager/ssl/src/nsSmartCardMonitor.h @@ -0,0 +1,94 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Contributed by Red Hat Inc. + * + * The Initial Developer of the Original Code is + * Red Hat, Inc. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#ifndef _NSSMARTCARDMONITOR_ +#define _NSSMARTCARDMONITOR_ + +#include "prthread.h" +#include "secmod.h" +#include "plhash.h" +#include "pkcs11t.h" + +class SmartCardThreadEntry; +class SmartCardMonitoringThread; + +// +// manage a group of SmartCardMonitoringThreads +// +class SmartCardThreadList { +public: + SmartCardThreadList(); + ~SmartCardThreadList(); + void Remove(SECMODModule *module); + nsresult Add(SmartCardMonitoringThread *thread); +private: + SmartCardThreadEntry *head; +}; + +// +// monitor a Module for token insertion and removal +// +// NOTE: this provides the application the ability to dynamically add slots +// on the fly as necessary. +// +class SmartCardMonitoringThread +{ + public: + SmartCardMonitoringThread(SECMODModule *module); + ~SmartCardMonitoringThread(); + + nsresult Start(); + void Stop(); + + void Execute(); + void Interrupt(); + + const SECMODModule *GetModule(); + + private: + + static void LaunchExecute(void *arg); + void SetTokenName(CK_SLOT_ID slotid, const char *tokenName, PRUint32 series); + const char *GetTokenName(CK_SLOT_ID slotid); + PRUint32 GetTokenSeries(CK_SLOT_ID slotid); + nsresult SendEvent(const nsAString &type,const char *tokenName); + + + SECMODModule *mModule; + PLHashTable *mHash; + PRThread* mThread; +}; + +#endif