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