1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : *
3 : * ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is mozilla.org code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Netscape Communications Corporation.
20 : * Portions created by the Initial Developer are Copyright (C) 2001
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Terry Hayes <thayes@netscape.com>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either the GNU General Public License Version 2 or later (the "GPL"), or
28 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 : #include "nsISupports.h"
40 : #include "nsIPK11TokenDB.h"
41 : #include "prerror.h"
42 : #include "secerr.h"
43 : #include "nsReadableUtils.h"
44 : #include "nsNSSComponent.h"
45 :
46 : #include "nsPK11TokenDB.h"
47 :
48 : #ifdef PR_LOGGING
49 : extern PRLogModuleInfo* gPIPNSSLog;
50 : #endif
51 :
52 : static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
53 :
54 3688 : NS_IMPL_ISUPPORTS1(nsPK11Token, nsIPK11Token)
55 :
56 194 : nsPK11Token::nsPK11Token(PK11SlotInfo *slot)
57 : {
58 388 : nsNSSShutDownPreventionLock locker;
59 194 : if (isAlreadyShutDown())
60 : return;
61 :
62 194 : PK11_ReferenceSlot(slot);
63 194 : mSlot = slot;
64 194 : mSeries = PK11_GetSlotSeries(slot);
65 :
66 194 : refreshTokenInfo();
67 194 : mUIContext = new PipUIContext();
68 : }
69 :
70 : void
71 194 : nsPK11Token::refreshTokenInfo()
72 : {
73 194 : mTokenName = NS_ConvertUTF8toUTF16(PK11_GetTokenName(mSlot));
74 :
75 : SECStatus srv;
76 :
77 : CK_TOKEN_INFO tok_info;
78 194 : srv = PK11_GetTokenInfo(mSlot, &tok_info);
79 194 : if (srv == SECSuccess) {
80 : // Set the Label field
81 :
82 194 : const char *ccLabel = (const char*)tok_info.label;
83 : const nsACString &cLabel = Substring(
84 : ccLabel,
85 388 : ccLabel+PL_strnlen(ccLabel, sizeof(tok_info.label)));
86 194 : mTokenLabel = NS_ConvertUTF8toUTF16(cLabel);
87 194 : mTokenLabel.Trim(" ", false, true);
88 :
89 : // Set the Manufacturer field
90 194 : const char *ccManID = (const char*)tok_info.manufacturerID;
91 : const nsACString &cManID = Substring(
92 : ccManID,
93 388 : ccManID+PL_strnlen(ccManID, sizeof(tok_info.manufacturerID)));
94 194 : mTokenManID = NS_ConvertUTF8toUTF16(cManID);
95 194 : mTokenManID.Trim(" ", false, true);
96 :
97 : // Set the Hardware Version field
98 194 : mTokenHWVersion.AppendInt(tok_info.hardwareVersion.major);
99 194 : mTokenHWVersion.AppendLiteral(".");
100 194 : mTokenHWVersion.AppendInt(tok_info.hardwareVersion.minor);
101 : // Set the Firmware Version field
102 194 : mTokenFWVersion.AppendInt(tok_info.firmwareVersion.major);
103 194 : mTokenFWVersion.AppendLiteral(".");
104 194 : mTokenFWVersion.AppendInt(tok_info.firmwareVersion.minor);
105 : // Set the Serial Number field
106 194 : const char *ccSerial = (const char*)tok_info.serialNumber;
107 : const nsACString &cSerial = Substring(
108 : ccSerial,
109 388 : ccSerial+PL_strnlen(ccSerial, sizeof(tok_info.serialNumber)));
110 194 : mTokenSerialNum = NS_ConvertUTF8toUTF16(cSerial);
111 194 : mTokenSerialNum.Trim(" ", false, true);
112 : }
113 :
114 194 : }
115 :
116 582 : nsPK11Token::~nsPK11Token()
117 : {
118 388 : nsNSSShutDownPreventionLock locker;
119 194 : if (isAlreadyShutDown())
120 : return;
121 :
122 30 : destructorSafeDestroyNSSReference();
123 224 : shutdown(calledFromObject);
124 776 : }
125 :
126 164 : void nsPK11Token::virtualDestroyNSSReference()
127 : {
128 164 : destructorSafeDestroyNSSReference();
129 164 : }
130 :
131 194 : void nsPK11Token::destructorSafeDestroyNSSReference()
132 : {
133 194 : if (isAlreadyShutDown())
134 0 : return;
135 :
136 194 : if (mSlot) {
137 194 : PK11_FreeSlot(mSlot);
138 194 : mSlot = nsnull;
139 : }
140 : }
141 :
142 : /* readonly attribute wstring tokenName; */
143 0 : NS_IMETHODIMP nsPK11Token::GetTokenName(PRUnichar * *aTokenName)
144 : {
145 : // handle removals/insertions
146 0 : if (mSeries != PK11_GetSlotSeries(mSlot)) {
147 0 : refreshTokenInfo();
148 : }
149 0 : *aTokenName = ToNewUnicode(mTokenName);
150 0 : if (!*aTokenName) return NS_ERROR_OUT_OF_MEMORY;
151 :
152 0 : return NS_OK;
153 : }
154 :
155 : /* readonly attribute wstring tokenDesc; */
156 0 : NS_IMETHODIMP nsPK11Token::GetTokenLabel(PRUnichar **aTokLabel)
157 : {
158 : // handle removals/insertions
159 0 : if (mSeries != PK11_GetSlotSeries(mSlot)) {
160 0 : refreshTokenInfo();
161 : }
162 0 : *aTokLabel = ToNewUnicode(mTokenLabel);
163 0 : if (!*aTokLabel) return NS_ERROR_OUT_OF_MEMORY;
164 0 : return NS_OK;
165 : }
166 :
167 : /* readonly attribute wstring tokenManID; */
168 0 : NS_IMETHODIMP nsPK11Token::GetTokenManID(PRUnichar **aTokManID)
169 : {
170 : // handle removals/insertions
171 0 : if (mSeries != PK11_GetSlotSeries(mSlot)) {
172 0 : refreshTokenInfo();
173 : }
174 0 : *aTokManID = ToNewUnicode(mTokenManID);
175 0 : if (!*aTokManID) return NS_ERROR_OUT_OF_MEMORY;
176 0 : return NS_OK;
177 : }
178 :
179 : /* readonly attribute wstring tokenHWVersion; */
180 0 : NS_IMETHODIMP nsPK11Token::GetTokenHWVersion(PRUnichar **aTokHWVersion)
181 : {
182 : // handle removals/insertions
183 0 : if (mSeries != PK11_GetSlotSeries(mSlot)) {
184 0 : refreshTokenInfo();
185 : }
186 0 : *aTokHWVersion = ToNewUnicode(mTokenHWVersion);
187 0 : if (!*aTokHWVersion) return NS_ERROR_OUT_OF_MEMORY;
188 0 : return NS_OK;
189 : }
190 :
191 : /* readonly attribute wstring tokenFWVersion; */
192 0 : NS_IMETHODIMP nsPK11Token::GetTokenFWVersion(PRUnichar **aTokFWVersion)
193 : {
194 : // handle removals/insertions
195 0 : if (mSeries != PK11_GetSlotSeries(mSlot)) {
196 0 : refreshTokenInfo();
197 : }
198 0 : *aTokFWVersion = ToNewUnicode(mTokenFWVersion);
199 0 : if (!*aTokFWVersion) return NS_ERROR_OUT_OF_MEMORY;
200 0 : return NS_OK;
201 : }
202 :
203 : /* readonly attribute wstring tokenSerialNumber; */
204 0 : NS_IMETHODIMP nsPK11Token::GetTokenSerialNumber(PRUnichar **aTokSerialNum)
205 : {
206 : // handle removals/insertions
207 0 : if (mSeries != PK11_GetSlotSeries(mSlot)) {
208 0 : refreshTokenInfo();
209 : }
210 0 : *aTokSerialNum = ToNewUnicode(mTokenSerialNum);
211 0 : if (!*aTokSerialNum) return NS_ERROR_OUT_OF_MEMORY;
212 0 : return NS_OK;
213 : }
214 :
215 : /* boolean isLoggedIn (); */
216 0 : NS_IMETHODIMP nsPK11Token::IsLoggedIn(bool *_retval)
217 : {
218 0 : nsNSSShutDownPreventionLock locker;
219 0 : if (isAlreadyShutDown())
220 0 : return NS_ERROR_NOT_AVAILABLE;
221 :
222 0 : nsresult rv = NS_OK;
223 :
224 0 : *_retval = PK11_IsLoggedIn(mSlot, 0);
225 :
226 0 : return rv;
227 : }
228 :
229 : /* void logout (in boolean force); */
230 : NS_IMETHODIMP
231 0 : nsPK11Token::Login(bool force)
232 : {
233 0 : nsNSSShutDownPreventionLock locker;
234 0 : if (isAlreadyShutDown())
235 0 : return NS_ERROR_NOT_AVAILABLE;
236 :
237 : nsresult rv;
238 : SECStatus srv;
239 : bool test;
240 0 : rv = this->NeedsLogin(&test);
241 0 : if (NS_FAILED(rv)) return rv;
242 0 : if (test && force) {
243 0 : rv = this->LogoutSimple();
244 0 : if (NS_FAILED(rv)) return rv;
245 : }
246 0 : rv = setPassword(mSlot, mUIContext);
247 0 : if (NS_FAILED(rv)) return rv;
248 0 : srv = PK11_Authenticate(mSlot, true, mUIContext);
249 0 : return (srv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE;
250 : }
251 :
252 0 : NS_IMETHODIMP nsPK11Token::LogoutSimple()
253 : {
254 0 : nsNSSShutDownPreventionLock locker;
255 0 : if (isAlreadyShutDown())
256 0 : return NS_ERROR_NOT_AVAILABLE;
257 :
258 : // PK11_MapError sets CKR_USER_NOT_LOGGED_IN to SEC_ERROR_LIBRARY_FAILURE,
259 : // so not going to learn anything here by a failure. Treat it like void.
260 0 : PK11_Logout(mSlot);
261 0 : return NS_OK;
262 : }
263 :
264 0 : NS_IMETHODIMP nsPK11Token::LogoutAndDropAuthenticatedResources()
265 : {
266 0 : nsresult rv = LogoutSimple();
267 :
268 0 : if (NS_FAILED(rv))
269 0 : return rv;
270 :
271 0 : nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
272 0 : if (NS_FAILED(rv))
273 0 : return rv;
274 :
275 0 : return nssComponent->LogoutAuthenticatedPK11();
276 : }
277 :
278 : /* void reset (); */
279 0 : NS_IMETHODIMP nsPK11Token::Reset()
280 : {
281 0 : nsNSSShutDownPreventionLock locker;
282 0 : if (isAlreadyShutDown())
283 0 : return NS_ERROR_NOT_AVAILABLE;
284 :
285 0 : PK11_ResetToken(mSlot, 0);
286 0 : return NS_OK;
287 : }
288 :
289 : /* readonly attribute long minimumPasswordLength; */
290 0 : NS_IMETHODIMP nsPK11Token::GetMinimumPasswordLength(PRInt32 *aMinimumPasswordLength)
291 : {
292 0 : nsNSSShutDownPreventionLock locker;
293 0 : if (isAlreadyShutDown())
294 0 : return NS_ERROR_NOT_AVAILABLE;
295 :
296 0 : *aMinimumPasswordLength = PK11_GetMinimumPwdLength(mSlot);
297 :
298 0 : return NS_OK;
299 : }
300 :
301 : /* readonly attribute boolean needsUserInit; */
302 194 : NS_IMETHODIMP nsPK11Token::GetNeedsUserInit(bool *aNeedsUserInit)
303 : {
304 388 : nsNSSShutDownPreventionLock locker;
305 194 : if (isAlreadyShutDown())
306 0 : return NS_ERROR_NOT_AVAILABLE;
307 :
308 194 : *aNeedsUserInit = PK11_NeedUserInit(mSlot);
309 194 : return NS_OK;
310 : }
311 :
312 : /* boolean checkPassword (in wstring password); */
313 0 : NS_IMETHODIMP nsPK11Token::CheckPassword(const PRUnichar *password, bool *_retval)
314 : {
315 0 : nsNSSShutDownPreventionLock locker;
316 0 : if (isAlreadyShutDown())
317 0 : return NS_ERROR_NOT_AVAILABLE;
318 :
319 : SECStatus srv;
320 : PRInt32 prerr;
321 0 : NS_ConvertUTF16toUTF8 aUtf8Password(password);
322 : srv = PK11_CheckUserPassword(mSlot,
323 0 : const_cast<char *>(aUtf8Password.get()));
324 0 : if (srv != SECSuccess) {
325 0 : *_retval = false;
326 0 : prerr = PR_GetError();
327 0 : if (prerr != SEC_ERROR_BAD_PASSWORD) {
328 : /* something really bad happened - throw an exception */
329 0 : return NS_ERROR_FAILURE;
330 : }
331 : } else {
332 0 : *_retval = true;
333 : }
334 0 : return NS_OK;
335 : }
336 :
337 : /* void initPassword (in wstring initialPassword); */
338 36 : NS_IMETHODIMP nsPK11Token::InitPassword(const PRUnichar *initialPassword)
339 : {
340 72 : nsNSSShutDownPreventionLock locker;
341 36 : if (isAlreadyShutDown())
342 0 : return NS_ERROR_NOT_AVAILABLE;
343 :
344 36 : nsresult rv = NS_OK;
345 : SECStatus status;
346 :
347 72 : NS_ConvertUTF16toUTF8 aUtf8InitialPassword(initialPassword);
348 36 : status = PK11_InitPin(mSlot, "", const_cast<char*>(aUtf8InitialPassword.get()));
349 36 : if (status == SECFailure) { rv = NS_ERROR_FAILURE; goto done; }
350 :
351 : done:
352 36 : return rv;
353 : }
354 :
355 : /* long getAskPasswordTimes(); */
356 : NS_IMETHODIMP
357 0 : nsPK11Token::GetAskPasswordTimes(PRInt32 *rvAskTimes)
358 : {
359 0 : nsNSSShutDownPreventionLock locker;
360 0 : if (isAlreadyShutDown())
361 0 : return NS_ERROR_NOT_AVAILABLE;
362 :
363 : int askTimes, askTimeout;
364 0 : PK11_GetSlotPWValues(mSlot, &askTimes, &askTimeout);
365 0 : *rvAskTimes = askTimes;
366 0 : return NS_OK;
367 : }
368 :
369 : /* long getAskPasswordTimeout(); */
370 : NS_IMETHODIMP
371 0 : nsPK11Token::GetAskPasswordTimeout(PRInt32 *rvAskTimeout)
372 : {
373 0 : nsNSSShutDownPreventionLock locker;
374 0 : if (isAlreadyShutDown())
375 0 : return NS_ERROR_NOT_AVAILABLE;
376 :
377 : int askTimes, askTimeout;
378 0 : PK11_GetSlotPWValues(mSlot, &askTimes, &askTimeout);
379 0 : *rvAskTimeout = askTimeout;
380 0 : return NS_OK;
381 : }
382 :
383 : /* void setAskPasswordDefaults(in unsigned long askTimes,
384 : * in unsigned long timeout);
385 : */
386 : NS_IMETHODIMP
387 0 : nsPK11Token::SetAskPasswordDefaults(const PRInt32 askTimes,
388 : const PRInt32 askTimeout)
389 : {
390 0 : nsNSSShutDownPreventionLock locker;
391 0 : if (isAlreadyShutDown())
392 0 : return NS_ERROR_NOT_AVAILABLE;
393 :
394 0 : PK11_SetSlotPWValues(mSlot, askTimes, askTimeout);
395 0 : return NS_OK;
396 : }
397 :
398 : /* void changePassword (in wstring oldPassword, in wstring newPassword); */
399 0 : NS_IMETHODIMP nsPK11Token::ChangePassword(const PRUnichar *oldPassword, const PRUnichar *newPassword)
400 : {
401 0 : nsNSSShutDownPreventionLock locker;
402 0 : if (isAlreadyShutDown())
403 0 : return NS_ERROR_NOT_AVAILABLE;
404 :
405 : SECStatus rv;
406 0 : NS_ConvertUTF16toUTF8 aUtf8OldPassword(oldPassword);
407 0 : NS_ConvertUTF16toUTF8 aUtf8NewPassword(newPassword);
408 :
409 : rv = PK11_ChangePW(mSlot,
410 : (oldPassword != NULL ? const_cast<char *>(aUtf8OldPassword.get()) : NULL),
411 0 : (newPassword != NULL ? const_cast<char *>(aUtf8NewPassword.get()) : NULL));
412 0 : return (rv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE;
413 : }
414 :
415 : /* boolean isHardwareToken (); */
416 0 : NS_IMETHODIMP nsPK11Token::IsHardwareToken(bool *_retval)
417 : {
418 0 : nsNSSShutDownPreventionLock locker;
419 0 : if (isAlreadyShutDown())
420 0 : return NS_ERROR_NOT_AVAILABLE;
421 :
422 0 : nsresult rv = NS_OK;
423 :
424 0 : *_retval = PK11_IsHW(mSlot);
425 :
426 0 : return rv;
427 : }
428 :
429 : /* boolean needsLogin (); */
430 0 : NS_IMETHODIMP nsPK11Token::NeedsLogin(bool *_retval)
431 : {
432 0 : nsNSSShutDownPreventionLock locker;
433 0 : if (isAlreadyShutDown())
434 0 : return NS_ERROR_NOT_AVAILABLE;
435 :
436 0 : nsresult rv = NS_OK;
437 :
438 0 : *_retval = PK11_NeedLogin(mSlot);
439 :
440 0 : return rv;
441 : }
442 :
443 : /* boolean isFriendly (); */
444 0 : NS_IMETHODIMP nsPK11Token::IsFriendly(bool *_retval)
445 : {
446 0 : nsNSSShutDownPreventionLock locker;
447 0 : if (isAlreadyShutDown())
448 0 : return NS_ERROR_NOT_AVAILABLE;
449 :
450 0 : nsresult rv = NS_OK;
451 :
452 0 : *_retval = PK11_IsFriendly(mSlot);
453 :
454 0 : return rv;
455 : }
456 :
457 : /*=========================================================*/
458 :
459 2570 : NS_IMPL_ISUPPORTS1(nsPK11TokenDB, nsIPK11TokenDB)
460 :
461 52 : nsPK11TokenDB::nsPK11TokenDB()
462 : {
463 : /* member initializers and constructor code */
464 52 : }
465 :
466 104 : nsPK11TokenDB::~nsPK11TokenDB()
467 : {
468 : /* destructor code */
469 208 : }
470 :
471 : /* nsIPK11Token getInternalKeyToken (); */
472 194 : NS_IMETHODIMP nsPK11TokenDB::GetInternalKeyToken(nsIPK11Token **_retval)
473 : {
474 388 : nsNSSShutDownPreventionLock locker;
475 194 : nsresult rv = NS_OK;
476 194 : PK11SlotInfo *slot = 0;
477 388 : nsCOMPtr<nsIPK11Token> token;
478 :
479 194 : slot = PK11_GetInternalKeySlot();
480 194 : if (!slot) { rv = NS_ERROR_FAILURE; goto done; }
481 :
482 194 : token = new nsPK11Token(slot);
483 194 : if (!token) { rv = NS_ERROR_OUT_OF_MEMORY; goto done; }
484 :
485 194 : *_retval = token;
486 194 : NS_ADDREF(*_retval);
487 :
488 : done:
489 194 : if (slot) PK11_FreeSlot(slot);
490 194 : return rv;
491 : }
492 :
493 : /* nsIPK11Token findTokenByName (in wchar tokenName); */
494 0 : NS_IMETHODIMP nsPK11TokenDB::
495 : FindTokenByName(const PRUnichar* tokenName, nsIPK11Token **_retval)
496 : {
497 0 : nsNSSShutDownPreventionLock locker;
498 0 : nsresult rv = NS_OK;
499 0 : PK11SlotInfo *slot = 0;
500 0 : NS_ConvertUTF16toUTF8 aUtf8TokenName(tokenName);
501 0 : slot = PK11_FindSlotByName(const_cast<char*>(aUtf8TokenName.get()));
502 0 : if (!slot) { rv = NS_ERROR_FAILURE; goto done; }
503 :
504 0 : *_retval = new nsPK11Token(slot);
505 0 : if (!*_retval) { rv = NS_ERROR_OUT_OF_MEMORY; goto done; }
506 :
507 0 : NS_ADDREF(*_retval);
508 :
509 : done:
510 0 : if (slot) PK11_FreeSlot(slot);
511 0 : return rv;
512 : }
513 :
514 : /* nsIEnumerator listTokens (); */
515 0 : NS_IMETHODIMP nsPK11TokenDB::ListTokens(nsIEnumerator* *_retval)
516 : {
517 0 : nsNSSShutDownPreventionLock locker;
518 0 : nsCOMPtr<nsISupportsArray> array;
519 0 : PK11SlotList *list = 0;
520 : PK11SlotListElement *le;
521 :
522 0 : *_retval = nsnull;
523 0 : nsresult rv = NS_NewISupportsArray(getter_AddRefs(array));
524 0 : if (NS_FAILED(rv)) { goto done; }
525 :
526 : /* List all tokens, creating PK11Token objects and putting them
527 : * into the array.
528 : */
529 0 : list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, false, false, 0);
530 0 : if (!list) { rv = NS_ERROR_FAILURE; goto done; }
531 :
532 0 : for (le = PK11_GetFirstSafe(list); le; le = PK11_GetNextSafe(list, le, false)) {
533 0 : nsCOMPtr<nsIPK11Token> token = new nsPK11Token(le->slot);
534 : rv = token
535 0 : ? array->AppendElement(token)
536 0 : : NS_ERROR_OUT_OF_MEMORY;
537 :
538 0 : if (NS_FAILED(rv)) {
539 0 : PK11_FreeSlotListElement(list, le);
540 0 : rv = NS_ERROR_OUT_OF_MEMORY;
541 : goto done;
542 : }
543 : }
544 :
545 0 : rv = array->Enumerate(_retval);
546 :
547 : done:
548 0 : if (list) PK11_FreeSlotList(list);
549 0 : return rv;
550 : }
551 :
|