gecko-dev/security/psm/server/password.c

1046 строки
32 KiB
C

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* 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.
*/
#include "connect.h"
#include "ssmerrs.h"
#include "ctrlconn.h"
#include "prinrval.h"
#include "crmf.h"
#include "newproto.h"
#include "messages.h"
#include "minihttp.h"
#include "textgen.h"
#include "sechash.h"
#include "pk11func.h"
extern SSMHashTable * tokenList;
extern PRMonitor * tokenLock;
#define SSMRESOURCE(conn) (&(conn)->super)
/* Make these into functions? */
#if 0
#define SSM_PARENT_CONN(x) ((((SSMConnection *)(x))->m_parent) != NULL)? \
(((SSMControlConnection *)(((SSMConnection *)(x))->m_parent))):\
((SSMControlConnection *)x)
#define SSM_PWD_TABLE(x) (SSM_PARENT_CONN(x))->m_passwdTable
#define SSM_OUT_QUEUE(x) (SSM_PARENT_CONN(x))->m_controlOutQ
#endif
#if 1
SSMControlConnection * SSM_PARENT_CONN (SSMConnection * x)
{
return (((((SSMConnection *)(x))->m_parent) != NULL)?
(((SSMControlConnection *)(((SSMConnection *)(x))->m_parent))):
((SSMControlConnection *)x));
}
SSMHashTable * SSM_PWD_TABLE(SSMConnection * x)
{
return (SSM_PARENT_CONN(x)->m_passwdTable);
}
SSMCollection * SSM_OUT_QUEUE(SSMConnection * x)
{
return (SSM_PARENT_CONN(x)->m_controlOutQ);
}
#endif
PRInt32 SSM_GetTokenKey(PK11SlotInfo * slot)
{
return ((PK11_GetSlotID(slot)<<16) | PK11_GetModuleID(slot));
}
char * SSM_GetPasswdCallback(PK11SlotInfo *slot, PRBool retry, void *arg)
{
return SSM_GetAuthentication(slot, retry, PR_FALSE, (SSMResource*)arg);
}
/* Do a couple of things in this functions:
* 1) Get a password from user, and authenticate to token.
* 2) Save this password encrypted in the global Cartman tokenList
* for future reference.
* Need to save password in case other users will need to authenticate
* to the same tokens, so we make sure they're using the correct
* passwords.
* 3) Save this password encrypted in the control connection table in
* case we will need to use it again.
*/
char * SSM_GetAuthentication(PK11SlotInfo * slot, PRBool retry, PRBool init,
SSMResource * res)
{
PRInt32 tokenKey;
SSMStatus rv = PR_SUCCESS;
char * passwd = NULL, * tmp = NULL;
PRBool first = PR_FALSE;
SSM_TokenInfo * info = NULL, * infoLocal = NULL;
SSMConnection *conn = &(res->m_connection->super);
tokenKey = SSM_GetTokenKey(slot);
/* register as interested in a password */
SSM_PARENT_CONN(conn)->m_waiting++;
/* Get passwd table lock. */
SSM_LockPasswdTable(conn);
/* Look for entry for moduleID/slotID. */
rv = SSM_HashFind(SSM_PWD_TABLE(conn), tokenKey, (void **)&passwd);
SSM_UnlockPasswdTable(conn);
if (rv != PR_SUCCESS) {
first = PR_TRUE;
/* no entry found, we are the first to authenticate to this slot */
SSM_DEBUG("%ld: creating passwd table entry for %s \n",
conn, PK11_GetSlotName(slot));
SSM_LockPasswdTable(conn);
rv = SSM_HashInsert(SSM_PWD_TABLE(conn),tokenKey,(void *)SSM_NO_PASSWORD);
SSM_UnlockPasswdTable(conn);
if (rv != PR_SUCCESS) {
SSM_DEBUG("%ld: could not create entry in password table\n", conn);
goto loser;
}
rv = SSM_AskUserPassword(res, slot, retry, init);
if (rv != PR_SUCCESS) {
SSM_DEBUG("%ld: error sending password request event\n", conn);
goto loser;
}
} /* end of the we-are-first-to-request-this-passwd-clause */
/* If no password found, wait for it */
if (!passwd || passwd == (char *)SSM_NO_PASSWORD) {
rv = SSMControlConnection_WaitPassword(conn, tokenKey, &passwd);
if (rv != PR_SUCCESS)
goto loser;
}
if (((int) passwd) == SSM_CANCEL_PASSWORD) {
/* no password was provided or user hit "Cancel" */
SSM_LockPasswdTable(conn);
rv = SSM_HashRemove(SSM_PWD_TABLE(conn), tokenKey, (void **)&passwd);
SSM_UnlockPasswdTable(conn);
if (rv != SSM_SUCCESS)
SSM_DEBUG("SSM_GetAuthentication: user hit Cancel, can't remove password from connection table\n");
passwd = NULL;
goto done;
}
if (first) {
/* We were the first to request the password,
* so we need to enter it in to the token list.
*/
/* encrypt the password */
if (SSM_EncryptPasswd(slot, passwd, &info) != SSM_SUCCESS) {
SSM_DEBUG("%ld: could not encrypt password\n.", conn);
goto loser;
}
/* Place encrypted passwd in Cartman-wide tokenList */
PR_EnterMonitor(tokenLock);
/* Remove from tokenList if already on the list - must be stale */
rv = SSM_HashRemove(tokenList, tokenKey, (void **)&tmp);
if (rv == SSM_SUCCESS && tmp && tmp != (char *)SSM_NO_PASSWORD
&& tmp != (char *)SSM_CANCEL_PASSWORD) { /* free stale data */
PR_Free(tmp);
tmp = NULL;
}
rv = SSM_HashInsert(tokenList, tokenKey, info);
PR_ExitMonitor(tokenLock);
if (rv != PR_SUCCESS) {
SSM_DEBUG("%ld: can't create encr passwd entry\n", conn, tokenKey);
goto loser;
}
/* Store encrypted password in control connection table */
infoLocal = (SSM_TokenInfo *) PORT_ZAlloc(sizeof(SSM_TokenInfo));
if (!infoLocal)
goto loser;
infoLocal->slot = info->slot;
infoLocal->tokenID = info->tokenID;
infoLocal->encryptedLen = info->encryptedLen;
infoLocal->symKey = info->symKey;
infoLocal->encrypted = (char *) PORT_ZAlloc(info->encryptedLen);
if (!infoLocal->encrypted)
goto loser;
memcpy(infoLocal->encrypted, info->encrypted, info->encryptedLen);
PR_EnterMonitor(SSM_PARENT_CONN(conn)->m_encrPasswdLock);
rv = SSM_HashRemove(SSM_PARENT_CONN(conn)->m_encrPasswdTable, tokenKey,
(void **)&tmp);
if (rv == SSM_SUCCESS && tmp && tmp != (char *)SSM_NO_PASSWORD &&
tmp != (char *)SSM_CANCEL_PASSWORD ) {/* free stale data */
PR_Free(tmp);
tmp = NULL;
}
rv = SSM_HashInsert(SSM_PARENT_CONN(conn)->m_encrPasswdTable, tokenKey,
infoLocal);
PR_ExitMonitor(SSM_PARENT_CONN(conn)->m_encrPasswdLock);
if (rv != PR_SUCCESS) {
SSM_DEBUG("%ld: cannot insert token %d entry in encrPasswdTable\n",
conn, tokenKey);
goto loser;
}
SSM_DEBUG("%ld: wait untill others are done with passwd, remove it\n",
conn);
/* while ((SSM_PARENT_CONN(conn))->m_waiting > 1)
* PR_Sleep(SSM_PASSWORD_WAIT_TIME);
*/
SSM_LockPasswdTable(conn);
rv = SSM_HashRemove(SSM_PWD_TABLE(conn), tokenKey, (void **)&passwd);
if (rv != PR_SUCCESS) {
SSM_DEBUG("%ld: could not remove passwd.\n", conn);
goto loser;
}
SSM_UnlockPasswdTable(conn);
} /* end of if-first clause */
goto done;
loser:
/* cleanup */
PR_FREEIF(passwd);
passwd = NULL;
if (info) {
PR_FREEIF(info->encrypted);
PR_Free(info);
}
if (infoLocal) {
PR_FREEIF(infoLocal->encrypted);
PR_Free(infoLocal);
}
done:
/* We are done receiving passwd */
(SSM_PARENT_CONN(conn))->m_waiting--;
return passwd ? strdup (passwd) : NULL;
}
/*
* We get this callback if the slot is already logged-in.
* Need to check client-supplied password against the password stored in
* tokenList.
*/
PRBool SSM_VerifyPasswdCallback(PK11SlotInfo * slot, void * arg)
{
char * passwd = NULL;
PRInt32 tokenKey;
SSM_TokenInfo * info = NULL;
SSM_TokenInfo * tokenInfo = NULL;
SSMStatus rv;
PRBool result = PR_FALSE;
SSMResource * res = (SSMResource*)arg;
SSMConnection * conn = &(res->m_connection->super);
PRInt32 doTry = 0;
void * tmp = NULL;
if (!slot || !arg)
goto loser;
tokenKey = PK11_GetSlotID(slot) ^ PK11_GetModuleID(slot);
info = (SSM_TokenInfo *) PORT_ZAlloc(sizeof(SSM_TokenInfo));
if (!info) {
SSM_DEBUG("Could not allocate memory in VerifyPasswdCallback.\n");
goto loser;
}
/* Get the password for this token.
* We might have to find it in the local encrypted password table or
* to request it from the client.
*/
rv = SSM_HashFind(SSM_PARENT_CONN(conn)->m_encrPasswdTable, tokenKey,
(void **)&info);
if (rv != PR_SUCCESS || info == (void *)SSM_NO_PASSWORD) {
askpassword:
/* ask user for a password and store it in local passwd table */
rv = SSM_AskUserPassword(res, slot, doTry?PR_TRUE:PR_FALSE, PR_FALSE);
if (rv != PR_SUCCESS)
goto loser;
doTry++;
rv = SSMControlConnection_WaitPassword(conn, tokenKey, &passwd);
if (rv != PR_SUCCESS || !passwd)
goto loser;
rv = SSM_EncryptPasswd(slot, passwd, &info);
if (rv != SSM_SUCCESS)
goto loser;
} /* end of no password, ask user */
/* Now get the stored password for this token */
if (!tokenInfo) {
PR_EnterMonitor(tokenLock);
rv = SSM_HashFind(tokenList, tokenKey, (void **)&tokenInfo);
PR_ExitMonitor(tokenLock);
if (rv != PR_SUCCESS || !tokenInfo) {
SSM_DEBUG("Can't find token info in VerifyPasswd.\n");
goto loser;
}
}
/* Check password against tokenList entry */
if (memcmp(tokenInfo->encrypted, info->encrypted, tokenInfo->encryptedLen)
!= 0 || tokenInfo->encryptedLen != info->encryptedLen) {
/* Failed compare, bad password */
/* first clean up */
if (info) PR_Free(info);
info = NULL;
/* If not retry, ask client for password. */
if (doTry < 2 ) {
/* ask user again */
PR_Free(passwd);
passwd = NULL;
goto askpassword;
}
else
goto loser;
} /* end of password not verified */
SSM_DEBUG("Password verified OK.\n");
/* store password for local use */
PR_EnterMonitor(SSM_PARENT_CONN(conn)->m_encrPasswdLock);
SSM_HashRemove(SSM_PARENT_CONN(conn)->m_encrPasswdTable, tokenKey,
(void **)&tmp);
if (tmp && tmp != (char *)SSM_NO_PASSWORD ) {/* free stale data */
PR_Free(tmp);
tmp = NULL;
}
rv = SSM_HashInsert(SSM_PARENT_CONN(conn)->m_encrPasswdTable, tokenKey,
info);
PR_ExitMonitor(SSM_PARENT_CONN(conn)->m_encrPasswdLock);
if (rv != PR_SUCCESS) {
SSM_DEBUG("%ld: cannot insert token %d entry in encrPasswdTable\n",
conn, tokenKey);
goto loser;
}
result = PR_TRUE;
goto done;
loser:
SSM_DEBUG("Password not verified. \n");
/* log out this slot?? */
if (info) {
if (info->encrypted)
PR_Free(info->encrypted);
PR_Free(info);
}
result = PR_FALSE;
done:
if (passwd)
PR_Free(passwd);
return result;
}
/* Encrypt password for storage */
#define SSM_PAD_BLOCK_SIZE(x, y) ((((x) + ((y)-1))/(y))*(y))
SSMStatus SSM_EncryptPasswd(PK11SlotInfo * slot, char * passwd,
SSM_TokenInfo ** tokenInfo)
{
int resultLen;
char *hashResult = NULL;
SSMStatus rv = SSM_SUCCESS;
SECStatus srv;
SSM_TokenInfo * info;
/* Hash the password. */
resultLen = HASH_ResultLen(HASH_AlgSHA1);
hashResult = (char *) PORT_ZAlloc(resultLen); /* because the original PORT_ZAlloc'd */
if (!hashResult)
goto loser;
srv = HASH_HashBuf(HASH_AlgSHA1, (unsigned char *) hashResult, (unsigned char *) passwd, strlen(passwd));
if (srv != SECSuccess)
goto loser;
/* fill in the tokenInfo structure */
info = (SSM_TokenInfo *) PORT_ZAlloc(sizeof(SSM_TokenInfo));
if (!info) {
SSM_DEBUG("EncryptPwd: could not allocate memory to token list entry.\n");
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
goto loser;
}
info->encrypted = hashResult;
info->encryptedLen = resultLen;
info->slot = slot;
info->tokenID = SSM_GetTokenKey(slot);
*tokenInfo = info;
goto done;
loser:
if (rv == SSM_SUCCESS) rv = SSM_FAILURE;
PR_FREEIF(hashResult);
done:
return rv;
}
SSMStatus SSM_NotEncryptPasswd(PK11SlotInfo * slot, char * passwd,
SSM_TokenInfo * info)
{
CK_MECHANISM_TYPE mechanism;
/* CK_SESSION_HANDLE session = CK_INVALID_SESSION; */
PRInt32 keyLength, blockSize, outlen;
PRUint32 encryptedLength;
PK11SymKey * symKey;
SECStatus rv;
char * encrypted = NULL;
PK11Context * context=NULL;
SECItem *params;
if (!slot || !passwd || !info) {
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
goto loser;
}
mechanism = CRMF_GetBestWrapPadMechanism(slot);
keyLength = PK11_GetBestKeyLength(slot, mechanism);
/* session = PK11_GetRWSession(slot);
if (session == CK_INVALID_SESSION)
goto loser;*/
blockSize = PK11_GetBlockSize(mechanism, NULL);
/*
* A password is encrypted when we first authenticate to token.
* In this case, generate a symmetric Key on the slot.
* If the key is already present, it means that the password for this
* slot has already been encrypted and stored, need to encrypt
* new password with the same key to compare against the stored
* password.
*/
/* If no symKey found, generate one */
if (!info->symKey) {
symKey = PK11_KeyGen(slot, mechanism, NULL, keyLength, NULL);
if (!symKey) {
SSM_DEBUG("Failed to generate symKey to encrypt passwd.\n");
goto loser;
}
} else
symKey = info->symKey;
encryptedLength = SSM_PAD_BLOCK_SIZE(strlen(passwd)+1, blockSize);
encrypted = (char *) PORT_ZAlloc(encryptedLength);
if (!encrypted) {
SSM_DEBUG("Could not allocate space for encrypted password. \n");
goto loser;
}
params = CRMF_GetIVFromMechanism(mechanism);
context=PK11_CreateContextBySymKey(mechanism, CKA_ENCRYPT,
symKey, params);
if (params != NULL) {
SECITEM_FreeItem(params, PR_TRUE);
}
if (!context) {
SSM_DEBUG("Can't create context to encrypt password: %d.\n",
PR_GetError());
goto loser;
}
rv = PK11_CipherOp(context, (unsigned char *) encrypted, &outlen,
(int) encryptedLength,
(unsigned char *) passwd, strlen(passwd));
if (rv != PR_SUCCESS) {
SSM_DEBUG("Error encrypting password: %d\n", PR_GetError());
goto loser;
}
rv = PK11_DigestFinal(context, (unsigned char *) &encrypted[outlen],
(unsigned int *) &outlen, (unsigned int) blockSize);
if (rv != PR_SUCCESS) {
SSM_DEBUG("Error encrypting password: %d\n", PR_GetError());
goto loser;
}
PK11_DestroyContext(context, PR_TRUE);
/*if (session != CK_INVALID_SESSION)
PK11_RestoreROSession(slot, session);*/
/* fill in the tokenInfo structure */
info->encrypted = encrypted;
info->encryptedLen = encryptedLength;
info->slot = slot;
return SSM_SUCCESS;
loser:
SSM_DEBUG("Failed to encrypt password.\n");
if (context != NULL)
PK11_DestroyContext(context, PR_TRUE);
/*if (session != CK_INVALID_SESSION)
PK11_RestoreROSession(slot, session);*/
if (encrypted && *encrypted)
PR_Free(encrypted);
return SSM_FAILURE;
}
/* Needs to be fixed using NLS lib and proper string storage. -jane */
char * SSM_GetPrompt(PK11SlotInfo *slot, PRBool retry, PRBool init)
{
char * prompt = NULL, * tmp = NULL, * key;
SSMTextGenContext * cx;
SSMStatus rv;
PR_ASSERT(init != PR_TRUE);
rv = SSMTextGen_NewTopLevelContext(NULL, &cx);
if (rv != SSM_SUCCESS || !cx)
goto loser;
if (retry)
key = "retry_token_password";
else
key = "ask_token_password";
rv = SSM_GetAndExpandTextKeyedByString(cx, key, &tmp);
if (rv != SSM_SUCCESS || !tmp)
goto loser;
prompt = PR_smprintf(tmp, PK11_GetTokenName(slot));
loser:
PR_FREEIF(tmp);
return prompt;
}
/* Send a password request for the client */
SSMStatus SSM_AskUserPassword(SSMResource * res,
PK11SlotInfo * slot, PRInt32 retry, PRBool init)
{
SECItem message;
char * prompt = NULL;
PRInt32 tokenKey = SSM_GetTokenKey(slot);
SSMStatus rv = PR_FAILURE;
SSMConnection *conn = (SSMConnection *)res->m_connection;
PasswordRequest request;
prompt = SSM_GetPrompt(slot, retry, init);
retry++;
if (!prompt) {
SSM_DEBUG("%ld: error getting prompt for password request.\n", conn);
goto loser;
}
request.tokenKey = tokenKey;
request.prompt = prompt;
request.clientContext = res->m_clientContext;
if (CMT_EncodeMessage(PasswordRequestTemplate, (CMTItem*)&message, &request) != CMTSuccess) {
goto loser;
}
if (message.len == 0 || !message.data) {
SSM_DEBUG("%ld: could not create password request message.\n", conn);
goto loser;
}
message.type = (SECItemType) (SSM_EVENT_MESSAGE | SSM_AUTH_EVENT);
rv = SSM_SendQMessage(SSM_OUT_QUEUE(conn), SSM_PRIORITY_UI, message.type,
message.len, (char *)message.data, PR_TRUE);
if (rv != PR_SUCCESS) {
SSM_DEBUG("%ld: Can't enqueue password request. \n", conn);
goto loser;
}
loser:
if (prompt)
PR_Free(prompt);
if (message.data)
PR_Free(message.data);
return rv;
}
SSMStatus SSMControlConnection_WaitPassword(SSMConnection * conn,
PRInt32 key, char ** str)
{
char * passwd;
PRIntervalTime before;
SSMStatus rv = PR_FAILURE;
*str = NULL;
/* Wait no longer than our time-out period. */
before = PR_IntervalNow();
SSM_LockPasswdTable(conn);
wait:
SSM_DEBUG("%ld : waiting on password table for the password\n", conn);
SSM_WaitPasswdTable(conn);
/* Returned from wait.
* Look for password.
*/
rv = SSM_HashFind(SSM_PWD_TABLE(conn), key, (void **)&passwd);
if (rv!=PR_SUCCESS || !passwd || passwd ==(char *)SSM_NO_PASSWORD) {
/* password not found, check for timeout */
if (PR_IntervalNow() - before > SSM_PASSWORD_WAIT_TIME) {
SSM_DEBUG("%ld:Timed out waiting for password.Bailing out.\n",
conn);
SSM_UnlockPasswdTable(conn);
return PR_FAILURE;
}
else
goto wait; /* continue waiting */
} /* end of no password found */
SSM_UnlockPasswdTable(conn);
*str = passwd;
return rv;
}
extern PK11SlotListElement *
PK11_GetNextSafe(PK11SlotList * list, PK11SlotListElement * element,PRBool start);
PK11SlotListElement *
ssm_GetSlotWithPwd(PK11SlotList * slotlist, PK11SlotListElement * current,
PRBool start)
{
PK11SlotListElement * next = NULL;
PR_ASSERT(slotlist);
if (!current || start)
next = PK11_GetFirstSafe(slotlist);
else
next = PK11_GetNextSafe(slotlist, current, PR_FALSE);
while (next &&
PK11_NeedUserInit(next->slot) &&
!PK11_NeedLogin(next->slot) )
next = PK11_GetNextSafe(slotlist, next, PR_FALSE);
return next;
}
PRIntn
ssm_NumSlotsWithPassword(PK11SlotList * slotList)
{
PRIntn numslots = 0;
PK11SlotListElement * element = PK11_GetFirstSafe(slotList);
while (element) {
if (PK11_NeedLogin(element->slot) || !PK11_NeedUserInit(element->slot))
numslots++;
element = PK11_GetNextSafe(slotList, element,PR_FALSE);
}
return numslots;
}
char*
SSM_GetSlotNameForPasswordChange(HTTPRequest * req)
{
PK11SlotList *slotList = NULL;
PK11SlotInfo *slot=NULL;
PK11SlotListElement *listElem = NULL;
SSMResource *target;
char *slotName=NULL;
SSMStatus rv;
slotName = NULL;
target = REQ_TARGET(req);
slotList = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_TRUE,
PR_TRUE, target);
if (!slotList || !slotList->head)
goto loser;
if (ssm_NumSlotsWithPassword(slotList)>1) {
char * mech = PR_smprintf("mech=%d&unused1=unused1&unused2=unused2",
CKM_INVALID_MECHANISM);
SSM_LockUIEvent(target);
rv = SSMControlConnection_SendUIEvent(req->ctrlconn,
"get", "select_token",
target,mech,
&target->m_clientContext,
PR_TRUE);
SSM_WaitUIEvent(target, PR_INTERVAL_NO_TIMEOUT);
slot = (PK11SlotInfo *) target->m_uiData;
if (!slot)
goto loser;
} else {
listElem = ssm_GetSlotWithPwd(slotList, NULL, PR_TRUE);
slot = listElem->slot;
}
if (!slot) {
goto loser;
}
slotName = PK11_GetTokenName(slot);
PK11_FreeSlot(slot);
PK11_FreeSlotList(slotList);
return PL_strdup(slotName);
loser:
if (slot)
PK11_FreeSlot(slot);
if (slotList)
PK11_FreeSlotList(slotList);
return NULL;
}
SSMStatus SSM_ReSetPasswordKeywordHandler(SSMTextGenContext * cx)
{
char * slotname = NULL;
PK11SlotInfo * slot;
char * tmp = NULL;
SSMStatus rv;
SSMResource * target = cx->m_request->target;
PK11SlotList * slotList = NULL;
PK11SlotListElement * el = NULL;
PR_ASSERT(cx != NULL);
PR_ASSERT(cx->m_request != NULL);
PR_ASSERT(&cx->m_result != NULL);
rv = SSM_HTTPParamValue(cx->m_request, "action", &slotname);
if (!slotname || strcmp(slotname, "")== 0)
slot = PK11_GetInternalKeySlot();
else if (strcmp(slotname, "all") == 0) {
char *userSlotName = NULL;
/* ask user */
userSlotName = SSM_GetSlotNameForPasswordChange(cx->m_request);
if (!userSlotName)
goto cancel;
slot = PK11_FindSlotByName(userSlotName);
PR_Free(userSlotName);
}
else
slot = PK11_FindSlotByName(slotname);
if (!slot) {
SSM_DEBUG("ReSetPasswordKeywordHandler: bad slotname %s\n", slotname);
goto loser;
}
slotname = PK11_GetTokenName(slot);
if (PK11_NeedPWInitForSlot(slot))
rv = SSM_GetAndExpandTextKeyedByString(cx, "set_new_password", &tmp);
else
rv = SSM_GetAndExpandTextKeyedByString(cx, "reset_password", &tmp);
if (rv != SSM_SUCCESS)
goto loser;
PR_FREEIF(cx->m_result);
cx->m_result = PR_smprintf(tmp, slotname);
return rv;
loser:
if (cx->m_result)
PR_Free(cx->m_result);
cx->m_result = NULL;
return PR_FAILURE;
cancel:
SSM_HTTPCloseWindow(cx->m_request);
goto loser;
}
PRBool
ssm_VerifyPwdLength(char * password)
{
if (!password)
return (!SSM_MIN_PWD_LEN);
if (strlen(password) < SSM_MIN_PWD_LEN)
return PR_FALSE;
if (strlen(password) > SSM_MAX_PWD_LEN)
return PR_FALSE;
return PR_TRUE;
}
SSMStatus SSM_PasswordPrefKeywordHandler(SSMTextGenContext * cx)
{
char * fmt = NULL, * checked = NULL;
char * markchecked[] = { "", "", ""};
SSMStatus rv;
PRIntn askpw, timeout;
PR_ASSERT(cx != NULL);
PR_ASSERT(cx->m_request != NULL);
PR_ASSERT(cx->m_result != NULL);
/* need to get the table and fill it with current preferences */
rv = SSM_GetAndExpandTextKeyedByString(cx, "password_lifetime", &fmt);
if (rv != SSM_SUCCESS || !fmt)
goto done;
rv = SSM_GetAndExpandTextKeyedByString(cx, "text_checked", &checked);
if (rv != SSM_SUCCESS || !checked)
goto done;
rv = PREF_GetIntPref(cx->m_request->ctrlconn->m_prefs,
"security.ask_for_password", &askpw);
if (rv != SSM_SUCCESS)
goto done;
rv = PREF_GetIntPref(cx->m_request->ctrlconn->m_prefs,
"security.password_lifetime", &timeout);
if (rv != SSM_SUCCESS)
goto done;
markchecked[askpw] = checked;
PR_FREEIF(cx->m_result);
cx->m_result = PR_smprintf(fmt, markchecked[0], markchecked[1],
markchecked[2], timeout);
done:
return rv;
}
SSMStatus SSM_SetDBPasswordHandler(HTTPRequest * req)
{
SSMStatus rv = SSM_FAILURE;
char * oldpassword, * newpassword, *repeatpassword, * action;
PK11SlotInfo * slot;
char * responseKey = NULL;
char * result = NULL;
char * slotname = NULL, * askpwdoption, * pwdlifetime;
PRIntn askpw, timeout;
rv = SSM_HTTPParamValue(req, "baseRef", &action);
if (rv != SSM_SUCCESS || strcmp(action, "windowclose_doclose_js")!= 0)
SSM_DEBUG("SetDBPasswordHandler: bad action %s\n", action);
rv = SSM_HTTPParamValue(req, "slot", &slotname);
if (rv != SSM_SUCCESS || !slotname ||
!(slot = PK11_FindSlotByName(slotname)))
goto loser;
/* process password preferences */
rv = SSM_HTTPParamValue(req, "passwordlife", &askpwdoption);
if (rv != SSM_SUCCESS || !askpwdoption)
goto loser;
rv = SSM_HTTPParamValue(req, "passwordwillexpire", &pwdlifetime);
if (rv != SSM_SUCCESS || !pwdlifetime)
goto loser;
if (strcmp(askpwdoption, "firsttime") == 0)
askpw = 0;
else if (strcmp(askpwdoption, "everytime") == 0)
askpw = 1;
else if (strcmp(askpwdoption, "expiretime")==0) {
askpw = 2;
}
else {
SSM_DEBUG("SetDBPasswordHandler: bad password lifetime parameter %s\n",
askpwdoption);
goto loser;
}
timeout = atoi(pwdlifetime);
if (askpw == 2 && !timeout)
goto loser;
PK11_SetSlotPWValues(slot, askpw, timeout);
rv = SSMControlConnection_SaveIntPref(req->ctrlconn,
"security.ask_for_password", askpw);
if (rv != PR_SUCCESS)
goto loser;
rv = SSMControlConnection_SaveIntPref(req->ctrlconn,
"security.password_lifetime", timeout);
if (rv != SSM_SUCCESS)
goto loser;
rv = SSM_HTTPParamValue(req, "newpassword", &newpassword);
if (rv != SSM_SUCCESS)
goto loser;
rv = SSM_HTTPParamValue(req, "repeatpassword", &repeatpassword);
if (rv != SSM_SUCCESS)
goto loser;
if (!PK11_NeedPWInitForSlot(slot)) {
/* oldpassword doesn't make sense for password initialization dialog */
rv = SSM_HTTPParamValue(req, "oldpassword", &oldpassword);
if (rv != SSM_SUCCESS) {
goto loser;
}
/* we do this check to find the case where the user changed only password
* settings, not the password itself
*/
if ((oldpassword[0] == '\0') && (newpassword[0] == '\0') &&
(repeatpassword[0] == '\0')) {
rv = SSM_HTTPDefaultCommandHandler(req);
goto done;
}
}
if (!ssm_VerifyPwdLength(newpassword))
goto loser;
if (strcmp(newpassword, repeatpassword) != 0)
goto loser;
if (!PK11_NeedPWInitForSlot(slot)) { /* there is some password on the DB */
if (!oldpassword)
goto loser;
if (PK11_CheckUserPassword(slot, oldpassword) !=
SECSuccess)
goto loser;
if (PK11_ChangePW(slot, oldpassword, newpassword) !=
SECSuccess)
goto loser;
}
else
{
if (PK11_NeedUserInit(slot)) {
if (PK11_InitPin(slot, NULL, newpassword) != SECSuccess)
goto loser;
}
else {
if (PK11_ChangePW(slot, NULL, newpassword) != SECSuccess)
goto loser;
}
}
result = PR_smprintf("result=password_success");
loser:
if (!result)
result = PR_smprintf("result=password_failure");
rv = SSM_HTTPCloseAndSleep(req);
if (rv != SSM_SUCCESS)
SSM_DEBUG("SetDBPasswordHandler: failure in DefaultCommandHandler\n");
/* post status if password dialog was invoked from the SecurityAdvisor */
if (SSM_IsA(req->target, SSM_RESTYPE_SECADVISOR_CONTEXT))
SSMControlConnection_SendUIEvent(req->ctrlconn, "get",
"show_followup", NULL,
result,
&((SSMResource *)req->ctrlconn)->m_clientContext,
PR_TRUE);
PR_FREEIF(responseKey);
done:
if (req->target && req->target->m_UILock)
SSM_NotifyUIEvent(req->target);
return rv;
}
SSMStatus SSM_ShowFollowupKeywordHandler(SSMTextGenContext * cx)
{
char * resultvalue;
SSMStatus rv;
PR_ASSERT(cx != NULL);
PR_ASSERT(cx->m_request != NULL);
PR_ASSERT(cx->m_result != NULL);
rv = SSM_HTTPParamValue(cx->m_request, "result", &resultvalue);
if (rv != SSM_SUCCESS || !resultvalue)
goto loser;
if (!strcmp(resultvalue, "password_success"))
rv = SSM_GetAndExpandTextKeyedByString(cx, "set_password_success",
&cx->m_result);
else if (!strcmp(resultvalue,"password_failure"))
rv = SSM_GetAndExpandTextKeyedByString(cx, "set_password_failure",
&cx->m_result);
else if (!strcmp(resultvalue, "no_ldap_setup"))
rv = SSM_GetAndExpandTextKeyedByString(cx, "no_ldap_server_set",
&cx->m_result);
loser:
return rv;
}
char *
SSM_SetPasswordHTMLParamsFromTokenName(char *tokenName)
{
char *url = NULL;
tokenName = SSM_ConvertStringToHTMLString(tokenName);
url = PR_smprintf("slot=%s&mechanism=%d", tokenName,
CKM_INVALID_MECHANISM);
PR_Free(tokenName);
return url;
}
char *
SSM_SetPasswordHTMLParams(PK11SlotInfo *slot) {
return SSM_SetPasswordHTMLParamsFromTokenName(PK11_GetTokenName(slot));
}
char * SSM_GenerateChangePasswordURL(PK11SlotInfo *slot, SSMResource *target)
{
PRUint32 width, height;
char *slotHTMLName = NULL, *url = NULL, *extraParams = NULL;
SSMStatus rv;
if (slot) {
slotHTMLName =
SSM_ConvertStringToHTMLString(PK11_GetTokenName(slot));
} else {
slotHTMLName = PL_strdup("all");
}
extraParams = SSM_SetPasswordHTMLParams(slot);
rv = SSM_GenerateURL(target->m_connection,"get", "set_password", target,
extraParams, &width, &height, &url);
if (rv != SSM_SUCCESS) {
goto loser;
}
PR_Free(slotHTMLName);
PR_Free(extraParams);
return url;
loser:
PR_FREEIF(slotHTMLName);
PR_FREEIF(extraParams);
return NULL;
}
SSMStatus SSM_SetUserPassword(PK11SlotInfo * slot, SSMResource * ct)
{
SSMStatus rv;
char *params = SSM_SetPasswordHTMLParams(slot);
SSM_LockUIEvent(ct);
rv = SSMControlConnection_SendUIEvent(ct->m_connection,
"get", "set_password",
ct, params,
&ct->m_clientContext,
PR_TRUE);
if (rv != SSM_SUCCESS)
goto loser;
SSM_WaitUIEvent(ct, PR_INTERVAL_NO_TIMEOUT);
return rv;
loser:
SSM_UnlockUIEvent(ct);
return rv;
}
SSMStatus SSM_ProcessPasswordWindow(HTTPRequest * req)
{
SSMStatus rv = SSM_FAILURE;
SSMResource * target = NULL;
char *slotName = NULL, *slotHTMLName = NULL;
char *extraParams = NULL;
if (!req || !req->ctrlconn)
goto loser;
/*
* The window contents aren't going to change, so just send back
* a NO_CONTENT error which causes leave its content as is.
*/
rv = SSM_HTTPReportError(req, HTTP_NO_CONTENT);
target = REQ_TARGET(req);
/* First let's figure out if there are more than one token installed,
* if so ask the user which one to change the password on
*/
slotName = SSM_GetSlotNameForPasswordChange(req);
if (slotName == NULL) {
goto loser;
}
extraParams = SSM_SetPasswordHTMLParamsFromTokenName(slotName);
SSM_LockUIEvent(target);
/* send UI event to bring up the dialog */
rv = SSMControlConnection_SendUIEvent(req->ctrlconn, "get",
"set_password", target,
extraParams,
&target->m_clientContext,
PR_TRUE);
PR_FREEIF(extraParams);
if (rv != SSM_SUCCESS) {
SSM_UnlockUIEvent(&req->ctrlconn->super.super);
goto loser;
}
SSM_WaitUIEvent(target, PR_INTERVAL_NO_TIMEOUT);
loser:
return rv;
}