Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : *
3 : * This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 : #include "nsPK11TokenDB.h"
7 :
8 : #include <string.h>
9 :
10 : #include "ScopedNSSTypes.h"
11 : #include "mozilla/Casting.h"
12 : #include "mozilla/Unused.h"
13 : #include "nsIMutableArray.h"
14 : #include "nsISupports.h"
15 : #include "nsNSSComponent.h"
16 : #include "nsPromiseFlatString.h"
17 : #include "nsReadableUtils.h"
18 : #include "nsServiceManagerUtils.h"
19 : #include "prerror.h"
20 : #include "secerr.h"
21 :
22 : extern mozilla::LazyLogModule gPIPNSSLog;
23 :
24 17 : NS_IMPL_ISUPPORTS(nsPK11Token, nsIPK11Token)
25 :
26 1 : nsPK11Token::nsPK11Token(PK11SlotInfo* slot)
27 2 : : mUIContext(new PipUIContext())
28 : {
29 1 : MOZ_ASSERT(slot);
30 :
31 2 : nsNSSShutDownPreventionLock locker;
32 1 : if (isAlreadyShutDown())
33 0 : return;
34 :
35 1 : mSlot.reset(PK11_ReferenceSlot(slot));
36 1 : mSeries = PK11_GetSlotSeries(slot);
37 :
38 1 : Unused << refreshTokenInfo(locker);
39 : }
40 :
41 : nsresult
42 1 : nsPK11Token::refreshTokenInfo(const nsNSSShutDownPreventionLock& /*proofOfLock*/)
43 : {
44 1 : mTokenName = PK11_GetTokenName(mSlot.get());
45 :
46 : CK_TOKEN_INFO tokInfo;
47 1 : nsresult rv = MapSECStatus(PK11_GetTokenInfo(mSlot.get(), &tokInfo));
48 1 : if (NS_FAILED(rv)) {
49 0 : return rv;
50 : }
51 :
52 : // Set the Label field
53 1 : const char* ccLabel = mozilla::BitwiseCast<char*, CK_UTF8CHAR*>(tokInfo.label);
54 1 : mTokenLabel.Assign(ccLabel, strnlen(ccLabel, sizeof(tokInfo.label)));
55 1 : mTokenLabel.Trim(" ", false, true);
56 :
57 : // Set the Manufacturer field
58 : const char* ccManID =
59 1 : mozilla::BitwiseCast<char*, CK_UTF8CHAR*>(tokInfo.manufacturerID);
60 1 : mTokenManufacturerID.Assign(
61 : ccManID,
62 2 : strnlen(ccManID, sizeof(tokInfo.manufacturerID)));
63 1 : mTokenManufacturerID.Trim(" ", false, true);
64 :
65 : // Set the Hardware Version field
66 1 : mTokenHWVersion.Truncate();
67 1 : mTokenHWVersion.AppendInt(tokInfo.hardwareVersion.major);
68 1 : mTokenHWVersion.Append('.');
69 1 : mTokenHWVersion.AppendInt(tokInfo.hardwareVersion.minor);
70 :
71 : // Set the Firmware Version field
72 1 : mTokenFWVersion.Truncate();
73 1 : mTokenFWVersion.AppendInt(tokInfo.firmwareVersion.major);
74 1 : mTokenFWVersion.Append('.');
75 1 : mTokenFWVersion.AppendInt(tokInfo.firmwareVersion.minor);
76 :
77 : // Set the Serial Number field
78 : const char* ccSerial =
79 1 : mozilla::BitwiseCast<char*, CK_CHAR*>(tokInfo.serialNumber);
80 1 : mTokenSerialNum.Assign(ccSerial,
81 2 : strnlen(ccSerial, sizeof(tokInfo.serialNumber)));
82 1 : mTokenSerialNum.Trim(" ", false, true);
83 :
84 1 : return NS_OK;
85 : }
86 :
87 0 : nsPK11Token::~nsPK11Token()
88 : {
89 0 : nsNSSShutDownPreventionLock locker;
90 0 : if (isAlreadyShutDown()) {
91 0 : return;
92 : }
93 0 : destructorSafeDestroyNSSReference();
94 0 : shutdown(ShutdownCalledFrom::Object);
95 0 : }
96 :
97 : void
98 0 : nsPK11Token::virtualDestroyNSSReference()
99 : {
100 0 : destructorSafeDestroyNSSReference();
101 0 : }
102 :
103 : void
104 0 : nsPK11Token::destructorSafeDestroyNSSReference()
105 : {
106 0 : mSlot = nullptr;
107 0 : }
108 :
109 : nsresult
110 0 : nsPK11Token::GetAttributeHelper(const nsACString& attribute,
111 : /*out*/ nsACString& xpcomOutParam)
112 : {
113 0 : nsNSSShutDownPreventionLock locker;
114 0 : if (isAlreadyShutDown()) {
115 0 : return NS_ERROR_NOT_AVAILABLE;
116 : }
117 :
118 : // Handle removals/insertions.
119 0 : if (PK11_GetSlotSeries(mSlot.get()) != mSeries) {
120 0 : nsresult rv = refreshTokenInfo(locker);
121 0 : if (NS_FAILED(rv)) {
122 0 : return rv;
123 : }
124 : }
125 :
126 0 : xpcomOutParam = attribute;
127 0 : return NS_OK;
128 : }
129 :
130 : NS_IMETHODIMP
131 0 : nsPK11Token::GetTokenName(/*out*/ nsACString& tokenName)
132 : {
133 0 : return GetAttributeHelper(mTokenName, tokenName);
134 : }
135 :
136 : NS_IMETHODIMP
137 0 : nsPK11Token::GetTokenLabel(/*out*/ nsACString& tokenLabel)
138 : {
139 0 : return GetAttributeHelper(mTokenLabel, tokenLabel);
140 : }
141 :
142 : NS_IMETHODIMP
143 0 : nsPK11Token::GetTokenManID(/*out*/ nsACString& tokenManufacturerID)
144 : {
145 0 : return GetAttributeHelper(mTokenManufacturerID, tokenManufacturerID);
146 : }
147 :
148 : NS_IMETHODIMP
149 0 : nsPK11Token::GetTokenHWVersion(/*out*/ nsACString& tokenHWVersion)
150 : {
151 0 : return GetAttributeHelper(mTokenHWVersion, tokenHWVersion);
152 : }
153 :
154 : NS_IMETHODIMP
155 0 : nsPK11Token::GetTokenFWVersion(/*out*/ nsACString& tokenFWVersion)
156 : {
157 0 : return GetAttributeHelper(mTokenFWVersion, tokenFWVersion);
158 : }
159 :
160 : NS_IMETHODIMP
161 0 : nsPK11Token::GetTokenSerialNumber(/*out*/ nsACString& tokenSerialNum)
162 : {
163 0 : return GetAttributeHelper(mTokenSerialNum, tokenSerialNum);
164 : }
165 :
166 : NS_IMETHODIMP
167 0 : nsPK11Token::IsLoggedIn(bool* _retval)
168 : {
169 0 : NS_ENSURE_ARG_POINTER(_retval);
170 :
171 0 : nsNSSShutDownPreventionLock locker;
172 0 : if (isAlreadyShutDown())
173 0 : return NS_ERROR_NOT_AVAILABLE;
174 :
175 0 : *_retval = PK11_IsLoggedIn(mSlot.get(), 0);
176 :
177 0 : return NS_OK;
178 : }
179 :
180 : NS_IMETHODIMP
181 0 : nsPK11Token::Login(bool force)
182 : {
183 0 : nsNSSShutDownPreventionLock locker;
184 0 : if (isAlreadyShutDown())
185 0 : return NS_ERROR_NOT_AVAILABLE;
186 :
187 : nsresult rv;
188 : bool test;
189 0 : rv = this->NeedsLogin(&test);
190 0 : if (NS_FAILED(rv)) return rv;
191 0 : if (test && force) {
192 0 : rv = this->LogoutSimple();
193 0 : if (NS_FAILED(rv)) return rv;
194 : }
195 0 : rv = setPassword(mSlot.get(), mUIContext, locker);
196 0 : if (NS_FAILED(rv)) return rv;
197 :
198 0 : return MapSECStatus(PK11_Authenticate(mSlot.get(), true, mUIContext));
199 : }
200 :
201 : NS_IMETHODIMP
202 0 : nsPK11Token::LogoutSimple()
203 : {
204 0 : nsNSSShutDownPreventionLock locker;
205 0 : if (isAlreadyShutDown())
206 0 : return NS_ERROR_NOT_AVAILABLE;
207 :
208 : // PK11_Logout() can fail if the user wasn't logged in beforehand. We want
209 : // this method to succeed even in this case, so we ignore the return value.
210 0 : Unused << PK11_Logout(mSlot.get());
211 0 : return NS_OK;
212 : }
213 :
214 : NS_IMETHODIMP
215 0 : nsPK11Token::LogoutAndDropAuthenticatedResources()
216 : {
217 : static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
218 :
219 0 : nsresult rv = LogoutSimple();
220 :
221 0 : if (NS_FAILED(rv))
222 0 : return rv;
223 :
224 0 : nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
225 0 : if (NS_FAILED(rv))
226 0 : return rv;
227 :
228 0 : return nssComponent->LogoutAuthenticatedPK11();
229 : }
230 :
231 : NS_IMETHODIMP
232 0 : nsPK11Token::Reset()
233 : {
234 0 : nsNSSShutDownPreventionLock locker;
235 0 : if (isAlreadyShutDown())
236 0 : return NS_ERROR_NOT_AVAILABLE;
237 :
238 0 : return MapSECStatus(PK11_ResetToken(mSlot.get(), nullptr));
239 : }
240 :
241 : NS_IMETHODIMP
242 0 : nsPK11Token::GetMinimumPasswordLength(int32_t* aMinimumPasswordLength)
243 : {
244 0 : NS_ENSURE_ARG_POINTER(aMinimumPasswordLength);
245 :
246 0 : nsNSSShutDownPreventionLock locker;
247 0 : if (isAlreadyShutDown())
248 0 : return NS_ERROR_NOT_AVAILABLE;
249 :
250 0 : *aMinimumPasswordLength = PK11_GetMinimumPwdLength(mSlot.get());
251 :
252 0 : return NS_OK;
253 : }
254 :
255 : NS_IMETHODIMP
256 1 : nsPK11Token::GetNeedsUserInit(bool* aNeedsUserInit)
257 : {
258 1 : NS_ENSURE_ARG_POINTER(aNeedsUserInit);
259 :
260 2 : nsNSSShutDownPreventionLock locker;
261 1 : if (isAlreadyShutDown())
262 0 : return NS_ERROR_NOT_AVAILABLE;
263 :
264 1 : *aNeedsUserInit = PK11_NeedUserInit(mSlot.get());
265 1 : return NS_OK;
266 : }
267 :
268 : NS_IMETHODIMP
269 0 : nsPK11Token::CheckPassword(const nsACString& password, bool* _retval)
270 : {
271 0 : NS_ENSURE_ARG_POINTER(_retval);
272 :
273 0 : nsNSSShutDownPreventionLock locker;
274 0 : if (isAlreadyShutDown())
275 0 : return NS_ERROR_NOT_AVAILABLE;
276 :
277 : SECStatus srv =
278 0 : PK11_CheckUserPassword(mSlot.get(), PromiseFlatCString(password).get());
279 0 : if (srv != SECSuccess) {
280 0 : *_retval = false;
281 0 : PRErrorCode error = PR_GetError();
282 0 : if (error != SEC_ERROR_BAD_PASSWORD) {
283 : /* something really bad happened - throw an exception */
284 0 : return mozilla::psm::GetXPCOMFromNSSError(error);
285 : }
286 : } else {
287 0 : *_retval = true;
288 : }
289 0 : return NS_OK;
290 : }
291 :
292 : NS_IMETHODIMP
293 0 : nsPK11Token::InitPassword(const nsACString& initialPassword)
294 : {
295 0 : nsNSSShutDownPreventionLock locker;
296 0 : if (isAlreadyShutDown())
297 0 : return NS_ERROR_NOT_AVAILABLE;
298 :
299 0 : return MapSECStatus(
300 0 : PK11_InitPin(mSlot.get(), "", PromiseFlatCString(initialPassword).get()));
301 : }
302 :
303 : NS_IMETHODIMP
304 0 : nsPK11Token::GetAskPasswordTimes(int32_t* askTimes)
305 : {
306 0 : NS_ENSURE_ARG_POINTER(askTimes);
307 :
308 0 : nsNSSShutDownPreventionLock locker;
309 0 : if (isAlreadyShutDown())
310 0 : return NS_ERROR_NOT_AVAILABLE;
311 :
312 : int askTimeout;
313 0 : PK11_GetSlotPWValues(mSlot.get(), askTimes, &askTimeout);
314 0 : return NS_OK;
315 : }
316 :
317 : NS_IMETHODIMP
318 0 : nsPK11Token::GetAskPasswordTimeout(int32_t* askTimeout)
319 : {
320 0 : NS_ENSURE_ARG_POINTER(askTimeout);
321 :
322 0 : nsNSSShutDownPreventionLock locker;
323 0 : if (isAlreadyShutDown())
324 0 : return NS_ERROR_NOT_AVAILABLE;
325 :
326 : int askTimes;
327 0 : PK11_GetSlotPWValues(mSlot.get(), &askTimes, askTimeout);
328 0 : return NS_OK;
329 : }
330 :
331 : NS_IMETHODIMP
332 0 : nsPK11Token::SetAskPasswordDefaults(const int32_t askTimes,
333 : const int32_t askTimeout)
334 : {
335 0 : nsNSSShutDownPreventionLock locker;
336 0 : if (isAlreadyShutDown())
337 0 : return NS_ERROR_NOT_AVAILABLE;
338 :
339 0 : PK11_SetSlotPWValues(mSlot.get(), askTimes, askTimeout);
340 0 : return NS_OK;
341 : }
342 :
343 : NS_IMETHODIMP
344 0 : nsPK11Token::ChangePassword(const nsACString& oldPassword,
345 : const nsACString& newPassword)
346 : {
347 0 : nsNSSShutDownPreventionLock locker;
348 0 : if (isAlreadyShutDown())
349 0 : return NS_ERROR_NOT_AVAILABLE;
350 :
351 : // PK11_ChangePW() has different semantics for the empty string and for
352 : // nullptr. In order to support this difference, we need to check IsVoid() to
353 : // find out if our caller supplied null/undefined args or just empty strings.
354 : // See Bug 447589.
355 0 : return MapSECStatus(PK11_ChangePW(
356 : mSlot.get(),
357 0 : oldPassword.IsVoid() ? nullptr : PromiseFlatCString(oldPassword).get(),
358 0 : newPassword.IsVoid() ? nullptr : PromiseFlatCString(newPassword).get()));
359 : }
360 :
361 : NS_IMETHODIMP
362 0 : nsPK11Token::GetHasPassword(bool* hasPassword)
363 : {
364 0 : NS_ENSURE_ARG_POINTER(hasPassword);
365 :
366 0 : nsNSSShutDownPreventionLock locker;
367 0 : if (isAlreadyShutDown()) {
368 0 : return NS_ERROR_NOT_AVAILABLE;
369 : }
370 :
371 : // PK11_NeedLogin returns true if the token is currently configured to require
372 : // the user to log in (whether or not the user is actually logged in makes no
373 : // difference).
374 0 : *hasPassword = PK11_NeedLogin(mSlot.get()) && !PK11_NeedUserInit(mSlot.get());
375 0 : return NS_OK;
376 : }
377 :
378 : NS_IMETHODIMP
379 0 : nsPK11Token::IsHardwareToken(bool* _retval)
380 : {
381 0 : NS_ENSURE_ARG_POINTER(_retval);
382 :
383 0 : nsNSSShutDownPreventionLock locker;
384 0 : if (isAlreadyShutDown())
385 0 : return NS_ERROR_NOT_AVAILABLE;
386 :
387 0 : *_retval = PK11_IsHW(mSlot.get());
388 :
389 0 : return NS_OK;
390 : }
391 :
392 : NS_IMETHODIMP
393 0 : nsPK11Token::NeedsLogin(bool* _retval)
394 : {
395 0 : NS_ENSURE_ARG_POINTER(_retval);
396 :
397 0 : nsNSSShutDownPreventionLock locker;
398 0 : if (isAlreadyShutDown())
399 0 : return NS_ERROR_NOT_AVAILABLE;
400 :
401 0 : *_retval = PK11_NeedLogin(mSlot.get());
402 :
403 0 : return NS_OK;
404 : }
405 :
406 : /*=========================================================*/
407 :
408 18 : NS_IMPL_ISUPPORTS(nsPK11TokenDB, nsIPK11TokenDB)
409 :
410 1 : nsPK11TokenDB::nsPK11TokenDB()
411 : {
412 1 : }
413 :
414 0 : nsPK11TokenDB::~nsPK11TokenDB()
415 : {
416 0 : nsNSSShutDownPreventionLock locker;
417 0 : if (isAlreadyShutDown()) {
418 0 : return;
419 : }
420 :
421 0 : shutdown(ShutdownCalledFrom::Object);
422 0 : }
423 :
424 : NS_IMETHODIMP
425 1 : nsPK11TokenDB::GetInternalKeyToken(nsIPK11Token** _retval)
426 : {
427 1 : NS_ENSURE_ARG_POINTER(_retval);
428 :
429 2 : nsNSSShutDownPreventionLock locker;
430 1 : if (isAlreadyShutDown()) {
431 0 : return NS_ERROR_NOT_AVAILABLE;
432 : }
433 :
434 2 : UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
435 1 : if (!slot) {
436 0 : return NS_ERROR_FAILURE;
437 : }
438 :
439 3 : nsCOMPtr<nsIPK11Token> token = new nsPK11Token(slot.get());
440 1 : token.forget(_retval);
441 :
442 1 : return NS_OK;
443 : }
444 :
445 : NS_IMETHODIMP
446 0 : nsPK11TokenDB::FindTokenByName(const nsACString& tokenName,
447 : /*out*/ nsIPK11Token** _retval)
448 : {
449 0 : NS_ENSURE_ARG_POINTER(_retval);
450 :
451 0 : nsNSSShutDownPreventionLock locker;
452 0 : if (isAlreadyShutDown()) {
453 0 : return NS_ERROR_NOT_AVAILABLE;
454 : }
455 :
456 0 : if (tokenName.IsEmpty()) {
457 0 : return NS_ERROR_ILLEGAL_VALUE;
458 : }
459 :
460 : UniquePK11SlotInfo slot(
461 0 : PK11_FindSlotByName(PromiseFlatCString(tokenName).get()));
462 0 : if (!slot) {
463 0 : return NS_ERROR_FAILURE;
464 : }
465 :
466 0 : nsCOMPtr<nsIPK11Token> token = new nsPK11Token(slot.get());
467 0 : token.forget(_retval);
468 :
469 0 : return NS_OK;
470 : }
471 :
472 : NS_IMETHODIMP
473 0 : nsPK11TokenDB::ListTokens(nsISimpleEnumerator** _retval)
474 : {
475 0 : NS_ENSURE_ARG_POINTER(_retval);
476 :
477 0 : nsNSSShutDownPreventionLock locker;
478 0 : if (isAlreadyShutDown()) {
479 0 : return NS_ERROR_NOT_AVAILABLE;
480 : }
481 :
482 0 : nsCOMPtr<nsIMutableArray> array = do_CreateInstance(NS_ARRAY_CONTRACTID);
483 0 : if (!array) {
484 0 : return NS_ERROR_FAILURE;
485 : }
486 :
487 0 : *_retval = nullptr;
488 :
489 : UniquePK11SlotList list(
490 0 : PK11_GetAllTokens(CKM_INVALID_MECHANISM, false, false, 0));
491 0 : if (!list) {
492 0 : return NS_ERROR_FAILURE;
493 : }
494 :
495 0 : for (PK11SlotListElement* le = PK11_GetFirstSafe(list.get()); le;
496 0 : le = PK11_GetNextSafe(list.get(), le, false)) {
497 0 : nsCOMPtr<nsIPK11Token> token = new nsPK11Token(le->slot);
498 0 : nsresult rv = array->AppendElement(token, false);
499 0 : if (NS_FAILED(rv)) {
500 0 : return rv;
501 : }
502 : }
503 :
504 0 : return array->Enumerate(_retval);
505 : }
|