password.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:32k
源码类别:

CA认证

开发平台:

WINDOWS

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /*
  3.  * The contents of this file are subject to the Mozilla Public
  4.  * License Version 1.1 (the "License"); you may not use this file
  5.  * except in compliance with the License. You may obtain a copy of
  6.  * the License at http://www.mozilla.org/MPL/
  7.  * 
  8.  * Software distributed under the License is distributed on an "AS
  9.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  10.  * implied. See the License for the specific language governing
  11.  * rights and limitations under the License.
  12.  * 
  13.  * The Original Code is the Netscape security libraries.
  14.  * 
  15.  * The Initial Developer of the Original Code is Netscape
  16.  * Communications Corporation.  Portions created by Netscape are 
  17.  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
  18.  * Rights Reserved.
  19.  * 
  20.  * Contributor(s):
  21.  * 
  22.  * Alternatively, the contents of this file may be used under the
  23.  * terms of the GNU General Public License Version 2 or later (the
  24.  * "GPL"), in which case the provisions of the GPL are applicable 
  25.  * instead of those above.  If you wish to allow use of your 
  26.  * version of this file only under the terms of the GPL and not to
  27.  * allow others to use your version of this file under the MPL,
  28.  * indicate your decision by deleting the provisions above and
  29.  * replace them with the notice and other provisions required by
  30.  * the GPL.  If you do not delete the provisions above, a recipient
  31.  * may use your version of this file under either the MPL or the
  32.  * GPL.
  33.  */
  34. #include "connect.h"
  35. #include "ssmerrs.h"
  36. #include "ctrlconn.h"
  37. #include "prinrval.h"
  38. #include "crmf.h"
  39. #include "newproto.h"
  40. #include "messages.h"
  41. #include "minihttp.h"
  42. #include "textgen.h"
  43. #include "sechash.h"
  44. #include "pk11func.h"
  45. extern SSMHashTable * tokenList;
  46. extern PRMonitor * tokenLock;
  47. #define SSMRESOURCE(conn) (&(conn)->super)
  48. /* Make these into functions? */
  49. #if 0
  50. #define SSM_PARENT_CONN(x)  ((((SSMConnection *)(x))->m_parent) != NULL)? 
  51. (((SSMControlConnection *)(((SSMConnection *)(x))->m_parent))):
  52. ((SSMControlConnection *)x)
  53. #define SSM_PWD_TABLE(x) (SSM_PARENT_CONN(x))->m_passwdTable
  54.      
  55. #define SSM_OUT_QUEUE(x) (SSM_PARENT_CONN(x))->m_controlOutQ
  56. #endif
  57. #if 1     
  58. SSMControlConnection * SSM_PARENT_CONN (SSMConnection * x) 
  59.   return (((((SSMConnection *)(x))->m_parent) != NULL)?
  60.           (((SSMControlConnection *)(((SSMConnection *)(x))->m_parent))):
  61.           ((SSMControlConnection *)x));
  62. }
  63. SSMHashTable * SSM_PWD_TABLE(SSMConnection * x) 
  64. {
  65.   return (SSM_PARENT_CONN(x)->m_passwdTable);
  66. }
  67. SSMCollection * SSM_OUT_QUEUE(SSMConnection * x)
  68. {
  69.   return (SSM_PARENT_CONN(x)->m_controlOutQ);
  70. }
  71. #endif
  72. PRInt32 SSM_GetTokenKey(PK11SlotInfo * slot) 
  73. {
  74.   return ((PK11_GetSlotID(slot)<<16) | PK11_GetModuleID(slot));
  75. }
  76. char * SSM_GetPasswdCallback(PK11SlotInfo *slot,  PRBool retry,  void *arg)
  77. {
  78.   return SSM_GetAuthentication(slot, retry, PR_FALSE, (SSMResource*)arg);
  79. }
  80. /* Do a couple of things in this functions: 
  81.  * 1) Get a password from user, and authenticate to token.
  82.  * 2) Save this password encrypted in the global Cartman tokenList 
  83.  *    for future reference. 
  84.  *    Need to save password in case other users will need to authenticate
  85.  *    to the same tokens, so we make sure they're using the correct 
  86.  *    passwords.
  87.  * 3) Save this password encrypted in the control connection table in 
  88.  *    case we will need to use it again. 
  89.  */
  90. char * SSM_GetAuthentication(PK11SlotInfo * slot, PRBool retry, PRBool init, 
  91.                              SSMResource * res)
  92. {
  93.   PRInt32 tokenKey;
  94.   SSMStatus rv = PR_SUCCESS;
  95.   char * passwd = NULL, * tmp = NULL; 
  96.   PRBool first  = PR_FALSE;
  97.   SSM_TokenInfo * info = NULL, * infoLocal = NULL;
  98.   SSMConnection *conn = &(res->m_connection->super);
  99.   
  100.   tokenKey = SSM_GetTokenKey(slot);
  101.   /* register as interested in a password */
  102.  SSM_PARENT_CONN(conn)->m_waiting++;
  103.   
  104.   /* Get passwd table lock. */
  105.   SSM_LockPasswdTable(conn);
  106.   /* Look for entry for moduleID/slotID. */
  107.   rv = SSM_HashFind(SSM_PWD_TABLE(conn), tokenKey, (void **)&passwd);
  108.   SSM_UnlockPasswdTable(conn);
  109.   if (rv != PR_SUCCESS) {
  110.     first = PR_TRUE;
  111.     /* no entry found, we are the first to authenticate to this slot */
  112.     SSM_DEBUG("%ld: creating passwd table entry for %s n", 
  113.               conn, PK11_GetSlotName(slot));
  114.     SSM_LockPasswdTable(conn);
  115.     rv = SSM_HashInsert(SSM_PWD_TABLE(conn),tokenKey,(void *)SSM_NO_PASSWORD);
  116.     SSM_UnlockPasswdTable(conn);
  117.     if (rv != PR_SUCCESS) {
  118.       SSM_DEBUG("%ld: could not create entry in password tablen", conn);
  119.       goto loser;
  120.     }
  121.     rv = SSM_AskUserPassword(res, slot, retry, init);
  122.     if (rv != PR_SUCCESS) {
  123.       SSM_DEBUG("%ld: error sending password request eventn", conn);
  124.       goto loser;
  125.     }
  126.   } /* end of the we-are-first-to-request-this-passwd-clause */
  127.   
  128.   /* If no password found, wait for it */
  129.   if (!passwd || passwd == (char *)SSM_NO_PASSWORD) {
  130.     rv = SSMControlConnection_WaitPassword(conn, tokenKey, &passwd);
  131.     if (rv != PR_SUCCESS) 
  132.       goto loser;
  133.   }
  134.   if (((int) passwd) == SSM_CANCEL_PASSWORD) {
  135.     /* no password was provided or user hit "Cancel" */
  136.     SSM_LockPasswdTable(conn);
  137.     rv = SSM_HashRemove(SSM_PWD_TABLE(conn), tokenKey, (void **)&passwd);  
  138.     SSM_UnlockPasswdTable(conn);
  139.     if (rv != SSM_SUCCESS) 
  140.       SSM_DEBUG("SSM_GetAuthentication: user hit Cancel, can't remove password from connection tablen");
  141.     passwd = NULL;
  142.     goto done;
  143.   }
  144.   
  145.   if (first) {
  146.     /* We were the first to request the password, 
  147.      * so we need to enter it in to the token list.
  148.      */
  149.     /* encrypt the password */
  150.     if (SSM_EncryptPasswd(slot, passwd, &info) != SSM_SUCCESS) {
  151.       SSM_DEBUG("%ld: could not encrypt passwordn.", conn);
  152.       goto loser;
  153.     }
  154.     
  155.     /* Place encrypted passwd in Cartman-wide tokenList */
  156.     PR_EnterMonitor(tokenLock);
  157.     /* Remove from tokenList if already on the list - must be stale */
  158.     rv = SSM_HashRemove(tokenList, tokenKey, (void **)&tmp);
  159.     if (rv == SSM_SUCCESS && tmp && tmp != (char *)SSM_NO_PASSWORD 
  160.         && tmp != (char *)SSM_CANCEL_PASSWORD) { /* free stale data */
  161.       PR_Free(tmp);
  162.       tmp = NULL;
  163.     }
  164.     rv = SSM_HashInsert(tokenList, tokenKey, info);
  165.     PR_ExitMonitor(tokenLock);
  166.     if (rv != PR_SUCCESS) {
  167.       SSM_DEBUG("%ld: can't create encr passwd entryn", conn, tokenKey);
  168.       goto loser;
  169.     }
  170.     
  171.     /* Store encrypted password in control connection table */ 
  172.     infoLocal = (SSM_TokenInfo *) PORT_ZAlloc(sizeof(SSM_TokenInfo));
  173.     if (!infoLocal) 
  174.       goto loser;
  175.     infoLocal->slot = info->slot;
  176.     infoLocal->tokenID = info->tokenID;
  177.     infoLocal->encryptedLen = info->encryptedLen;
  178.     infoLocal->symKey = info->symKey;
  179.     infoLocal->encrypted = (char *) PORT_ZAlloc(info->encryptedLen);
  180.     if (!infoLocal->encrypted)
  181.       goto loser;
  182.     memcpy(infoLocal->encrypted, info->encrypted, info->encryptedLen);
  183.     PR_EnterMonitor(SSM_PARENT_CONN(conn)->m_encrPasswdLock);
  184.     rv = SSM_HashRemove(SSM_PARENT_CONN(conn)->m_encrPasswdTable, tokenKey, 
  185.                    (void **)&tmp);
  186.     if (rv == SSM_SUCCESS && tmp && tmp != (char *)SSM_NO_PASSWORD && 
  187.         tmp != (char *)SSM_CANCEL_PASSWORD )  {/* free stale data */
  188.       PR_Free(tmp); 
  189.       tmp = NULL;
  190.     }
  191.     rv = SSM_HashInsert(SSM_PARENT_CONN(conn)->m_encrPasswdTable, tokenKey,
  192.                         infoLocal);
  193.     PR_ExitMonitor(SSM_PARENT_CONN(conn)->m_encrPasswdLock);
  194.     if (rv != PR_SUCCESS) {
  195.       SSM_DEBUG("%ld: cannot insert token %d entry in encrPasswdTablen",
  196.                 conn, tokenKey);
  197.       goto loser;
  198.     }
  199.     
  200.     SSM_DEBUG("%ld: wait untill others are done with passwd, remove itn",
  201.               conn);
  202.     /* while ((SSM_PARENT_CONN(conn))->m_waiting > 1)
  203.      *  PR_Sleep(SSM_PASSWORD_WAIT_TIME);
  204.      */
  205.     SSM_LockPasswdTable(conn);
  206.     rv = SSM_HashRemove(SSM_PWD_TABLE(conn), tokenKey, (void **)&passwd);
  207.     if (rv != PR_SUCCESS) { 
  208.       SSM_DEBUG("%ld: could not remove passwd.n", conn);
  209.       goto loser;
  210.     }
  211.       SSM_UnlockPasswdTable(conn);
  212.     } /* end of if-first clause */
  213.     
  214.     goto done;
  215.     
  216.  loser:
  217.     /* cleanup */
  218.     PR_FREEIF(passwd);
  219.     passwd = NULL;
  220.     if (info) {
  221.       PR_FREEIF(info->encrypted);
  222.       PR_Free(info);
  223.     }
  224.     if (infoLocal) {
  225.       PR_FREEIF(infoLocal->encrypted);
  226.       PR_Free(infoLocal);
  227.     }
  228.  done:
  229.     /* We are done receiving passwd */
  230.     (SSM_PARENT_CONN(conn))->m_waiting--;
  231.     return passwd ? strdup (passwd) : NULL;
  232. }
  233. /* 
  234.  * We get this callback if the slot is already logged-in. 
  235.  * Need to check client-supplied password against the password stored in 
  236.  *      tokenList.
  237.  */
  238. PRBool SSM_VerifyPasswdCallback(PK11SlotInfo * slot, void * arg)
  239. {
  240.   char * passwd = NULL;
  241.   PRInt32 tokenKey;
  242.   SSM_TokenInfo * info = NULL;
  243.   SSM_TokenInfo * tokenInfo = NULL;
  244.   SSMStatus rv;
  245.   PRBool result = PR_FALSE;
  246.   SSMResource * res = (SSMResource*)arg;
  247.   SSMConnection * conn = &(res->m_connection->super);
  248.   PRInt32 doTry = 0;
  249.   void * tmp = NULL;
  250.   
  251.   if (!slot || !arg) 
  252.     goto loser;
  253.   
  254.   tokenKey = PK11_GetSlotID(slot) ^ PK11_GetModuleID(slot);
  255.   info = (SSM_TokenInfo *) PORT_ZAlloc(sizeof(SSM_TokenInfo));
  256.   if (!info) {
  257.     SSM_DEBUG("Could not allocate memory in VerifyPasswdCallback.n");
  258.     goto loser;
  259.   }
  260.   
  261.   /* Get the password for this token. 
  262.    * We might have to find it in the local encrypted password table or 
  263.    * to request it from the client. 
  264.    */
  265.   rv = SSM_HashFind(SSM_PARENT_CONN(conn)->m_encrPasswdTable, tokenKey, 
  266.                     (void **)&info);
  267.   if (rv != PR_SUCCESS || info == (void *)SSM_NO_PASSWORD) { 
  268.   askpassword:
  269.     /* ask user for a password and store it in local passwd table */
  270.     rv = SSM_AskUserPassword(res, slot, doTry?PR_TRUE:PR_FALSE, PR_FALSE);
  271.     if (rv != PR_SUCCESS)
  272.       goto loser;
  273.     doTry++;
  274.     rv = SSMControlConnection_WaitPassword(conn, tokenKey, &passwd);
  275.     if (rv != PR_SUCCESS || !passwd)
  276.       goto loser;
  277.     rv = SSM_EncryptPasswd(slot, passwd, &info);
  278.     if (rv != SSM_SUCCESS) 
  279.       goto loser;
  280.   } /* end of no password, ask user */
  281.   
  282.   /* Now get the stored password for this token */
  283.   if (!tokenInfo) {
  284.     PR_EnterMonitor(tokenLock);
  285.     rv = SSM_HashFind(tokenList, tokenKey, (void **)&tokenInfo);
  286.     PR_ExitMonitor(tokenLock);
  287.     if (rv != PR_SUCCESS || !tokenInfo) {
  288.       SSM_DEBUG("Can't find token info in VerifyPasswd.n");
  289.       goto loser;
  290.     }
  291.   }
  292.   /* Check password against tokenList entry   */
  293.   if (memcmp(tokenInfo->encrypted, info->encrypted, tokenInfo->encryptedLen)
  294.       != 0 || tokenInfo->encryptedLen != info->encryptedLen) {
  295.     /* Failed compare, bad password */
  296.     /* first clean up */
  297.     if (info) PR_Free(info);
  298.     info = NULL;
  299.     /* If not retry, ask client for password. */
  300.     if (doTry < 2 ) {
  301.       /* ask user again */
  302.       PR_Free(passwd);
  303.       passwd = NULL;
  304.       goto askpassword; 
  305.     }
  306.     else 
  307.       goto loser;
  308.   } /* end of password not verified */
  309.   
  310.   SSM_DEBUG("Password verified OK.n");
  311.   /* store password for local use */
  312.   PR_EnterMonitor(SSM_PARENT_CONN(conn)->m_encrPasswdLock);
  313.   SSM_HashRemove(SSM_PARENT_CONN(conn)->m_encrPasswdTable, tokenKey, 
  314.                  (void **)&tmp);
  315.   if (tmp && tmp != (char *)SSM_NO_PASSWORD )  {/* free stale data */
  316.     PR_Free(tmp); 
  317.     tmp = NULL;
  318.   }
  319.   rv = SSM_HashInsert(SSM_PARENT_CONN(conn)->m_encrPasswdTable, tokenKey,
  320.                       info);
  321.   PR_ExitMonitor(SSM_PARENT_CONN(conn)->m_encrPasswdLock);
  322.   if (rv != PR_SUCCESS) {
  323.     SSM_DEBUG("%ld: cannot insert token %d entry in encrPasswdTablen",
  324.               conn, tokenKey);
  325.     goto loser;
  326.   }
  327.   
  328.   result = PR_TRUE;
  329.   goto done;
  330.  loser:
  331.   SSM_DEBUG("Password not verified. n");
  332.   /* log out this slot?? */
  333.   if (info) {
  334.     if (info->encrypted)
  335.       PR_Free(info->encrypted);
  336.     PR_Free(info);
  337.   }
  338.   result = PR_FALSE;
  339.  done:
  340.   if (passwd)
  341.     PR_Free(passwd);
  342.   return result;
  343. }
  344. /* Encrypt password for storage */
  345. #define SSM_PAD_BLOCK_SIZE(x, y) ((((x) + ((y)-1))/(y))*(y)) 
  346. SSMStatus SSM_EncryptPasswd(PK11SlotInfo * slot, char * passwd, 
  347.                             SSM_TokenInfo ** tokenInfo)
  348. {
  349.   int resultLen;
  350.   char *hashResult = NULL;
  351.   SSMStatus rv = SSM_SUCCESS;
  352.   SECStatus srv;
  353.   SSM_TokenInfo * info;
  354.   /* Hash the password. */
  355.   resultLen = HASH_ResultLen(HASH_AlgSHA1);
  356.   hashResult = (char *) PORT_ZAlloc(resultLen); /* because the original PORT_ZAlloc'd */
  357.   if (!hashResult)
  358.     goto loser;
  359.   
  360.   srv = HASH_HashBuf(HASH_AlgSHA1, (unsigned char *) hashResult, (unsigned char *) passwd, strlen(passwd));
  361.   if (srv != SECSuccess)
  362.     goto loser;
  363.   
  364.   /* fill in the tokenInfo structure */
  365.   info = (SSM_TokenInfo *) PORT_ZAlloc(sizeof(SSM_TokenInfo));
  366.   if (!info) {
  367.     SSM_DEBUG("EncryptPwd: could not allocate memory to token list entry.n");
  368.     PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  369.     goto loser;
  370.   }
  371.   info->encrypted = hashResult;
  372.   info->encryptedLen = resultLen;
  373.   info->slot = slot;
  374.   info->tokenID = SSM_GetTokenKey(slot);
  375.   *tokenInfo = info;
  376.   goto done;
  377.  loser:
  378.   if (rv == SSM_SUCCESS) rv = SSM_FAILURE;
  379.   PR_FREEIF(hashResult);
  380.  done:
  381.   return rv;
  382. }
  383. SSMStatus SSM_NotEncryptPasswd(PK11SlotInfo * slot, char * passwd, 
  384.                                SSM_TokenInfo * info)
  385. {
  386.   CK_MECHANISM_TYPE mechanism;
  387.   /* CK_SESSION_HANDLE session = CK_INVALID_SESSION; */
  388.   PRInt32 keyLength, blockSize, outlen;
  389.   PRUint32 encryptedLength;
  390.   PK11SymKey * symKey;
  391.   SECStatus rv;
  392.   char * encrypted = NULL;
  393.   PK11Context * context=NULL;
  394.   SECItem *params; 
  395.   
  396.   
  397.   if (!slot || !passwd || !info) {
  398.     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  399.     goto loser;
  400.   }
  401.   mechanism = CRMF_GetBestWrapPadMechanism(slot);
  402.   keyLength = PK11_GetBestKeyLength(slot, mechanism);
  403.   /* session = PK11_GetRWSession(slot);
  404.      if (session == CK_INVALID_SESSION)
  405.      goto loser;*/
  406.   blockSize = PK11_GetBlockSize(mechanism, NULL);
  407.   
  408.   /* 
  409.    * A password is encrypted when we first authenticate to token. 
  410.    * In this case, generate a symmetric Key on the slot. 
  411.    * If the key is already present, it means that the password for this 
  412.    *       slot has already been encrypted and stored, need to encrypt 
  413.    *       new password with the same key to compare against the stored
  414.    *       password. 
  415.    */ 
  416.   /* If no symKey found, generate one */
  417.   if (!info->symKey) {
  418.     symKey = PK11_KeyGen(slot, mechanism, NULL, keyLength, NULL);
  419.     if (!symKey) { 
  420.       SSM_DEBUG("Failed to generate symKey to encrypt passwd.n");
  421.       goto loser;
  422.     }
  423.   } else 
  424.     symKey = info->symKey;
  425.   
  426.   encryptedLength = SSM_PAD_BLOCK_SIZE(strlen(passwd)+1, blockSize);
  427.   encrypted = (char *) PORT_ZAlloc(encryptedLength);
  428.   if (!encrypted) {
  429.     SSM_DEBUG("Could not allocate space for encrypted password. n");
  430.     goto loser;
  431.   }
  432.   params = CRMF_GetIVFromMechanism(mechanism);
  433.   context=PK11_CreateContextBySymKey(mechanism, CKA_ENCRYPT, 
  434.                                      symKey, params);
  435.   if (params != NULL) {
  436.     SECITEM_FreeItem(params, PR_TRUE);
  437.   } 
  438.   if (!context) {
  439.     SSM_DEBUG("Can't create context to encrypt password: %d.n", 
  440.               PR_GetError());
  441.     goto loser;
  442.   }
  443.   rv = PK11_CipherOp(context, (unsigned char *) encrypted, &outlen, 
  444.                      (int) encryptedLength, 
  445.                      (unsigned char *) passwd, strlen(passwd));
  446.   if (rv != PR_SUCCESS) {
  447.     SSM_DEBUG("Error encrypting password: %dn", PR_GetError());
  448.     goto loser;
  449.   }
  450.   rv = PK11_DigestFinal(context, (unsigned char *) &encrypted[outlen], 
  451.                         (unsigned int *) &outlen, (unsigned int) blockSize);
  452.   if (rv != PR_SUCCESS) {
  453.     SSM_DEBUG("Error encrypting password: %dn", PR_GetError());
  454.     goto loser;
  455.   }
  456.   PK11_DestroyContext(context, PR_TRUE);
  457.   /*if (session != CK_INVALID_SESSION)
  458.     PK11_RestoreROSession(slot, session);*/
  459.   
  460.   /* fill in the tokenInfo structure */
  461.   info->encrypted = encrypted;
  462.   info->encryptedLen = encryptedLength;
  463.   info->slot = slot;
  464.   return SSM_SUCCESS;
  465.  loser:
  466.   SSM_DEBUG("Failed to encrypt password.n");
  467.   if (context != NULL)
  468.     PK11_DestroyContext(context, PR_TRUE);
  469.   /*if (session != CK_INVALID_SESSION)
  470.     PK11_RestoreROSession(slot, session);*/
  471.   if (encrypted && *encrypted) 
  472.     PR_Free(encrypted);
  473.   return SSM_FAILURE;
  474. }
  475. /* Needs to be fixed using NLS lib and proper string storage. -jane */
  476. char * SSM_GetPrompt(PK11SlotInfo *slot, PRBool retry, PRBool init)
  477. {
  478.   char * prompt = NULL, * tmp = NULL, * key;
  479.   SSMTextGenContext * cx;
  480.   SSMStatus rv;
  481.   PR_ASSERT(init != PR_TRUE);
  482.  
  483.   rv = SSMTextGen_NewTopLevelContext(NULL, &cx);
  484.   if (rv != SSM_SUCCESS || !cx) 
  485.     goto loser;
  486.   if (retry) 
  487.     key = "retry_token_password";
  488.   else 
  489.     key = "ask_token_password";
  490.   
  491.   rv = SSM_GetAndExpandTextKeyedByString(cx, key, &tmp);
  492.   if (rv != SSM_SUCCESS || !tmp)
  493.     goto loser;
  494.   prompt = PR_smprintf(tmp, PK11_GetTokenName(slot));
  495.   
  496.  loser:
  497.   PR_FREEIF(tmp);
  498.   return prompt;
  499. }
  500. /* Send a password request for the client */
  501. SSMStatus SSM_AskUserPassword(SSMResource * res, 
  502.                              PK11SlotInfo * slot, PRInt32 retry, PRBool init)
  503. {
  504.   SECItem message;
  505.   char * prompt = NULL;
  506.   PRInt32 tokenKey = SSM_GetTokenKey(slot);
  507.   SSMStatus rv = PR_FAILURE;
  508.   SSMConnection *conn = (SSMConnection *)res->m_connection;
  509.   PasswordRequest request;
  510.   
  511.   prompt = SSM_GetPrompt(slot, retry, init);
  512.   retry++;
  513.   if (!prompt) {
  514.     SSM_DEBUG("%ld: error getting prompt for password request.n", conn);
  515.     goto loser;
  516.   }
  517.   request.tokenKey = tokenKey;
  518.   request.prompt = prompt;
  519.   request.clientContext = res->m_clientContext;
  520.   if (CMT_EncodeMessage(PasswordRequestTemplate, (CMTItem*)&message, &request) != CMTSuccess) {
  521.       goto loser;
  522.   }
  523.   if (message.len == 0 || !message.data) {
  524.     SSM_DEBUG("%ld: could not create password request message.n", conn);
  525.     goto loser;
  526.   }
  527.   message.type = (SECItemType) (SSM_EVENT_MESSAGE | SSM_AUTH_EVENT);
  528.   rv = SSM_SendQMessage(SSM_OUT_QUEUE(conn), SSM_PRIORITY_UI, message.type, 
  529.                         message.len, (char *)message.data, PR_TRUE);
  530.   if (rv != PR_SUCCESS) { 
  531.     SSM_DEBUG("%ld: Can't enqueue password request. n", conn);
  532.     goto loser;
  533.   }
  534.  loser:
  535.   if (prompt)
  536.     PR_Free(prompt);
  537.   if (message.data)
  538.     PR_Free(message.data);
  539.   return rv;
  540. }
  541. SSMStatus SSMControlConnection_WaitPassword(SSMConnection * conn, 
  542.                                            PRInt32 key, char ** str)
  543. {
  544.   char * passwd;
  545.   PRIntervalTime before;
  546.   SSMStatus rv = PR_FAILURE;
  547.   
  548.   *str = NULL;
  549.   /* Wait no longer than our time-out period. */
  550.   before = PR_IntervalNow();
  551.   SSM_LockPasswdTable(conn);    
  552.  wait:
  553.   SSM_DEBUG("%ld : waiting on password table for the passwordn", conn); 
  554.   SSM_WaitPasswdTable(conn);
  555.   /* Returned from wait.
  556.    * Look for password.
  557.    */
  558.   rv = SSM_HashFind(SSM_PWD_TABLE(conn), key, (void **)&passwd);
  559.   if (rv!=PR_SUCCESS || !passwd || passwd ==(char *)SSM_NO_PASSWORD) {
  560.     /* password not found, check for timeout */
  561.     if (PR_IntervalNow() - before > SSM_PASSWORD_WAIT_TIME) {
  562.       SSM_DEBUG("%ld:Timed out waiting for password.Bailing out.n", 
  563.                 conn);
  564.       SSM_UnlockPasswdTable(conn);
  565.       return PR_FAILURE;
  566.     } 
  567.     else 
  568.       goto wait; /* continue waiting */
  569.   } /* end of no password found */
  570.   SSM_UnlockPasswdTable(conn);
  571.   *str = passwd;
  572.   return rv;
  573. }
  574. extern PK11SlotListElement * 
  575. PK11_GetNextSafe(PK11SlotList * list, PK11SlotListElement * element,PRBool start);
  576.                                        
  577. PK11SlotListElement *
  578. ssm_GetSlotWithPwd(PK11SlotList * slotlist, PK11SlotListElement * current,
  579.                         PRBool start)
  580. {
  581.   PK11SlotListElement * next = NULL;
  582.   PR_ASSERT(slotlist);
  583.   if (!current || start)
  584.     next = PK11_GetFirstSafe(slotlist);
  585.   else
  586.     next = PK11_GetNextSafe(slotlist, current, PR_FALSE);
  587.   while (next                          && 
  588.          PK11_NeedUserInit(next->slot) && 
  589.          !PK11_NeedLogin(next->slot)     )
  590.     next = PK11_GetNextSafe(slotlist, next, PR_FALSE);
  591.   return next;
  592. }
  593. PRIntn
  594. ssm_NumSlotsWithPassword(PK11SlotList * slotList)
  595. {
  596.   PRIntn numslots = 0;
  597.   PK11SlotListElement * element = PK11_GetFirstSafe(slotList);
  598.   while (element) {
  599.     if (PK11_NeedLogin(element->slot) || !PK11_NeedUserInit(element->slot))
  600.       numslots++;
  601.     element = PK11_GetNextSafe(slotList, element,PR_FALSE);
  602.   }
  603.   return numslots;
  604. }
  605. char*
  606. SSM_GetSlotNameForPasswordChange(HTTPRequest * req)
  607. {
  608.     PK11SlotList *slotList = NULL;
  609.     PK11SlotInfo *slot=NULL;
  610.     PK11SlotListElement *listElem = NULL;
  611.     SSMResource *target;
  612.     char *slotName=NULL;
  613.     SSMStatus rv;
  614.     
  615.     slotName = NULL;
  616.     target = REQ_TARGET(req);
  617.     slotList = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_TRUE, 
  618.                                  PR_TRUE, target);
  619.     if (!slotList || !slotList->head)
  620.       goto loser;
  621.     if (ssm_NumSlotsWithPassword(slotList)>1) {
  622.       char * mech = PR_smprintf("mech=%d&unused1=unused1&unused2=unused2",
  623.                                 CKM_INVALID_MECHANISM);
  624.       SSM_LockUIEvent(target);
  625.       rv = SSMControlConnection_SendUIEvent(req->ctrlconn,
  626.                                             "get", "select_token",
  627.                                             target,mech,
  628.                                             &target->m_clientContext, 
  629.                                               PR_TRUE);
  630.       SSM_WaitUIEvent(target, PR_INTERVAL_NO_TIMEOUT);
  631.       slot = (PK11SlotInfo *) target->m_uiData;
  632.       if (!slot) 
  633.         goto loser;
  634.     } else {
  635.       listElem = ssm_GetSlotWithPwd(slotList, NULL, PR_TRUE);
  636.       slot = listElem->slot;
  637.     }
  638.     if (!slot) {
  639.       goto loser;
  640.     }
  641.     slotName = PK11_GetTokenName(slot);
  642.     PK11_FreeSlot(slot);
  643.     PK11_FreeSlotList(slotList);
  644.     return PL_strdup(slotName);
  645.  loser:
  646.     if (slot)
  647.       PK11_FreeSlot(slot);
  648.     if (slotList)
  649.       PK11_FreeSlotList(slotList);
  650.     return NULL;
  651. }
  652. SSMStatus SSM_ReSetPasswordKeywordHandler(SSMTextGenContext * cx)
  653. {  
  654.   char * slotname = NULL;
  655.   PK11SlotInfo * slot; 
  656.   char * tmp = NULL;
  657.   SSMStatus rv;
  658.   SSMResource * target = cx->m_request->target;
  659.   PK11SlotList * slotList = NULL;
  660.   PK11SlotListElement * el = NULL;
  661.   PR_ASSERT(cx != NULL);
  662.   PR_ASSERT(cx->m_request != NULL);
  663.   PR_ASSERT(&cx->m_result != NULL);
  664.   rv = SSM_HTTPParamValue(cx->m_request, "action", &slotname);
  665.   
  666.   if (!slotname || strcmp(slotname, "")== 0) 
  667.     slot = PK11_GetInternalKeySlot();
  668.   else if (strcmp(slotname, "all") == 0) {
  669.       char *userSlotName = NULL;
  670.       /* ask user */
  671.       userSlotName = SSM_GetSlotNameForPasswordChange(cx->m_request);
  672.       if (!userSlotName) 
  673.         goto cancel;
  674.       slot = PK11_FindSlotByName(userSlotName);
  675.       PR_Free(userSlotName);
  676.   } 
  677.   else 
  678.     slot = PK11_FindSlotByName(slotname);
  679.   if (!slot) {
  680.     SSM_DEBUG("ReSetPasswordKeywordHandler: bad slotname %sn", slotname);
  681.     goto loser;
  682.   }
  683.   
  684.   slotname = PK11_GetTokenName(slot);
  685.   if (PK11_NeedPWInitForSlot(slot))
  686.     rv = SSM_GetAndExpandTextKeyedByString(cx, "set_new_password", &tmp);
  687.   else 
  688.     rv = SSM_GetAndExpandTextKeyedByString(cx, "reset_password", &tmp);
  689.   if (rv != SSM_SUCCESS) 
  690.     goto loser;
  691.   PR_FREEIF(cx->m_result);
  692.   cx->m_result = PR_smprintf(tmp, slotname);
  693.   return rv;
  694.   
  695.  loser:
  696.   if (cx->m_result) 
  697.     PR_Free(cx->m_result);
  698.   cx->m_result = NULL;
  699.   return PR_FAILURE;
  700.  cancel:
  701.   SSM_HTTPCloseWindow(cx->m_request);
  702.   goto loser;
  703. }
  704. PRBool 
  705. ssm_VerifyPwdLength(char * password)
  706. {
  707.   if (!password)
  708.     return (!SSM_MIN_PWD_LEN);
  709.   if (strlen(password) < SSM_MIN_PWD_LEN)
  710.     return PR_FALSE;
  711.   if (strlen(password) > SSM_MAX_PWD_LEN)
  712.     return PR_FALSE;
  713.   return PR_TRUE;
  714. }
  715. SSMStatus SSM_PasswordPrefKeywordHandler(SSMTextGenContext * cx)
  716. {
  717.   char * fmt = NULL, * checked = NULL;
  718.   char * markchecked[] = { "", "", ""};
  719.   SSMStatus rv;
  720.   PRIntn askpw, timeout;
  721.   PR_ASSERT(cx != NULL);
  722.   PR_ASSERT(cx->m_request != NULL);
  723.   PR_ASSERT(cx->m_result != NULL);
  724.   
  725.   /* need to get the table and fill it with current preferences */
  726.   rv = SSM_GetAndExpandTextKeyedByString(cx, "password_lifetime", &fmt);
  727.   if (rv != SSM_SUCCESS || !fmt) 
  728.     goto done;
  729.   rv = SSM_GetAndExpandTextKeyedByString(cx, "text_checked", &checked);
  730.   if (rv != SSM_SUCCESS || !checked) 
  731.     goto done;
  732.   rv = PREF_GetIntPref(cx->m_request->ctrlconn->m_prefs, 
  733.                        "security.ask_for_password", &askpw);
  734.   if (rv != SSM_SUCCESS)
  735.     goto done;
  736.   rv = PREF_GetIntPref(cx->m_request->ctrlconn->m_prefs, 
  737.                        "security.password_lifetime", &timeout);
  738.   if (rv != SSM_SUCCESS)
  739.     goto done;
  740.   markchecked[askpw] = checked;
  741.   PR_FREEIF(cx->m_result);
  742.   cx->m_result = PR_smprintf(fmt, markchecked[0], markchecked[1], 
  743.                              markchecked[2], timeout);
  744.   
  745. done: 
  746.   return rv;
  747. }
  748. SSMStatus SSM_SetDBPasswordHandler(HTTPRequest * req)
  749. {
  750.   SSMStatus rv = SSM_FAILURE;
  751.   char * oldpassword, * newpassword, *repeatpassword, * action;
  752.   PK11SlotInfo * slot;
  753.   char * responseKey = NULL;
  754.   char * result = NULL;
  755.   char * slotname = NULL, * askpwdoption, * pwdlifetime;
  756.   PRIntn askpw, timeout;
  757.   rv = SSM_HTTPParamValue(req, "baseRef", &action);
  758.   if (rv != SSM_SUCCESS || strcmp(action, "windowclose_doclose_js")!= 0)
  759.     SSM_DEBUG("SetDBPasswordHandler: bad action %sn", action);
  760.   
  761.   rv = SSM_HTTPParamValue(req, "slot", &slotname);
  762.   if (rv != SSM_SUCCESS || !slotname || 
  763.       !(slot = PK11_FindSlotByName(slotname)))
  764.     goto loser;
  765.   /* process password preferences */
  766.   rv = SSM_HTTPParamValue(req, "passwordlife", &askpwdoption);
  767.   if (rv != SSM_SUCCESS || !askpwdoption) 
  768.     goto loser;
  769.   rv = SSM_HTTPParamValue(req, "passwordwillexpire", &pwdlifetime);
  770.   if (rv != SSM_SUCCESS || !pwdlifetime) 
  771.     goto loser;
  772.   if (strcmp(askpwdoption, "firsttime") == 0)
  773.     askpw = 0;
  774.   else if (strcmp(askpwdoption, "everytime") == 0)
  775.     askpw = 1;
  776.   else if (strcmp(askpwdoption, "expiretime")==0) {
  777.     askpw = 2;
  778.   }
  779.   else {
  780.     SSM_DEBUG("SetDBPasswordHandler: bad password lifetime parameter %sn", 
  781.               askpwdoption);
  782.     goto loser;
  783.   }
  784.   timeout = atoi(pwdlifetime);
  785.   if (askpw == 2 && !timeout) 
  786.     goto loser;
  787.   PK11_SetSlotPWValues(slot, askpw, timeout);
  788.   rv = SSMControlConnection_SaveIntPref(req->ctrlconn, 
  789.                                         "security.ask_for_password", askpw);
  790.   if (rv != PR_SUCCESS)
  791.     goto loser;
  792.   rv = SSMControlConnection_SaveIntPref(req->ctrlconn,
  793.                                         "security.password_lifetime", timeout);
  794.   if (rv != SSM_SUCCESS)
  795.     goto loser;
  796.   rv = SSM_HTTPParamValue(req, "newpassword", &newpassword);
  797.   if (rv != SSM_SUCCESS) 
  798.     goto loser;
  799.   rv = SSM_HTTPParamValue(req, "repeatpassword", &repeatpassword);
  800.   if (rv != SSM_SUCCESS) 
  801.     goto loser;
  802.   if (!PK11_NeedPWInitForSlot(slot)) {
  803.       /* oldpassword doesn't make sense for password initialization dialog */
  804.       rv = SSM_HTTPParamValue(req, "oldpassword", &oldpassword);
  805.       if (rv != SSM_SUCCESS) {
  806.           goto loser;
  807.       }
  808.       /* we do this check to find the case where the user changed only password
  809.        * settings, not the password itself
  810.        */
  811.       if ((oldpassword[0] == '') && (newpassword[0] == '') &&
  812.           (repeatpassword[0] == '')) {
  813.           rv = SSM_HTTPDefaultCommandHandler(req);
  814.           goto done;
  815.       }
  816.   }
  817.   if (!ssm_VerifyPwdLength(newpassword))
  818.     goto loser;
  819.   if (strcmp(newpassword, repeatpassword) != 0)
  820.     goto loser;
  821.   if (!PK11_NeedPWInitForSlot(slot)) { /* there is some password on the DB */
  822.     if (!oldpassword) 
  823.       goto loser;
  824.     if (PK11_CheckUserPassword(slot, oldpassword) != 
  825.         SECSuccess)
  826.       goto loser;
  827.     if (PK11_ChangePW(slot, oldpassword, newpassword) != 
  828.       SECSuccess)
  829.       goto loser;
  830.   }
  831.   else 
  832.     {
  833.       if (PK11_NeedUserInit(slot)) {
  834.         if (PK11_InitPin(slot, NULL, newpassword) != SECSuccess)
  835.           goto loser;
  836.         }
  837.       else {
  838.         if (PK11_ChangePW(slot, NULL, newpassword) != SECSuccess) 
  839.           goto loser;
  840.       }
  841.     }
  842.   result = PR_smprintf("result=password_success");
  843.  loser:
  844.   if (!result)
  845.     result = PR_smprintf("result=password_failure");
  846.   
  847.   rv = SSM_HTTPCloseAndSleep(req);
  848.   if (rv != SSM_SUCCESS) 
  849.     SSM_DEBUG("SetDBPasswordHandler: failure in DefaultCommandHandlern");
  850.   /* post status if password dialog was invoked from the SecurityAdvisor */
  851.   if (SSM_IsA(req->target, SSM_RESTYPE_SECADVISOR_CONTEXT))
  852.     SSMControlConnection_SendUIEvent(req->ctrlconn, "get", 
  853.                                      "show_followup", NULL, 
  854.                                      result, 
  855.                                      &((SSMResource *)req->ctrlconn)->m_clientContext,
  856.                                      PR_TRUE);
  857.   
  858.   PR_FREEIF(responseKey);
  859. done:
  860.   if (req->target && req->target->m_UILock)
  861.     SSM_NotifyUIEvent(req->target);
  862.   return rv;
  863. }
  864. SSMStatus SSM_ShowFollowupKeywordHandler(SSMTextGenContext * cx)
  865. {
  866.   char * resultvalue;
  867.   SSMStatus rv;
  868.   PR_ASSERT(cx != NULL);
  869.   PR_ASSERT(cx->m_request != NULL);
  870.   PR_ASSERT(cx->m_result != NULL);
  871.   
  872.   rv = SSM_HTTPParamValue(cx->m_request, "result", &resultvalue);
  873.   if (rv != SSM_SUCCESS || !resultvalue)
  874.     goto loser;
  875.   if (!strcmp(resultvalue, "password_success"))
  876.     rv = SSM_GetAndExpandTextKeyedByString(cx, "set_password_success",
  877.                                            &cx->m_result);
  878.   else if (!strcmp(resultvalue,"password_failure"))
  879.     rv = SSM_GetAndExpandTextKeyedByString(cx, "set_password_failure",
  880.                                            &cx->m_result);
  881.   else if (!strcmp(resultvalue, "no_ldap_setup"))
  882.     rv = SSM_GetAndExpandTextKeyedByString(cx, "no_ldap_server_set",
  883.                                            &cx->m_result);
  884.  loser:
  885.   return rv;
  886. }
  887. char *
  888. SSM_SetPasswordHTMLParamsFromTokenName(char *tokenName)
  889. {
  890.     char *url = NULL;
  891.     tokenName = SSM_ConvertStringToHTMLString(tokenName);
  892.     url = PR_smprintf("slot=%s&mechanism=%d", tokenName, 
  893.                       CKM_INVALID_MECHANISM);
  894.     PR_Free(tokenName);
  895.     return url;
  896. }
  897. char *
  898. SSM_SetPasswordHTMLParams(PK11SlotInfo *slot) {
  899.   return SSM_SetPasswordHTMLParamsFromTokenName(PK11_GetTokenName(slot));
  900. }
  901. char * SSM_GenerateChangePasswordURL(PK11SlotInfo *slot, SSMResource *target)
  902. {
  903.     PRUint32 width, height;
  904.     char *slotHTMLName = NULL, *url = NULL, *extraParams = NULL;
  905.     SSMStatus rv;
  906.     if (slot) {
  907.         slotHTMLName = 
  908.           SSM_ConvertStringToHTMLString(PK11_GetTokenName(slot));
  909.     } else {
  910.         slotHTMLName = PL_strdup("all");
  911.     }
  912.     extraParams = SSM_SetPasswordHTMLParams(slot);
  913.     rv = SSM_GenerateURL(target->m_connection,"get", "set_password", target, 
  914.                          extraParams, &width, &height, &url);
  915.     if (rv != SSM_SUCCESS) {
  916.         goto loser;
  917.     }
  918.     PR_Free(slotHTMLName);
  919.     PR_Free(extraParams);
  920.     return url;
  921.  loser:
  922.     PR_FREEIF(slotHTMLName);
  923.     PR_FREEIF(extraParams);
  924.    
  925.     return NULL;
  926. }
  927. SSMStatus SSM_SetUserPassword(PK11SlotInfo * slot, SSMResource * ct)
  928. {
  929.   SSMStatus rv;
  930.   char *params = SSM_SetPasswordHTMLParams(slot);
  931.   SSM_LockUIEvent(ct);
  932.   rv = SSMControlConnection_SendUIEvent(ct->m_connection,
  933.                                         "get", "set_password",
  934.                                         ct, params,
  935.                                         &ct->m_clientContext,
  936.                                         PR_TRUE);
  937.   if (rv != SSM_SUCCESS) 
  938.     goto loser;
  939.   SSM_WaitUIEvent(ct, PR_INTERVAL_NO_TIMEOUT);
  940.   return rv;
  941. loser:
  942.   SSM_UnlockUIEvent(ct);
  943.   return rv;
  944. }
  945. SSMStatus SSM_ProcessPasswordWindow(HTTPRequest * req)
  946. {
  947.   SSMStatus rv = SSM_FAILURE;
  948.   SSMResource * target = NULL;
  949.   char *slotName = NULL, *slotHTMLName = NULL;
  950.   char *extraParams = NULL;
  951.   
  952.   if (!req || !req->ctrlconn) 
  953.     goto loser;
  954.   /*
  955.    * The window contents aren't going to change, so just send back
  956.    * a NO_CONTENT error which causes leave its content as is.
  957.    */
  958.   rv = SSM_HTTPReportError(req, HTTP_NO_CONTENT);
  959.   target = REQ_TARGET(req);
  960.   /* First let's figure out if there are more than one token installed,
  961.    * if so ask the user which one to change the password on
  962.    */
  963.   slotName = SSM_GetSlotNameForPasswordChange(req);
  964.   if (slotName == NULL) {
  965.     goto loser;
  966.   }
  967.   extraParams = SSM_SetPasswordHTMLParamsFromTokenName(slotName);
  968.   SSM_LockUIEvent(target);
  969.   /* send UI event to bring up the dialog */
  970.   rv = SSMControlConnection_SendUIEvent(req->ctrlconn, "get", 
  971.                                         "set_password", target, 
  972.                                         extraParams, 
  973.                                         &target->m_clientContext,
  974.                                         PR_TRUE);
  975.   PR_FREEIF(extraParams);
  976.   if (rv != SSM_SUCCESS) { 
  977.     SSM_UnlockUIEvent(&req->ctrlconn->super.super);
  978.     goto loser;
  979.   }
  980.   SSM_WaitUIEvent(target, PR_INTERVAL_NO_TIMEOUT);
  981.  loser:
  982.   return rv;
  983. }