LCOV - code coverage report
Current view: directory - security/manager/ssl/src - nsSmartCardMonitor.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 112 0 0.0 %
Date: 2012-06-02 Functions: 18 0 0.0 %

       1                 : /* ***** BEGIN LICENSE BLOCK *****
       2                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       3                 :  *
       4                 :  * The contents of this file are subject to the Mozilla Public License Version
       5                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       6                 :  * the License. You may obtain a copy of the License at
       7                 :  * http://www.mozilla.org/MPL/
       8                 :  *
       9                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      10                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      11                 :  * for the specific language governing rights and limitations under the
      12                 :  * License.
      13                 :  *
      14                 :  * The Original Code is Contributed by Red Hat Inc.
      15                 :  *
      16                 :  * The Initial Developer of the Original Code is
      17                 :  * Red Hat, Inc.
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2005
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *
      23                 :  * Alternatively, the contents of this file may be used under the terms of
      24                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      25                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      26                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      27                 :  * of those above. If you wish to allow use of your version of this file only
      28                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      29                 :  * use your version of this file under the terms of the MPL, indicate your
      30                 :  * decision by deleting the provisions above and replace them with the notice
      31                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      32                 :  * the provisions above, a recipient may use your version of this file under
      33                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      34                 :  *
      35                 :  * ***** END LICENSE BLOCK ***** */
      36                 : #include "nspr.h"
      37                 : 
      38                 : #include "pk11func.h"
      39                 : #include "nsNSSComponent.h"
      40                 : #include "nsSmartCardMonitor.h"
      41                 : #include "nsSmartCardEvent.h"
      42                 : 
      43                 : //
      44                 : // The SmartCard monitoring thread should start up for each module we load
      45                 : // that has removable tokens. This code calls an NSS function which waits
      46                 : // until there is a change in the token state. NSS uses the 
      47                 : // C_WaitForSlotEvent() call in PKCS #11 if the module implements the call,
      48                 : // otherwise NSS will poll the token in a loop with a delay of 'latency' 
      49                 : // between polls. Note that the C_WaitForSlotEvent() may wake up on any type
      50                 : // of token event, so it's necessary to filter these events down to just the
      51                 : // insertion and removal events we are looking for.
      52                 : //
      53                 : // Once the event is found, It is passed to nsNSSComponent for dispatching
      54                 : // on the UI thread, and forwarding to any interested listeners (including
      55                 : // javascript).
      56                 : //
      57                 : 
      58                 : 
      59                 : static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
      60                 : 
      61                 : #include <assert.h>
      62                 : 
      63                 : // self linking and removing double linked entry
      64                 : // adopts the thread it is passed.
      65                 : class SmartCardThreadEntry {
      66                 : public:
      67                 :  SmartCardThreadEntry *next;
      68                 :  SmartCardThreadEntry *prev;
      69                 :  SmartCardThreadEntry **head;
      70                 :  SmartCardMonitoringThread *thread;
      71               0 :  SmartCardThreadEntry(SmartCardMonitoringThread *thread_,
      72                 :    SmartCardThreadEntry *next_, SmartCardThreadEntry *prev_,
      73                 :    SmartCardThreadEntry **head_) : 
      74               0 :    next(next_), prev(prev_), head(head_), thread(thread_) { 
      75               0 :     if (prev) { prev->next = this; } else { *head = this; }
      76               0 :     if (next) { next->prev = this; }
      77               0 :   }
      78               0 :   ~SmartCardThreadEntry() {
      79               0 :     if (prev) { prev->next = next; } else { *head = next; }
      80               0 :     if (next) { next->prev = prev; }
      81                 :     // NOTE: automatically stops the thread
      82               0 :     delete thread;
      83               0 :   }
      84                 : };
      85                 : 
      86                 : //
      87                 : // SmartCardThreadList is a class to help manage the running threads.
      88                 : // That way new threads could be started and old ones terminated as we
      89                 : // load and unload modules.
      90                 : //
      91               0 : SmartCardThreadList::SmartCardThreadList() : head(0)
      92                 : {
      93               0 : }
      94                 : 
      95               0 : SmartCardThreadList::~SmartCardThreadList()
      96                 : {
      97                 :   // the head is self linking and unlinking, the following
      98                 :   // loop removes all entries on the list.
      99                 :   // it will also stop the thread if it happens to be running
     100               0 :   while (head) {
     101               0 :     delete head;
     102                 :   }
     103               0 : }
     104                 : 
     105                 : void
     106               0 : SmartCardThreadList::Remove(SECMODModule *aModule)
     107                 : {
     108                 :   SmartCardThreadEntry *current;
     109               0 :   for (current = head; current; current=current->next) {
     110               0 :     if (current->thread->GetModule() == aModule) {
     111                 :       // NOTE: automatically stops the thread and dequeues it from the list
     112               0 :       delete current;
     113               0 :       return;
     114                 :     }
     115                 :   }
     116                 : }
     117                 : 
     118                 : // adopts the thread passwd to it. Starts the thread as well
     119                 : nsresult
     120               0 : SmartCardThreadList::Add(SmartCardMonitoringThread *thread)
     121                 : {
     122                 :   SmartCardThreadEntry *current = new SmartCardThreadEntry(thread, head, nsnull,
     123               0 :                                                            &head);
     124               0 :   if (current) {  
     125                 :      // OK to forget current here, it's on the list
     126               0 :     return thread->Start();
     127                 :   }
     128               0 :   return NS_ERROR_OUT_OF_MEMORY;
     129                 : }
     130                 : 
     131                 : 
     132                 : // We really should have a Unity PL Hash function...
     133                 : static PR_CALLBACK PLHashNumber
     134               0 : unity(const void *key) { return PLHashNumber(NS_PTR_TO_INT32(key)); }
     135                 : 
     136               0 : SmartCardMonitoringThread::SmartCardMonitoringThread(SECMODModule *module_)
     137               0 :   : mThread(nsnull)
     138                 : {
     139               0 :   mModule = SECMOD_ReferenceModule(module_);
     140                 :   // simple hash functions, most modules have less than 3 slots, so 10 buckets
     141                 :   // should be plenty
     142                 :   mHash = PL_NewHashTable(10, unity, PL_CompareValues, 
     143               0 :                            PL_CompareStrings, nsnull, 0);
     144               0 : }
     145                 : 
     146                 : //
     147                 : // when we shutdown the thread, be sure to stop it first. If not, it just might
     148                 : // crash when the mModule it is looking at disappears.
     149                 : //
     150               0 : SmartCardMonitoringThread::~SmartCardMonitoringThread()
     151                 : {
     152               0 :   Stop();
     153               0 :   SECMOD_DestroyModule(mModule);
     154               0 :   if (mHash) {
     155               0 :     PL_HashTableDestroy(mHash);
     156                 :   }
     157               0 : }
     158                 : 
     159                 : nsresult
     160               0 : SmartCardMonitoringThread::Start()
     161                 : {
     162               0 :   if (!mThread) {
     163                 :     mThread = PR_CreateThread(PR_SYSTEM_THREAD, LaunchExecute, this,
     164                 :                               PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
     165               0 :                               PR_JOINABLE_THREAD, 0);
     166                 :   }
     167               0 :   return mThread ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
     168                 : }
     169                 : 
     170                 : //
     171                 : // Should only stop if we are through with the module.
     172                 : // CancelWait has the side effect of losing all the keys and
     173                 : // current operations on the module!. (See the comment in
     174                 : // SECMOD_CancelWait for why this is so..).
     175                 : //
     176               0 : void SmartCardMonitoringThread::Stop()
     177                 : {
     178                 :   SECStatus rv;
     179                 : 
     180               0 :   rv = SECMOD_CancelWait(mModule);
     181               0 :   if (rv != SECSuccess) {
     182                 :     // we didn't wake up the Wait, so don't try to join the thread 
     183                 :     // otherwise we will hang forever...
     184               0 :     return;
     185                 :   }
     186                 :  
     187                 :   // confused about the memory model here? NSPR owns the memory for
     188                 :   // threads. non-joinable threads are freed when the thread dies.
     189                 :   // joinable threads are freed after the call to PR_JoinThread.
     190                 :   // That means if SECMOD_CancelWait fails, we'll leak the mThread
     191                 :   // structure. this is considered preferable to hanging (which is
     192                 :   // what will happen if we try to join a thread that blocked).
     193               0 :   if (mThread) {
     194               0 :     PR_JoinThread(mThread);
     195               0 :     mThread = 0; 
     196                 :   }
     197                 : }
     198                 : 
     199                 : //
     200                 : // remember the name and series of a token in a particular slot.
     201                 : // This is important because the name is no longer available when
     202                 : // the token is removed. If listeners depended on this information,
     203                 : // They would be out of luck. It also is a handy way of making sure
     204                 : // we don't generate spurious insertion and removal events as the slot
     205                 : // cycles through various states.
     206                 : //
     207                 : void
     208               0 : SmartCardMonitoringThread::SetTokenName(CK_SLOT_ID slotid, 
     209                 :                                        const char *tokenName, PRUint32 series)
     210                 : {
     211               0 :   if (mHash) {
     212               0 :     if (tokenName) {
     213               0 :       int len = strlen(tokenName) + 1;
     214                 :       /* this must match the allocator used in
     215                 :        * PLHashAllocOps.freeEntry DefaultFreeEntry */
     216               0 :       char *entry = (char *)PR_Malloc(len+sizeof(PRUint32));
     217                 :      
     218               0 :       if (entry) {  
     219               0 :         memcpy(entry,&series,sizeof(PRUint32));
     220               0 :         memcpy(&entry[sizeof(PRUint32)],tokenName,len);
     221                 : 
     222               0 :         PL_HashTableAdd(mHash,(void *)slotid, entry); /* adopt */
     223               0 :         return;
     224                 :       }
     225                 :     } 
     226                 :     else {
     227                 :       // if tokenName was not provided, remove the old one (implicit delete)
     228               0 :       PL_HashTableRemove(mHash,(void *)slotid);
     229                 :     }
     230                 :   }
     231                 : }
     232                 : 
     233                 : // retrieve the name saved above
     234                 : const char *
     235               0 : SmartCardMonitoringThread::GetTokenName(CK_SLOT_ID slotid)
     236                 : {
     237               0 :   const char *tokenName = nsnull;
     238                 :   const char *entry;
     239                 : 
     240               0 :   if (mHash) {
     241               0 :     entry = (const char *)PL_HashTableLookupConst(mHash,(void *)slotid);
     242               0 :     if (entry) {
     243               0 :       tokenName = &entry[sizeof(PRUint32)];
     244                 :     }
     245                 :   }
     246               0 :   return tokenName;
     247                 : }
     248                 : 
     249                 : // retrieve the series saved in SetTokenName above
     250                 : PRUint32
     251               0 : SmartCardMonitoringThread::GetTokenSeries(CK_SLOT_ID slotid)
     252                 : {
     253               0 :   PRUint32 series = 0;
     254                 :   const char *entry;
     255                 : 
     256               0 :   if (mHash) {
     257               0 :     entry = (const char *)PL_HashTableLookupConst(mHash,(void *)slotid);
     258               0 :     if (entry) {
     259               0 :       memcpy(&series,entry,sizeof(PRUint32));
     260                 :     }
     261                 :   }
     262               0 :   return series;
     263                 : }
     264                 : 
     265                 : //
     266                 : // helper function to pass the event off to nsNSSComponent.
     267                 : //
     268                 : nsresult
     269               0 : SmartCardMonitoringThread::SendEvent(const nsAString &eventType,
     270                 :                                      const char *tokenName)
     271                 : {
     272                 :   nsresult rv;
     273                 :   nsCOMPtr<nsINSSComponent> 
     274               0 :                     nssComponent(do_GetService(kNSSComponentCID, &rv));
     275               0 :   if (NS_FAILED(rv))
     276               0 :     return rv;
     277                 : 
     278                 :   // NSS returns actual UTF8, not ASCII
     279               0 :   nssComponent->PostEvent(eventType, NS_ConvertUTF8toUTF16(tokenName));
     280               0 :   return NS_OK;
     281                 : }
     282                 : 
     283                 : //
     284                 : // This is the main loop.
     285                 : //
     286               0 : void SmartCardMonitoringThread::Execute()
     287                 : {
     288                 :   PK11SlotInfo *slot;
     289               0 :   const char *tokenName = nsnull;
     290                 : 
     291                 :   //
     292                 :   // populate token names for already inserted tokens.
     293                 :   //
     294                 :   PK11SlotList *sl =
     295               0 :             PK11_FindSlotsByNames(mModule->dllName, nsnull, nsnull, true);
     296                 :   PK11SlotListElement *sle;
     297                 :  
     298               0 :   if (sl) {
     299               0 :     for (sle=PK11_GetFirstSafe(sl); sle; 
     300                 :                                       sle=PK11_GetNextSafe(sl,sle,false)) {
     301                 :       SetTokenName(PK11_GetSlotID(sle->slot), 
     302               0 :                   PK11_GetTokenName(sle->slot), PK11_GetSlotSeries(sle->slot));
     303                 :     }
     304               0 :     PK11_FreeSlotList(sl);
     305                 :   }
     306                 : 
     307                 :   // loop starts..
     308               0 :   do {
     309               0 :     slot = SECMOD_WaitForAnyTokenEvent(mModule, 0, PR_SecondsToInterval(1)  );
     310               0 :     if (slot == nsnull) {
     311                 :       break;
     312                 :     }
     313                 : 
     314                 :     // now we have a potential insertion or removal event, see if the slot
     315                 :     // is present to determine which it is...
     316               0 :     if (PK11_IsPresent(slot)) {
     317                 :       // insertion
     318               0 :       CK_SLOT_ID slotID = PK11_GetSlotID(slot);
     319               0 :       PRUint32 series = PK11_GetSlotSeries(slot);
     320                 : 
     321                 :       // skip spurious insertion events...
     322               0 :       if (series != GetTokenSeries(slotID)) {
     323                 :         // if there's a token name, then we have not yet issued a remove
     324                 :         // event for the previous token, do so now...
     325               0 :         tokenName = GetTokenName(slotID);
     326               0 :         if (tokenName) {
     327               0 :           SendEvent(NS_LITERAL_STRING(SMARTCARDEVENT_REMOVE), tokenName);
     328                 :         }
     329               0 :         tokenName = PK11_GetTokenName(slot);
     330                 :         // save the token name and series
     331               0 :         SetTokenName(slotID, tokenName, series);
     332               0 :         SendEvent(NS_LITERAL_STRING(SMARTCARDEVENT_INSERT), tokenName);
     333                 :       }
     334                 :     } else {
     335                 :       // retrieve token name 
     336               0 :       CK_SLOT_ID slotID = PK11_GetSlotID(slot);
     337               0 :       tokenName = GetTokenName(slotID);
     338                 :       // if there's not a token name, then the software isn't expecting
     339                 :       // a (or another) remove event.
     340               0 :       if (tokenName) {
     341               0 :         SendEvent(NS_LITERAL_STRING(SMARTCARDEVENT_REMOVE), tokenName);
     342                 :         // clear the token name (after we send it)
     343               0 :         SetTokenName(slotID, nsnull, 0);
     344                 :       }
     345                 :     }
     346               0 :     PK11_FreeSlot(slot);
     347                 : 
     348                 :   } while (1);
     349               0 : }
     350                 : 
     351                 : // accessor to help searching active Monitoring threads
     352               0 : const SECMODModule * SmartCardMonitoringThread::GetModule() 
     353                 : {
     354               0 :   return mModule;
     355                 : }
     356                 : 
     357                 : // C-like calling sequence to glue into PR_CreateThread.
     358               0 : void SmartCardMonitoringThread::LaunchExecute(void *arg)
     359                 : {
     360               0 :   ((SmartCardMonitoringThread*)arg)->Execute();
     361               0 : }
     362                 : 

Generated by: LCOV version 1.7