/*********************************************************************** * * 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=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; }