relyea%netscape.com 162c530b16 Land BOB_WORK_BRANCH unto the tip.
remove lots of depricated files.
move some files to appropriate directories (pcertdb *_rand
associated headers to soft token, for instance)
rename several stan files which had the same name as other nss files.
remove depricated functions.


git-svn-id: svn://10.0.0.236/trunk@107628 18797224-902f-48f8-a5cc-f745e15eee43
2001-11-08 00:15:51 +00:00

538 lines
13 KiB
C

/*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the Netscape security libraries.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
* "GPL"), in which case the provisions of the GPL are applicable
* instead of those above. If you wish to allow use of your
* version of this file only under the terms of the GPL and not to
* allow others to use your version of this file under the MPL,
* indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by
* the GPL. If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the
* GPL.
*/
#ifdef DEBUG
static const char CVS_ID[] = "@(#) $RCSfile: devslot.c,v $ $Revision: 1.1 $ $Date: 2001-11-08 00:14:53 $ $Name: not supported by cvs2svn $";
#endif /* DEBUG */
#ifndef DEV_H
#include "dev.h"
#endif /* DEV_H */
#ifndef DEVM_H
#include "devm.h"
#endif /* DEVM_H */
#ifdef NSS_3_4_CODE
#include "pkcs11.h"
#else
#ifndef NSSCKEPV_H
#include "nssckepv.h"
#endif /* NSSCKEPV_H */
#endif /* NSS_3_4_CODE */
#ifndef CKHELPER_H
#include "ckhelper.h"
#endif /* CKHELPER_H */
#ifndef BASE_H
#include "base.h"
#endif /* BASE_H */
/* The flags needed to open a read-only session. */
static const CK_FLAGS s_ck_readonly_flags = CKF_SERIAL_SESSION;
/* In pk11slot.c, this was a no-op. So it is here also. */
static CK_RV PR_CALLBACK
nss_ck_slot_notify
(
CK_SESSION_HANDLE session,
CK_NOTIFICATION event,
CK_VOID_PTR pData
)
{
return CKR_OK;
}
/* maybe this should really inherit completely from the module... I dunno,
* any uses of slots where independence is needed?
*/
NSS_IMPLEMENT NSSSlot *
nssSlot_Create
(
NSSArena *arenaOpt,
CK_SLOT_ID slotID,
NSSModule *parent
)
{
NSSArena *arena;
nssArenaMark *mark;
NSSSlot *rvSlot;
NSSToken *token;
NSSUTF8 *slotName = NULL;
PRUint32 length;
PRBool newArena;
PRStatus nssrv;
CK_SLOT_INFO slotInfo;
CK_RV ckrv;
if (arenaOpt) {
arena = arenaOpt;
mark = nssArena_Mark(arena);
if (!mark) {
return (NSSSlot *)NULL;
}
newArena = PR_FALSE;
} else {
arena = NSSArena_Create();
if(!arena) {
return (NSSSlot *)NULL;
}
newArena = PR_TRUE;
}
rvSlot = nss_ZNEW(arena, NSSSlot);
if (!rvSlot) {
goto loser;
}
/* Get slot information */
ckrv = CKAPI(parent)->C_GetSlotInfo(slotID, &slotInfo);
if (ckrv != CKR_OK) {
/* set an error here, eh? */
goto loser;
}
/* Grab the slot description from the PKCS#11 fixed-length buffer */
length = nssPKCS11StringLength(slotInfo.slotDescription,
sizeof(slotInfo.slotDescription));
if (length > 0) {
slotName = nssUTF8_Create(arena, nssStringType_UTF8String,
(void *)slotInfo.slotDescription, length);
if (!slotName) {
goto loser;
}
}
if (!arenaOpt) {
/* Avoid confusion now - only set the slot's arena to a non-NULL value
* if a new arena is created. Otherwise, depend on the caller (having
* passed arenaOpt) to free the arena.
*/
rvSlot->arena = arena;
}
rvSlot->refCount = 1;
rvSlot->epv = parent->epv;
rvSlot->module = parent;
rvSlot->name = slotName;
rvSlot->slotID = slotID;
rvSlot->ckFlags = slotInfo.flags;
/* Initialize the token if present. */
if (slotInfo.flags & CKF_TOKEN_PRESENT) {
token = nssToken_Create(arena, slotID, rvSlot);
if (!token) {
goto loser;
}
}
rvSlot->token = token;
nssrv = nssArena_Unmark(arena, mark);
if (nssrv != PR_SUCCESS) {
goto loser;
}
return rvSlot;
loser:
if (newArena) {
nssArena_Destroy(arena);
} else {
if (mark) {
nssArena_Release(arena, mark);
}
}
/* everything was created in the arena, nothing to see here, move along */
return (NSSSlot *)NULL;
}
NSS_IMPLEMENT PRStatus
nssSlot_Destroy
(
NSSSlot *slot
)
{
if (--slot->refCount == 0) {
#ifndef NSS_3_4_CODE
/* Not going to do this in 3.4, maybe never */
nssToken_Destroy(slot->token);
#endif
if (slot->arena) {
return NSSArena_Destroy(slot->arena);
} else {
nss_ZFreeIf(slot);
}
}
return PR_SUCCESS;
}
NSS_IMPLEMENT NSSSlot *
nssSlot_AddRef
(
NSSSlot *slot
)
{
++slot->refCount;
return slot;
}
NSS_IMPLEMENT NSSUTF8 *
nssSlot_GetName
(
NSSSlot *slot,
NSSArena *arenaOpt
)
{
if (slot->name) {
return nssUTF8_Duplicate(slot->name, arenaOpt);
}
return (NSSUTF8 *)NULL;
}
static PRStatus
nssslot_login(NSSSlot *slot, nssSession *session,
CK_USER_TYPE userType, NSSCallback *pwcb)
{
PRStatus nssrv;
PRUint32 attempts;
PRBool keepTrying;
NSSUTF8 *password = NULL;
CK_ULONG pwLen;
CK_RV ckrv;
if (!pwcb->getPW) {
/* set error INVALID_ARG */
return PR_FAILURE;
}
keepTrying = PR_TRUE;
nssrv = PR_FAILURE;
attempts = 0;
while (keepTrying) {
nssrv = pwcb->getPW(slot->name, &attempts, pwcb->arg, &password);
if (nssrv != PR_SUCCESS) {
nss_SetError(NSS_ERROR_USER_CANCELED);
break;
}
pwLen = (CK_ULONG)nssUTF8_Length(password, &nssrv);
if (nssrv != PR_SUCCESS) {
break;
}
nssSession_EnterMonitor(session);
ckrv = CKAPI(slot)->C_Login(session->handle, userType,
(CK_CHAR_PTR)password, pwLen);
nssSession_ExitMonitor(session);
switch (ckrv) {
case CKR_OK:
case CKR_USER_ALREADY_LOGGED_IN:
slot->authInfo.lastLogin = PR_Now();
nssrv = PR_SUCCESS;
keepTrying = PR_FALSE;
break;
case CKR_PIN_INCORRECT:
nss_SetError(NSS_ERROR_INVALID_PASSWORD);
keepTrying = PR_TRUE; /* received bad pw, keep going */
break;
default:
nssrv = PR_FAILURE;
keepTrying = PR_FALSE;
break;
}
nss_ZFreeIf(password);
password = NULL;
++attempts;
}
nss_ZFreeIf(password);
return nssrv;
}
static PRStatus
nssslot_init_password(NSSSlot *slot, nssSession *rwSession, NSSCallback *pwcb)
{
NSSUTF8 *userPW = NULL;
NSSUTF8 *ssoPW = NULL;
PRStatus nssrv;
CK_ULONG userPWLen, ssoPWLen;
CK_RV ckrv;
if (!pwcb->getInitPW) {
/* set error INVALID_ARG */
return PR_FAILURE;
}
/* Get the SO and user passwords */
nssrv = pwcb->getInitPW(slot->name, pwcb->arg, &ssoPW, &userPW);
if (nssrv != PR_SUCCESS) goto loser;
userPWLen = (CK_ULONG)nssUTF8_Length(userPW, &nssrv);
if (nssrv != PR_SUCCESS) goto loser;
ssoPWLen = (CK_ULONG)nssUTF8_Length(ssoPW, &nssrv);
if (nssrv != PR_SUCCESS) goto loser;
/* First log in as SO */
ckrv = CKAPI(slot)->C_Login(rwSession->handle, CKU_SO,
(CK_CHAR_PTR)ssoPW, ssoPWLen);
if (ckrv != CKR_OK) {
/* set error ...SO_LOGIN_FAILED */
goto loser;
}
/* Now change the user PIN */
ckrv = CKAPI(slot)->C_InitPIN(rwSession->handle,
(CK_CHAR_PTR)userPW, userPWLen);
if (ckrv != CKR_OK) {
/* set error */
goto loser;
}
nss_ZFreeIf(ssoPW);
nss_ZFreeIf(userPW);
return PR_SUCCESS;
loser:
nss_ZFreeIf(ssoPW);
nss_ZFreeIf(userPW);
return PR_FAILURE;
}
static PRStatus
nssslot_change_password(NSSSlot *slot, nssSession *rwSession, NSSCallback *pwcb)
{
NSSUTF8 *userPW = NULL;
NSSUTF8 *newPW = NULL;
PRUint32 attempts;
PRStatus nssrv;
PRBool keepTrying = PR_TRUE;
CK_ULONG userPWLen, newPWLen;
CK_RV ckrv;
if (!pwcb->getNewPW) {
/* set error INVALID_ARG */
return PR_FAILURE;
}
attempts = 0;
while (keepTrying) {
nssrv = pwcb->getNewPW(slot->name, &attempts, pwcb->arg,
&userPW, &newPW);
if (nssrv != PR_SUCCESS) {
nss_SetError(NSS_ERROR_USER_CANCELED);
break;
}
userPWLen = (CK_ULONG)nssUTF8_Length(userPW, &nssrv);
if (nssrv != PR_SUCCESS) return nssrv;
newPWLen = (CK_ULONG)nssUTF8_Length(newPW, &nssrv);
if (nssrv != PR_SUCCESS) return nssrv;
nssSession_EnterMonitor(rwSession);
ckrv = CKAPI(slot)->C_SetPIN(rwSession->handle,
(CK_CHAR_PTR)userPW, userPWLen,
(CK_CHAR_PTR)newPW, newPWLen);
nssSession_ExitMonitor(rwSession);
switch (ckrv) {
case CKR_OK:
slot->authInfo.lastLogin = PR_Now();
nssrv = PR_SUCCESS;
keepTrying = PR_FALSE;
break;
case CKR_PIN_INCORRECT:
nss_SetError(NSS_ERROR_INVALID_PASSWORD);
keepTrying = PR_TRUE; /* received bad pw, keep going */
break;
default:
nssrv = PR_FAILURE;
keepTrying = PR_FALSE;
break;
}
nss_ZFreeIf(userPW);
nss_ZFreeIf(newPW);
userPW = NULL;
newPW = NULL;
++attempts;
}
nss_ZFreeIf(userPW);
nss_ZFreeIf(newPW);
return nssrv;
}
NSS_IMPLEMENT PRStatus
nssSlot_Login
(
NSSSlot *slot,
PRBool asSO,
NSSCallback *pwcb
)
{
PRBool needsLogin, needsInit;
CK_USER_TYPE userType;
userType = (asSO) ? CKU_SO : CKU_USER;
needsInit = PR_FALSE; /* XXX */
needsLogin = PR_TRUE; /* XXX */
if (needsInit) {
return nssSlot_SetPassword(slot, pwcb);
} else if (needsLogin) {
return nssslot_login(slot, slot->token->defaultSession,
userType, pwcb);
}
return PR_SUCCESS; /* login not required */
}
NSS_IMPLEMENT PRStatus
nssSlot_Logout
(
NSSSlot *slot,
nssSession *sessionOpt
)
{
nssSession *session;
PRStatus nssrv = PR_SUCCESS;
CK_RV ckrv;
session = (sessionOpt) ? sessionOpt : slot->token->defaultSession;
nssSession_EnterMonitor(session);
ckrv = CKAPI(slot)->C_Logout(session->handle);
nssSession_ExitMonitor(session);
if (ckrv != CKR_OK) {
/* translate the error */
nssrv = PR_FAILURE;
}
return nssrv;
}
NSS_IMPLEMENT void
nssSlot_SetPasswordDefaults
(
NSSSlot *slot,
PRInt32 askPasswordTimeout
)
{
slot->authInfo.askPasswordTimeout = askPasswordTimeout;
}
NSS_IMPLEMENT PRStatus
nssSlot_SetPassword
(
NSSSlot *slot,
NSSCallback *pwcb
)
{
PRStatus nssrv;
nssSession *rwSession;
PRBool needsInit;
needsInit = PR_FALSE; /* XXX */
rwSession = nssSlot_CreateSession(slot, NULL, PR_TRUE);
if (needsInit) {
nssrv = nssslot_init_password(slot, rwSession, pwcb);
} else {
nssrv = nssslot_change_password(slot, rwSession, pwcb);
}
nssSession_Destroy(rwSession);
return nssrv;
}
#ifdef PURE_STAN
NSS_IMPLEMENT nssSession *
nssSlot_CreateSession
(
NSSSlot *slot,
NSSArena *arenaOpt,
PRBool readWrite /* so far, this is the only flag used */
)
{
CK_RV ckrv;
CK_FLAGS ckflags;
CK_SESSION_HANDLE session;
nssSession *rvSession;
ckflags = s_ck_readonly_flags;
if (readWrite) {
ckflags |= CKF_RW_SESSION;
}
/* does the opening and closing of sessions need to be done in a
* threadsafe manner? should there be a "meta-lock" controlling
* calls like this?
*/
ckrv = CKAPI(slot)->C_OpenSession(slot->slotID, ckflags,
slot, nss_ck_slot_notify, &session);
if (ckrv != CKR_OK) {
/* set an error here, eh? */
return (nssSession *)NULL;
}
rvSession = nss_ZNEW(arenaOpt, nssSession);
if (!rvSession) {
return (nssSession *)NULL;
}
if (slot->module->flags & NSSMODULE_FLAGS_NOT_THREADSAFE) {
/* If the parent module is not threadsafe, create lock to manage
* session within threads.
*/
rvSession->lock = PZ_NewLock(nssILockOther);
if (!rvSession->lock) {
/* need to translate NSPR error? */
if (arenaOpt) {
} else {
nss_ZFreeIf(rvSession);
}
return (nssSession *)NULL;
}
}
rvSession->handle = session;
rvSession->slot = slot;
rvSession->isRW = readWrite;
return rvSession;
}
NSS_IMPLEMENT PRStatus
nssSession_Destroy
(
nssSession *s
)
{
CK_RV ckrv = CKR_OK;
if (s) {
ckrv = CKAPI(s->slot)->C_CloseSession(s->handle);
if (s->lock) {
PZ_DestroyLock(s->lock);
}
nss_ZFreeIf(s);
}
return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
}
#endif
NSS_IMPLEMENT PRStatus
nssSession_EnterMonitor
(
nssSession *s
)
{
if (s->lock) PZ_Lock(s->lock);
return PR_SUCCESS;
}
NSS_IMPLEMENT PRStatus
nssSession_ExitMonitor
(
nssSession *s
)
{
return (s->lock) ? PZ_Unlock(s->lock) : PR_SUCCESS;
}
NSS_EXTERN PRBool
nssSession_IsReadWrite
(
nssSession *s
)
{
return s->isRW;
}