1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 #include "pk11func.h"
6 #include "mozilla/DebugOnly.h"
7 #include "mozilla/RefPtr.h"
8 #include "nsCOMPtr.h"
9 #include "PSMRunnable.h"
10 #include "nsString.h"
11 #include "nsReadableUtils.h"
12 #include "nsPKCS11Slot.h"
13 #include "nsProtectedAuthThread.h"
14 
15 using namespace mozilla;
16 using namespace mozilla::psm;
17 
NS_IMPL_ISUPPORTS(nsProtectedAuthThread,nsIProtectedAuthThread)18 NS_IMPL_ISUPPORTS(nsProtectedAuthThread, nsIProtectedAuthThread)
19 
20 static void nsProtectedAuthThreadRunner(void *arg)
21 {
22     PR_SetCurrentThreadName("Protected Auth");
23 
24     nsProtectedAuthThread *self = static_cast<nsProtectedAuthThread *>(arg);
25     self->Run();
26 }
27 
nsProtectedAuthThread()28 nsProtectedAuthThread::nsProtectedAuthThread()
29 : mMutex("nsProtectedAuthThread.mMutex")
30 , mIAmRunning(false)
31 , mLoginReady(false)
32 , mThreadHandle(nullptr)
33 , mSlot(0)
34 , mLoginResult(SECFailure)
35 {
36 }
37 
~nsProtectedAuthThread()38 nsProtectedAuthThread::~nsProtectedAuthThread()
39 {
40 }
41 
Login(nsIObserver * aObserver)42 NS_IMETHODIMP nsProtectedAuthThread::Login(nsIObserver *aObserver)
43 {
44     NS_ENSURE_ARG(aObserver);
45 
46     if (!mSlot)
47         // We need pointer to the slot
48         return NS_ERROR_FAILURE;
49 
50     MutexAutoLock lock(mMutex);
51 
52     if (mIAmRunning || mLoginReady) {
53         return NS_OK;
54     }
55 
56     if (aObserver) {
57       // We must AddRef aObserver here on the main thread, because it probably
58       // does not implement a thread-safe AddRef.
59       mNotifyObserver = new NotifyObserverRunnable(aObserver,
60                                                    "operation-completed");
61     }
62 
63     mIAmRunning = true;
64 
65     mThreadHandle = PR_CreateThread(PR_USER_THREAD, nsProtectedAuthThreadRunner, static_cast<void*>(this),
66         PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
67 
68     // bool thread_started_ok = (threadHandle != nullptr);
69     // we might want to return "thread started ok" to caller in the future
70     NS_ASSERTION(mThreadHandle, "Could not create nsProtectedAuthThreadRunner thread\n");
71 
72     return NS_OK;
73 }
74 
GetTokenName(nsAString & _retval)75 NS_IMETHODIMP nsProtectedAuthThread::GetTokenName(nsAString &_retval)
76 {
77     MutexAutoLock lock(mMutex);
78 
79     // Get token name
80     CopyUTF8toUTF16(nsDependentCString(PK11_GetTokenName(mSlot)), _retval);
81 
82     return NS_OK;
83 }
84 
GetSlot(nsIPKCS11Slot ** _retval)85 NS_IMETHODIMP nsProtectedAuthThread::GetSlot(nsIPKCS11Slot **_retval)
86 {
87     RefPtr<nsPKCS11Slot> slot;
88     {
89         MutexAutoLock lock(mMutex);
90         slot = new nsPKCS11Slot(mSlot);
91     }
92 
93     slot.forget(_retval);
94     return NS_OK;
95 }
96 
SetParams(PK11SlotInfo * aSlot)97 void nsProtectedAuthThread::SetParams(PK11SlotInfo* aSlot)
98 {
99     MutexAutoLock lock(mMutex);
100 
101     mSlot = (aSlot) ? PK11_ReferenceSlot(aSlot) : 0;
102 }
103 
GetResult()104 SECStatus nsProtectedAuthThread::GetResult()
105 {
106     return mLoginResult;
107 }
108 
Run(void)109 void nsProtectedAuthThread::Run(void)
110 {
111     // Login with null password. This call will also do C_Logout() but
112     // it is harmless here
113     mLoginResult = PK11_CheckUserPassword(mSlot, 0);
114 
115     nsCOMPtr<nsIRunnable> notifyObserver;
116     {
117         MutexAutoLock lock(mMutex);
118 
119         mLoginReady = true;
120         mIAmRunning = false;
121 
122         // Forget the slot
123         if (mSlot)
124         {
125             PK11_FreeSlot(mSlot);
126             mSlot = 0;
127         }
128 
129         notifyObserver.swap(mNotifyObserver);
130     }
131 
132     if (notifyObserver) {
133         DebugOnly<nsresult> rv = NS_DispatchToMainThread(notifyObserver);
134 	NS_ASSERTION(NS_SUCCEEDED(rv),
135 		     "failed to dispatch protected auth observer to main thread");
136     }
137 }
138 
Join()139 void nsProtectedAuthThread::Join()
140 {
141     if (!mThreadHandle)
142         return;
143 
144     PR_JoinThread(mThreadHandle);
145     mThreadHandle = nullptr;
146 }
147