michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: #include "nsISupports.h" michael@0: #include "nsISupportsArray.h" michael@0: #include "nsIPK11TokenDB.h" michael@0: #include "prerror.h" michael@0: #include "secerr.h" michael@0: #include "nsReadableUtils.h" michael@0: #include "nsNSSComponent.h" michael@0: #include "nsServiceManagerUtils.h" michael@0: michael@0: #include "nsPK11TokenDB.h" michael@0: michael@0: #ifdef PR_LOGGING michael@0: extern PRLogModuleInfo* gPIPNSSLog; michael@0: #endif michael@0: michael@0: NS_IMPL_ISUPPORTS(nsPK11Token, nsIPK11Token) michael@0: michael@0: nsPK11Token::nsPK11Token(PK11SlotInfo *slot) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return; michael@0: michael@0: PK11_ReferenceSlot(slot); michael@0: mSlot = slot; michael@0: mSeries = PK11_GetSlotSeries(slot); michael@0: michael@0: refreshTokenInfo(); michael@0: mUIContext = new PipUIContext(); michael@0: } michael@0: michael@0: void michael@0: nsPK11Token::refreshTokenInfo() michael@0: { michael@0: mTokenName = NS_ConvertUTF8toUTF16(PK11_GetTokenName(mSlot)); michael@0: michael@0: SECStatus srv; michael@0: michael@0: CK_TOKEN_INFO tok_info; michael@0: srv = PK11_GetTokenInfo(mSlot, &tok_info); michael@0: if (srv == SECSuccess) { michael@0: // Set the Label field michael@0: michael@0: const char *ccLabel = (const char*)tok_info.label; michael@0: const nsACString &cLabel = Substring( michael@0: ccLabel, michael@0: ccLabel+PL_strnlen(ccLabel, sizeof(tok_info.label))); michael@0: mTokenLabel = NS_ConvertUTF8toUTF16(cLabel); michael@0: mTokenLabel.Trim(" ", false, true); michael@0: michael@0: // Set the Manufacturer field michael@0: const char *ccManID = (const char*)tok_info.manufacturerID; michael@0: const nsACString &cManID = Substring( michael@0: ccManID, michael@0: ccManID+PL_strnlen(ccManID, sizeof(tok_info.manufacturerID))); michael@0: mTokenManID = NS_ConvertUTF8toUTF16(cManID); michael@0: mTokenManID.Trim(" ", false, true); michael@0: michael@0: // Set the Hardware Version field michael@0: mTokenHWVersion.AppendInt(tok_info.hardwareVersion.major); michael@0: mTokenHWVersion.AppendLiteral("."); michael@0: mTokenHWVersion.AppendInt(tok_info.hardwareVersion.minor); michael@0: // Set the Firmware Version field michael@0: mTokenFWVersion.AppendInt(tok_info.firmwareVersion.major); michael@0: mTokenFWVersion.AppendLiteral("."); michael@0: mTokenFWVersion.AppendInt(tok_info.firmwareVersion.minor); michael@0: // Set the Serial Number field michael@0: const char *ccSerial = (const char*)tok_info.serialNumber; michael@0: const nsACString &cSerial = Substring( michael@0: ccSerial, michael@0: ccSerial+PL_strnlen(ccSerial, sizeof(tok_info.serialNumber))); michael@0: mTokenSerialNum = NS_ConvertUTF8toUTF16(cSerial); michael@0: mTokenSerialNum.Trim(" ", false, true); michael@0: } michael@0: michael@0: } michael@0: michael@0: nsPK11Token::~nsPK11Token() michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) { michael@0: return; michael@0: } michael@0: destructorSafeDestroyNSSReference(); michael@0: shutdown(calledFromObject); michael@0: } michael@0: michael@0: void nsPK11Token::virtualDestroyNSSReference() michael@0: { michael@0: destructorSafeDestroyNSSReference(); michael@0: } michael@0: michael@0: void nsPK11Token::destructorSafeDestroyNSSReference() michael@0: { michael@0: if (mSlot) { michael@0: PK11_FreeSlot(mSlot); michael@0: mSlot = nullptr; michael@0: } michael@0: } michael@0: michael@0: /* readonly attribute wstring tokenName; */ michael@0: NS_IMETHODIMP nsPK11Token::GetTokenName(char16_t * *aTokenName) michael@0: { michael@0: // handle removals/insertions michael@0: if (mSeries != PK11_GetSlotSeries(mSlot)) { michael@0: refreshTokenInfo(); michael@0: } michael@0: *aTokenName = ToNewUnicode(mTokenName); michael@0: if (!*aTokenName) return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute wstring tokenDesc; */ michael@0: NS_IMETHODIMP nsPK11Token::GetTokenLabel(char16_t **aTokLabel) michael@0: { michael@0: // handle removals/insertions michael@0: if (mSeries != PK11_GetSlotSeries(mSlot)) { michael@0: refreshTokenInfo(); michael@0: } michael@0: *aTokLabel = ToNewUnicode(mTokenLabel); michael@0: if (!*aTokLabel) return NS_ERROR_OUT_OF_MEMORY; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute wstring tokenManID; */ michael@0: NS_IMETHODIMP nsPK11Token::GetTokenManID(char16_t **aTokManID) michael@0: { michael@0: // handle removals/insertions michael@0: if (mSeries != PK11_GetSlotSeries(mSlot)) { michael@0: refreshTokenInfo(); michael@0: } michael@0: *aTokManID = ToNewUnicode(mTokenManID); michael@0: if (!*aTokManID) return NS_ERROR_OUT_OF_MEMORY; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute wstring tokenHWVersion; */ michael@0: NS_IMETHODIMP nsPK11Token::GetTokenHWVersion(char16_t **aTokHWVersion) michael@0: { michael@0: // handle removals/insertions michael@0: if (mSeries != PK11_GetSlotSeries(mSlot)) { michael@0: refreshTokenInfo(); michael@0: } michael@0: *aTokHWVersion = ToNewUnicode(mTokenHWVersion); michael@0: if (!*aTokHWVersion) return NS_ERROR_OUT_OF_MEMORY; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute wstring tokenFWVersion; */ michael@0: NS_IMETHODIMP nsPK11Token::GetTokenFWVersion(char16_t **aTokFWVersion) michael@0: { michael@0: // handle removals/insertions michael@0: if (mSeries != PK11_GetSlotSeries(mSlot)) { michael@0: refreshTokenInfo(); michael@0: } michael@0: *aTokFWVersion = ToNewUnicode(mTokenFWVersion); michael@0: if (!*aTokFWVersion) return NS_ERROR_OUT_OF_MEMORY; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute wstring tokenSerialNumber; */ michael@0: NS_IMETHODIMP nsPK11Token::GetTokenSerialNumber(char16_t **aTokSerialNum) michael@0: { michael@0: // handle removals/insertions michael@0: if (mSeries != PK11_GetSlotSeries(mSlot)) { michael@0: refreshTokenInfo(); michael@0: } michael@0: *aTokSerialNum = ToNewUnicode(mTokenSerialNum); michael@0: if (!*aTokSerialNum) return NS_ERROR_OUT_OF_MEMORY; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* boolean isLoggedIn (); */ michael@0: NS_IMETHODIMP nsPK11Token::IsLoggedIn(bool *_retval) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: nsresult rv = NS_OK; michael@0: michael@0: *_retval = PK11_IsLoggedIn(mSlot, 0); michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: /* void logout (in boolean force); */ michael@0: NS_IMETHODIMP michael@0: nsPK11Token::Login(bool force) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: nsresult rv; michael@0: SECStatus srv; michael@0: bool test; michael@0: rv = this->NeedsLogin(&test); michael@0: if (NS_FAILED(rv)) return rv; michael@0: if (test && force) { michael@0: rv = this->LogoutSimple(); michael@0: if (NS_FAILED(rv)) return rv; michael@0: } michael@0: rv = setPassword(mSlot, mUIContext); michael@0: if (NS_FAILED(rv)) return rv; michael@0: srv = PK11_Authenticate(mSlot, true, mUIContext); michael@0: return (srv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsPK11Token::LogoutSimple() michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: // PK11_MapError sets CKR_USER_NOT_LOGGED_IN to SEC_ERROR_LIBRARY_FAILURE, michael@0: // so not going to learn anything here by a failure. Treat it like void. michael@0: PK11_Logout(mSlot); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsPK11Token::LogoutAndDropAuthenticatedResources() michael@0: { michael@0: static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); michael@0: michael@0: nsresult rv = LogoutSimple(); michael@0: michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: nsCOMPtr nssComponent(do_GetService(kNSSComponentCID, &rv)); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: return nssComponent->LogoutAuthenticatedPK11(); michael@0: } michael@0: michael@0: /* void reset (); */ michael@0: NS_IMETHODIMP nsPK11Token::Reset() michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: PK11_ResetToken(mSlot, 0); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute long minimumPasswordLength; */ michael@0: NS_IMETHODIMP nsPK11Token::GetMinimumPasswordLength(int32_t *aMinimumPasswordLength) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: *aMinimumPasswordLength = PK11_GetMinimumPwdLength(mSlot); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute boolean needsUserInit; */ michael@0: NS_IMETHODIMP nsPK11Token::GetNeedsUserInit(bool *aNeedsUserInit) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: *aNeedsUserInit = PK11_NeedUserInit(mSlot); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* boolean checkPassword (in wstring password); */ michael@0: NS_IMETHODIMP nsPK11Token::CheckPassword(const char16_t *password, bool *_retval) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: SECStatus srv; michael@0: int32_t prerr; michael@0: NS_ConvertUTF16toUTF8 aUtf8Password(password); michael@0: srv = PK11_CheckUserPassword(mSlot, michael@0: const_cast(aUtf8Password.get())); michael@0: if (srv != SECSuccess) { michael@0: *_retval = false; michael@0: prerr = PR_GetError(); michael@0: if (prerr != SEC_ERROR_BAD_PASSWORD) { michael@0: /* something really bad happened - throw an exception */ michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: } else { michael@0: *_retval = true; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void initPassword (in wstring initialPassword); */ michael@0: NS_IMETHODIMP nsPK11Token::InitPassword(const char16_t *initialPassword) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: nsresult rv = NS_OK; michael@0: SECStatus status; michael@0: michael@0: NS_ConvertUTF16toUTF8 aUtf8InitialPassword(initialPassword); michael@0: status = PK11_InitPin(mSlot, "", const_cast(aUtf8InitialPassword.get())); michael@0: if (status == SECFailure) { rv = NS_ERROR_FAILURE; goto done; } michael@0: michael@0: done: michael@0: return rv; michael@0: } michael@0: michael@0: /* long getAskPasswordTimes(); */ michael@0: NS_IMETHODIMP michael@0: nsPK11Token::GetAskPasswordTimes(int32_t *rvAskTimes) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: int askTimes, askTimeout; michael@0: PK11_GetSlotPWValues(mSlot, &askTimes, &askTimeout); michael@0: *rvAskTimes = askTimes; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* long getAskPasswordTimeout(); */ michael@0: NS_IMETHODIMP michael@0: nsPK11Token::GetAskPasswordTimeout(int32_t *rvAskTimeout) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: int askTimes, askTimeout; michael@0: PK11_GetSlotPWValues(mSlot, &askTimes, &askTimeout); michael@0: *rvAskTimeout = askTimeout; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void setAskPasswordDefaults(in unsigned long askTimes, michael@0: * in unsigned long timeout); michael@0: */ michael@0: NS_IMETHODIMP michael@0: nsPK11Token::SetAskPasswordDefaults(const int32_t askTimes, michael@0: const int32_t askTimeout) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: PK11_SetSlotPWValues(mSlot, askTimes, askTimeout); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* void changePassword (in wstring oldPassword, in wstring newPassword); */ michael@0: NS_IMETHODIMP nsPK11Token::ChangePassword(const char16_t *oldPassword, const char16_t *newPassword) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: SECStatus rv; michael@0: NS_ConvertUTF16toUTF8 aUtf8OldPassword(oldPassword); michael@0: NS_ConvertUTF16toUTF8 aUtf8NewPassword(newPassword); michael@0: michael@0: rv = PK11_ChangePW(mSlot, michael@0: (oldPassword ? const_cast(aUtf8OldPassword.get()) : nullptr), michael@0: (newPassword ? const_cast(aUtf8NewPassword.get()) : nullptr)); michael@0: return (rv == SECSuccess) ? NS_OK : NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: /* boolean isHardwareToken (); */ michael@0: NS_IMETHODIMP nsPK11Token::IsHardwareToken(bool *_retval) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: nsresult rv = NS_OK; michael@0: michael@0: *_retval = PK11_IsHW(mSlot); michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: /* boolean needsLogin (); */ michael@0: NS_IMETHODIMP nsPK11Token::NeedsLogin(bool *_retval) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: nsresult rv = NS_OK; michael@0: michael@0: *_retval = PK11_NeedLogin(mSlot); michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: /* boolean isFriendly (); */ michael@0: NS_IMETHODIMP nsPK11Token::IsFriendly(bool *_retval) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: if (isAlreadyShutDown()) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: nsresult rv = NS_OK; michael@0: michael@0: *_retval = PK11_IsFriendly(mSlot); michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: /*=========================================================*/ michael@0: michael@0: NS_IMPL_ISUPPORTS(nsPK11TokenDB, nsIPK11TokenDB) michael@0: michael@0: nsPK11TokenDB::nsPK11TokenDB() michael@0: { michael@0: /* member initializers and constructor code */ michael@0: } michael@0: michael@0: nsPK11TokenDB::~nsPK11TokenDB() michael@0: { michael@0: /* destructor code */ michael@0: } michael@0: michael@0: /* nsIPK11Token getInternalKeyToken (); */ michael@0: NS_IMETHODIMP nsPK11TokenDB::GetInternalKeyToken(nsIPK11Token **_retval) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: nsresult rv = NS_OK; michael@0: PK11SlotInfo *slot = 0; michael@0: nsCOMPtr token; michael@0: michael@0: slot = PK11_GetInternalKeySlot(); michael@0: if (!slot) { rv = NS_ERROR_FAILURE; goto done; } michael@0: michael@0: token = new nsPK11Token(slot); michael@0: *_retval = token; michael@0: NS_ADDREF(*_retval); michael@0: michael@0: done: michael@0: if (slot) PK11_FreeSlot(slot); michael@0: return rv; michael@0: } michael@0: michael@0: /* nsIPK11Token findTokenByName (in wchar tokenName); */ michael@0: NS_IMETHODIMP nsPK11TokenDB:: michael@0: FindTokenByName(const char16_t* tokenName, nsIPK11Token **_retval) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: nsresult rv = NS_OK; michael@0: PK11SlotInfo *slot = 0; michael@0: NS_ConvertUTF16toUTF8 aUtf8TokenName(tokenName); michael@0: slot = PK11_FindSlotByName(const_cast(aUtf8TokenName.get())); michael@0: if (!slot) { rv = NS_ERROR_FAILURE; goto done; } michael@0: michael@0: *_retval = new nsPK11Token(slot); michael@0: NS_ADDREF(*_retval); michael@0: michael@0: done: michael@0: if (slot) PK11_FreeSlot(slot); michael@0: return rv; michael@0: } michael@0: michael@0: /* nsIEnumerator listTokens (); */ michael@0: NS_IMETHODIMP nsPK11TokenDB::ListTokens(nsIEnumerator* *_retval) michael@0: { michael@0: nsNSSShutDownPreventionLock locker; michael@0: nsCOMPtr array; michael@0: PK11SlotList *list = 0; michael@0: PK11SlotListElement *le; michael@0: michael@0: *_retval = nullptr; michael@0: nsresult rv = NS_NewISupportsArray(getter_AddRefs(array)); michael@0: if (NS_FAILED(rv)) { goto done; } michael@0: michael@0: /* List all tokens, creating PK11Token objects and putting them michael@0: * into the array. michael@0: */ michael@0: list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, false, false, 0); michael@0: if (!list) { rv = NS_ERROR_FAILURE; goto done; } michael@0: michael@0: for (le = PK11_GetFirstSafe(list); le; le = PK11_GetNextSafe(list, le, false)) { michael@0: nsCOMPtr token = new nsPK11Token(le->slot); michael@0: rv = array->AppendElement(token); michael@0: if (NS_FAILED(rv)) { michael@0: PK11_FreeSlotListElement(list, le); michael@0: rv = NS_ERROR_OUT_OF_MEMORY; michael@0: goto done; michael@0: } michael@0: } michael@0: michael@0: rv = array->Enumerate(_retval); michael@0: michael@0: done: michael@0: if (list) PK11_FreeSlotList(list); michael@0: return rv; michael@0: } michael@0: