CASA/c_adlib/ad_ff/native/FirefoxPasswordManager.cpp
2006-03-10 18:39:22 +00:00

728 lines
21 KiB
C++

/***********************************************************************
*
* Copyright (C) 2005-2006 Novell, Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, Novell, Inc.
*
* To contact Novell about this file by physical or electronic mail,
* you may find current contact information at www.novell.com.
*
***********************************************************************/
#include "FirefoxPasswordManager.h"
#include "Common.h"
#include "ProfileManager.h"
ProfileManager profileManager[MAX_PROFILE_COUNT];
int profileCount = 0;
/**
* Check if firefox is there on the system
*
* @return 1 if firefox libraries are present
* 0 otherwise
*
* It loads the libraries from the firefox library path and if they are loaded
* successfully then that indicates that firefox is present.
*
*/
extern "C" APIEXPORT int FPM_IsStoreAvailable()
{
ProfileManager pm;
return pm.IsStoreAvailable();
}
/*
* Gets the list of profile names...
*
* @param[in/out] profiles pointer to array of profile names
* @param[in/out] profileFlag Indicates if default profile or not.
* @return count count of profiles
* 0 no profiles found
* < 0 on error
*
* If one or more profiles found then profiles array is filled with
* the profile names and count of profiles is returned. ProfileFlag[]
* array is filled with 1 or 0 to indicate if the respective profile
* is default profile or not.If no profiles found then value 0 is
* returned and negative values is returned if there is an error.
*
*/
extern "C" APIEXPORT int FPM_GetProfileList(char **profileList[], int *profileFlag[])
{
#ifdef WIN32
char profileDir[MAX_PATH] = "";
char partialPath[] = "Application Data\\Mozilla\\Firefox";
char profilePath[MAX_PATH];
char line[1024];
DWORD pathSize = MAX_PATH;
char *finalProfilePath = NULL;
int profileCount = 0;
unsigned int i;
HANDLE token;
// Get current user's profile directory
if( OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token) == FALSE )
{
PrintMessage(MESG_ERROR, "\n GetProfileList : Failed to get current process token ");
return FPM_FALSE;
}
if( GetUserProfileDirectory(token, profileDir, &pathSize) == FALSE )
{
PrintMessage(MESG_ERROR, "\n GetProfileList : Failed to get user profile directory");
return FPM_FALSE;
}
PrintMessage(MESG_DEBUG, "\n GetProfileList : User Profile directory = %s", profileDir);
// Get firefox profile directory
strcpy(profilePath, profileDir);
strcat(profilePath,"\\");
strcat(profilePath,partialPath);
strcat(profilePath,"\\profiles.ini");
PrintMessage(MESG_DEBUG, "\n GetProfileList : Firefox profile dir path = %s ", profilePath);
#else // Linux platform....
char profileDir[] ="/.mozilla/firefox";
char profileFile[] ="/.mozilla/firefox/profiles.ini";
char line[1024];
char *profilePath = NULL;
char *homeDir = NULL;
char *finalProfilePath = NULL;
int profileCount = 0;
unsigned int i;
// Get home directory
homeDir = getenv("HOME");
if(homeDir == NULL )
{
PrintMessage(MESG_ERROR, "\n GetProfileList : Unable to get home directory ");
return FPM_FALSE;
}
profilePath = (char*) malloc( strlen(homeDir) + strlen(profileFile) + 3 );
if( profilePath == NULL )
{
PrintMessage(MESG_ERROR, "\n GetProfileList : Insufficient memory ");
return FPM_FALSE;
}
strcpy(profilePath,homeDir);
strcat(profilePath,profileFile);
PrintMessage(MESG_DEBUG, "\n GetProfileList : Firefox profile dir path = %s ", profilePath);
#endif
// Open the firefox profile setting file
FILE *profile = fopen(profilePath, "r");
if( profile == NULL )
{
PrintMessage(MESG_ERROR, "\n GetProfileList : Unable to find firefox profile file : %s ", profilePath);
return FPM_FALSE;
}
// First find out the count of profiles....
profileCount = 0;
while(fgets(line, 1024, profile))
{
// Remove trailing end of line character
line[strlen(line)-1]= 0;
// Convert to smaller case until "=" found....
for(i=0; i<strlen(line); i++)
{
if( line[i] == '=' )
break;
if( line[i] >=65 && line[i]<=90 )
line[i]+=32;
}
if( strstr(line, "name=") != NULL )
profileCount++;
}
PrintMessage(MESG_DEBUG, "\n GetProfileList : Total profiles found = %d ", profileCount);
if( profileCount == 0 )
{
fclose(profile);
return FPM_FALSE;
}
*profileList = ( char**) malloc(profileCount * sizeof (char *));
*profileFlag = ( int * ) malloc(profileCount * sizeof(int));
if( *profileList == NULL || *profileFlag == NULL )
{
PrintMessage(MESG_ERROR, "\n GetProfileList : Insufficient memory ");
fclose(profile);
return FPM_FALSE;
}
char **profList = *profileList;
int *profFlag = *profileFlag;
// Now read the profile names and store it..
fseek(profile, 0, SEEK_SET);
profileCount = 0;
while(fgets(line, 1024, profile))
{
// Remove trailing end of line character
line[strlen(line)-1]= 0;
// Convert to smaller case until "=" found....
for(i=0; i<strlen(line); i++)
{
if( line[i] == '=' )
break;
if( line[i] >=65 && line[i]<=90 )
line[i]+=32;
}
if( strstr(line, "name=") != NULL )
{
char *temp = strchr(line,'=') + 1;
profList[profileCount] = (char*) malloc(strlen(temp)+1);
if( profList[profileCount] == NULL )
{
PrintMessage(MESG_ERROR, "\n GetProfileList : Insufficient memory ");
fclose(profile);
return 0;
}
strcpy(profList[profileCount],temp);
profFlag[profileCount] = 0;
PrintMessage(MESG_DEBUG, "\n GetProfileList : Found profile = [%s]", profList[profileCount]);
profileCount++;
continue;
}
// check if the current profile is default
if( strstr(line, "default=1") != NULL )
{
profFlag[profileCount-1] = 1;
}
}
fclose(profile);
// if there is only one profile then set it default profile
if( profileCount == 1 )
{
**profileFlag = 1;
}
return profileCount;
}
/**
* Initializes the firefox library with the specified profile
*
* @param profileName name of the profile
* @return 1 on success
* <=0 on error
*
* It initializes the firefox library with the specified profile. This must be called before
* invoking any operation on the specified profile.
* It performs following tasks
* * Determine firefox profile directory
* * Loads the firefox security libraries.
* * Initializes the firefox security library for the profile.
*
* If the mentioned profile is not found then FPM_PROFILE_NOT_PRESENT will be returned. If there is
* an error in loading or initializing the firefox library then FPM_LIBRARY_LOAD_FAILED or FPM_LIBRARY_INIT_FAILED
* is returned. If user has not enabled "remember passwords" then certain files (key3.db, cert8.db) required for
* initialization will not be present in the profile directory. This can cause FPM_LIBRARY_INIT_FAILED error.
*
*/
extern "C" APIEXPORT int FPM_FirefoxProfileInit(char *profileName)
{
int retValue;
int profileIndex = -1;
// Check if the object for specified profile already present...
for(int i=0; i< profileCount; i++)
{
if( profileManager[i].profileName != NULL )
{
if( STRCMPI(profileManager[i].profileName, profileName) == 0 )
{
PrintMessage(MESG_DEBUG, "\n FirefoxProfileInit : Object for specified profile %s exist ", profileName);
profileIndex = i;
break;
}
}
}
// This is new profile...
if( profileIndex == -1)
{
if( (profileCount + 1) >= MAX_PROFILE_COUNT)
{
PrintMessage(MESG_ERROR, "\n FirefoxProfileInit : Max profile count exceeded.");
return FPM_PROFILE_LIMIT_EXCEEDED;
}
profileIndex = profileCount;
profileCount++;
}
// check if the profile is already initialized...
if( profileManager[profileIndex].isInitialized == FPM_TRUE )
{
PrintMessage(MESG_DEBUG, "\n FirefoxProfileInit : Specified profile %s is already initialized", profileName);
return FPM_TRUE;
}
if( (retValue = profileManager[profileIndex].ProfileInit(profileName)) != FPM_TRUE )
{
PrintMessage(MESG_ERROR, "\n FirefoxProfileInit : Failed to initialize the profile %s ", profileName);
return retValue;
}
PrintMessage(MESG_DEBUG, "\n FirefoxProfileInit : Firefox profile %s initialized successfully ", profileName);
return FPM_TRUE;
}
/**
* Uninitializes the specified profile.
*
* @param profileName name of the profile
* @return 1 on success
* <=0 on error
*
* Uninitializes the specified profile and unloads the firefox security library.
* It also cleans up internal data structure.
*/
extern "C" APIEXPORT int FPM_FirefoxProfileExit(char *profileName)
{
// Find the profile...
for(int i=0; i< profileCount; i++)
{
if( profileManager[i].profileName != NULL )
{
if( STRCMPI(profileManager[i].profileName, profileName) == 0 )
{
// check if its initialized
if( profileManager[i].isInitialized == FPM_TRUE )
{
PrintMessage(MESG_DEBUG, "\n FirefoxProfileExit : Exiting the firefox profile %s ", profileName);
profileManager[i].ProfileExit();
return FPM_TRUE;
}
else
{
PrintMessage(MESG_ERROR, "\n FirefoxProfileExit : Specified profile %s is not initialized , cannot exit the profile", profileName);
return FPM_PROFILE_NOT_INITIALIZED;
}
}
}
}
PrintMessage(MESG_ERROR, "\n FirefoxProfileExit : Specified profile %s is not found", profileName);
return FPM_PROFILE_NOT_PRESENT;
}
/**
* Verifies if master passsword is set for the specified profile
*
* @param profileName name of the profile
* @return 1 if master password is set
* 0 if master password not set
*
* Checks if the master password is set or not for the specified profile. The application can
* use this function to determine if the user has set the master password. If so it can prompt
* the user to enter the master password.
*/
extern "C" APIEXPORT int FPM_IsMasterPasswordSet(char *profileName)
{
// Find the profile...
for(int i=0; i< profileCount; i++)
{
if( profileManager[i].profileName != NULL )
{
if( STRCMPI(profileManager[i].profileName, profileName) == 0 )
{
// check if its initialized
if( profileManager[i].isInitialized == FPM_TRUE )
{
PrintMessage(MESG_DEBUG, "\n IsMasterPasswordSet : invoking IsMasterPasswordSet for profile %s", profileName);
return profileManager[i].IsMasterPasswordSet();
}
else
{
PrintMessage(MESG_ERROR, "\n IsMasterPasswordSet : Specified profile %s is not initialized ", profileName);
return FPM_PROFILE_NOT_INITIALIZED;
}
}
}
}
PrintMessage(MESG_ERROR, "\n IsMasterPasswordSet : Specified profile %s is not found", profileName);
return FPM_PROFILE_NOT_PRESENT;
}
/**
* Checks if the master password is correct for the specified profile.
*
* @param profileName name of the profile
* @param masterPassword Master password to be checked.
* @return 1 if the specified master password is correct
* 0 if the master password is wrong.
*
*
* Check if the specified master password is correct or not. If it is
* correct then password is stored to the internal store for later use.
* If it is wrong then nothing is stored and 0 will be returned.
*/
extern "C" APIEXPORT int FPM_CheckMasterPassword(char *profileName, char *masterPassword)
{
// Find the profile...
for(int i=0; i< profileCount; i++)
{
if( profileManager[i].profileName != NULL )
{
if( STRCMPI(profileManager[i].profileName, profileName) == 0 )
{
// check if its initialized
if( profileManager[i].isInitialized == FPM_TRUE )
{
PrintMessage(MESG_DEBUG, "\n CheckMasterPassword : invoking CheckMasterPassword for profile %s", profileName);
return profileManager[i].CheckMasterPassword(masterPassword, 1);
}
else
{
PrintMessage(MESG_ERROR, "\n CheckMasterPassword : Specified profile %s is not initialized ", profileName);
return FPM_PROFILE_NOT_INITIALIZED;
}
}
}
}
PrintMessage(MESG_ERROR, "\n CheckMasterPassword : Specified profile %s is not found", profileName);
return FPM_PROFILE_NOT_PRESENT;
}
/**
* Loads the signon data from the firefox signon file for specified profile
*
* @param profileName name of the profile
* @param struct Host** pointer to list of signon host structure
* @param doRefresh signon data to be refreshed or not
* @return 1 success
* <= 0 If an error has occurred.
*
* Returns the pointer to the internal signon data store which contains list of hosts
* and associated name/value pairs. If doRefresh value is positive then fresh signon
* data is loaded from the signon file. Otherwise current signon data is returned.
*
* If the master password is set and its not specified or wrong password is specified
* then error code FPM_MASTERPASSWORD_WRONG will be returned. In this case use
* CheckMasterPassword function to set the correct master password and then call this
* function again.
*
* In case of error in reading signon information FPM_SIGNON_FILE_READ_ERROR or
* FPM_SIGNON_FILE_NOT_PRESENT will be returned.
*
*/
extern "C" APIEXPORT int FPM_GetSignonData(char *profileName,struct Host **host, int doRefresh)
{
// Find the profile...
for(int i=0; i< profileCount; i++)
{
if( profileManager[i].profileName != NULL )
{
if( STRCMPI(profileManager[i].profileName, profileName) == 0 )
{
// check if its initialized
if( profileManager[i].isInitialized == FPM_TRUE )
{
PrintMessage(MESG_DEBUG, "\n GetSignonData : invoking GetSignonData for profile %s", profileName);
return profileManager[i].GetSignonData(host, doRefresh);
}
else
{
PrintMessage(MESG_ERROR, "\n GetSignonData : Specified profile %s is not initialized", profileName);
return FPM_PROFILE_NOT_INITIALIZED;
}
}
}
}
PrintMessage(MESG_ERROR, "\n GetSignonData : Specified profile %s is not found", profileName);
return FPM_PROFILE_NOT_PRESENT;
}
/**
* Updates the firefox signon file with new signon data.
*
* @param profileName name of the profile
* @return 1 If signon data written to the disk successfully
* <=0 If an error has occurred.
*
* Writes the signon data from the internal signon data store to the disk. If an
* error occurs then proper error code will be returned. If the master password is set
* and its not specified or wrong password is specified then error code FPM_MASTERPASSWORD_WRONG
* will be returned. In this case use CheckMasterPassword function to set the correct
* master password and then call this function again.
*
* In case of write error, error code FPM_SIGNON_FILE_WRITE_ERROR will be returned.
*
* If the signon file is locked then error code FPM_SIGNON_FILE_LOCKED will be
* returned. In this case application should ask the user to close the firefox
* application and then it should call this function again.
*
*/
extern "C" APIEXPORT int FPM_WriteSignonData(char *profileName)
{
// Find the profile...
for(int i=0; i< profileCount; i++)
{
if( profileManager[i].profileName != NULL )
{
if( STRCMPI(profileManager[i].profileName, profileName) == 0 )
{
// check if its initialized
if( profileManager[i].isInitialized == FPM_TRUE )
{
PrintMessage(MESG_DEBUG, "\n WriteSignonData : invoking WriteSignonData for profile %s", profileName);
return profileManager[i].WriteSignonData();
}
else
{
PrintMessage(MESG_ERROR, "\n WriteSignonData : Specified profile %s is not initialized", profileName);
return FPM_PROFILE_NOT_INITIALIZED;
}
}
}
}
PrintMessage(MESG_ERROR, "\n WriteSignonData : Specified profile %s is not found", profileName);
return FPM_PROFILE_NOT_PRESENT;
}
/**
* Adds signon data for new host...
*
* @param profileName name of the profile
* @param struct Host* pointer to host structure to be added
* @param doUpdate signon data to be written to the file or not
* @return 1 success
* <=0 error
*
* Adds the specified host information to the internal signon data store. If the
* value of doUpdate is positive then the entire signon data is written to the file.
* Otherwise changes are done only in the internal data store.
*
* If doUpdate is positive then error code may be from FPM_WriteSignonData function.
*
*/
extern "C" APIEXPORT int FPM_AddHost(char *profileName, struct Host *host, int doUpdate)
{
// Find the profile...
for(int i=0; i< profileCount; i++)
{
if( profileManager[i].profileName != NULL )
{
if( STRCMPI(profileManager[i].profileName, profileName) == 0 )
{
// check if its initialized
if( profileManager[i].isInitialized == FPM_TRUE )
{
PrintMessage(MESG_DEBUG, "\n AddHost : invoking AddHost for profile %s", profileName);
return profileManager[i].AddHost(host, doUpdate);
}
else
{
PrintMessage(MESG_ERROR, "\n AddHost : Specified profile %s is not initialized", profileName);
return FPM_PROFILE_NOT_INITIALIZED;
}
}
}
}
PrintMessage(MESG_ERROR, "\n AddHost : Specified profile %s is not found", profileName);
return FPM_PROFILE_NOT_PRESENT;
}
/**
* Modifies the credentials for the specified host url for specified profile.
*
* @param profileName name of the profile
* @param struct Host* pointer to host structure to be modified.
* @param doUpdate signon data to be written to the file or not
* @return 1 success
* <=0 error
*
* Modifes the values of the specified host with new values. If the value
* of doUpdate is positive then the entire signon data is written to the file.
* Otherwise changes are done only in the internal data store. If any of
* the names ( name/value pairs ) is not matched with the existing name in the
* Host's username/password list then error FPM_NAME_NOT_PRESENT is returned.
*
* If doUpdate is positive then error code may be from FPM_WriteSignonData function.
*
*/
extern "C" APIEXPORT int FPM_ModifyHost(char *profileName, struct Host *host, int doUpdate)
{
// Find the profile...
for(int i=0; i< profileCount; i++)
{
if( profileManager[i].profileName != NULL )
{
if( STRCMPI(profileManager[i].profileName, profileName) == 0 )
{
// check if its initialized
if( profileManager[i].isInitialized == FPM_TRUE )
{
PrintMessage(MESG_DEBUG, "\n ModifyHost : invoking ModifyHost for profile %s", profileName);
return profileManager[i].ModifyHost(host, doUpdate);
}
else
{
PrintMessage(MESG_ERROR, "\n ModifyHost : Specified profile %s is not initialized", profileName);
return FPM_PROFILE_NOT_INITIALIZED;
}
}
}
}
PrintMessage(MESG_ERROR, "\n ModifyHost : Specified profile %s is not found", profileName);
return FPM_PROFILE_NOT_PRESENT;
}
/**
* Removes the signon credentials for specified host
*
* @param profileName name of the profile
* @param hostName complete URL of the host name
* @param doUpdate signon data to be written to the file or not
*
* @return 1 on success
* <=0 on error
*
* Removes the specified host from the internal signon data store. All
* name-value pairs associated with specified host will also be removed.
* If the value of doUpdate is positive then the entire signon data is
* written to the file. Otherwise changes are done only in the internal data store.
*
* If doUpdate is positive then error code may be from FPM_WriteSignonData function.
*
*/
extern "C" APIEXPORT int FPM_RemoveHost(char *profileName, char *hostName, int doUpdate)
{
// Find the profile...
for(int i=0; i< profileCount; i++)
{
if( profileManager[i].profileName != NULL )
{
if( STRCMPI(profileManager[i].profileName, profileName) == 0 )
{
// check if its initialized
if( profileManager[i].isInitialized == FPM_TRUE )
{
PrintMessage(MESG_DEBUG, "\n RemoveHost : invoking RemoveHost for profile %s", profileName);
return profileManager[i].RemoveHost(hostName, doUpdate);
}
else
{
PrintMessage(MESG_ERROR, "\n RemoveHost : Specified profile %s is not initialized", profileName);
return FPM_PROFILE_NOT_INITIALIZED;
}
}
}
}
PrintMessage(MESG_ERROR, "\n RemoveHost : Specified profile %s is not found", profileName);
return FPM_PROFILE_NOT_PRESENT;
}