StringX PWSAuxParse::GetAutoTypeString(const CItemData &ci, const PWScore &core, std::vector<size_t> &vactionverboffsets) { // Set up all the data (a shortcut entry will change all of them!) StringX sxgroup = ci.GetGroup(); StringX sxtitle = ci.GetTitle(); StringX sxuser = ci.GetUser(); StringX sxpwd = ci.GetPassword(); StringX sxnotes = ci.GetNotes(); StringX sxurl = ci.GetURL(); StringX sxemail = ci.GetEmail(); StringX sxautotype = ci.GetAutoType(); if (ci.IsAlias()) { const CItemData *pbci = core.GetBaseEntry(&ci); if (pbci != NULL) { sxpwd = pbci->GetPassword(); } else { // Problem - alias entry without a base! ASSERT(0); } } else if (ci.IsShortcut()) { const CItemData *pbci = core.GetBaseEntry(&ci); if (pbci != NULL) { sxgroup = pbci->GetGroup(); sxtitle = pbci->GetTitle(); sxuser = pbci->GetUser(); sxpwd = pbci->GetPassword(); sxnotes = pbci->GetNotes(); sxurl = pbci->GetURL(); sxemail = pbci->GetEmail(); sxautotype = pbci->GetAutoType(); } else { // Problem - shortcut entry without a base! ASSERT(0); } } // ci.IsShortcut() // If empty, try the database default if (sxautotype.empty()) { sxautotype = PWSprefs::GetInstance()-> GetPref(PWSprefs::DefaultAutotypeString); // If still empty, take this default if (sxautotype.empty()) { // checking for user and password for default settings if (!sxpwd.empty()){ if (!sxuser.empty()) sxautotype = DEFAULT_AUTOTYPE; else sxautotype = _T("\\p\\n"); } } } return PWSAuxParse::GetAutoTypeString(sxautotype, sxgroup, sxtitle, sxuser, sxpwd, sxnotes, sxurl, sxemail, vactionverboffsets); }
static void ParseNotes(StringX &sxNotes, std::vector<StringX> &vsxnotes_lines) { if (!sxNotes.empty()) { // Use \n and \r to tokenise this line StringX::size_type st_start(0), st_end(0); const StringX sxdelim = _T("\r\n"); StringX sxline; StringX::size_type st_index; while (st_end != StringX::npos) { st_end = sxNotes.find(sxdelim, st_start); sxline = (sxNotes.substr(st_start, (st_end == StringX::npos) ? StringX::npos : st_end - st_start)); st_index = 0; // Remove all tabs - \t for (;;) { st_index = sxline.find(_T("\\t"), st_index); if (st_index == StringX::npos) break; sxline.replace(st_index, 2, _T("")); st_index += 1; } vsxnotes_lines.push_back(sxline); st_start = ((st_end > (StringX::npos - sxdelim.size())) ? StringX::npos : st_end + sxdelim.size()); } } }
int PWSfile::CheckPasskey(const StringX &filename, const StringX &passkey, VERSION &version) { /** * We start with V3 because it's the quickest to rule out * due to header/footer. * V4 can take a looong time if the iter value's too big. * XXX Need to address this later with a popup prompting the user. */ if (passkey.empty()) return WRONG_PASSWORD; int status; version = UNKNOWN_VERSION; status = PWSfileV3::CheckPasskey(filename, passkey); if (status == SUCCESS) { version = V30; } else { status = PWSfileV4::CheckPasskey(filename, passkey); if (status == SUCCESS) version = V40; else { status = PWSfileV1V2::CheckPasskey(filename, passkey); if (status == SUCCESS) version = V20; // or V17? } } return status; }
void EditShortcut::ItemFieldsToDialog() { // Populate the combo box std::vector<stringT> aryGroups; m_core.GetUniqueGroups(aryGroups); for (size_t igrp = 0; igrp < aryGroups.size(); igrp++) { m_groupCtrl->Append(aryGroups[igrp].c_str()); } // select relevant group const StringX group = m_item->GetGroup(); if (!group.empty()) for (size_t igrp = 0; igrp < aryGroups.size(); igrp++) if (group == aryGroups[igrp].c_str()) { m_groupCtrl->SetSelection(reinterpret_cast<int &>(igrp)); break; } m_title = m_item->GetTitle().c_str(); m_user = m_item->GetUser().c_str(); m_created = m_item->GetCTimeL().c_str(); m_lastAccess = m_item->GetATimeL().c_str(); m_lastAny = m_item->GetRMTimeL().c_str(); const CItemData *base = m_core.GetBaseEntry(m_item); if (base != NULL) { m_lastChanged = base->GetRMTimeL().c_str(); } else { m_lastChanged = _("Unknown"); // Internal error } }
static StringX ReMergeNotes(const CItemData &item) { StringX notes = item.GetNotes(); const StringX url(item.GetURL()); if (!url.empty()) { notes += _T("\r\n"); notes += url; } const StringX at(item.GetAutoType()); if (!at.empty()) { stringT cs_autotype; LoadAString(cs_autotype, IDSC_AUTOTYPE); notes += _T("\r\n"); notes += cs_autotype.c_str(); notes += at; } return notes; }
stringT CPasswordCharPool::GetDefaultSymbols() { stringT symbols; const StringX sx_symbols = PWSprefs::GetInstance()->GetPref(PWSprefs::DefaultSymbols); if (!sx_symbols.empty()) symbols = sx_symbols.c_str(); else symbols = std_symbol_chars; return symbols; }
lines_vec stream2vec(StringXStream &wss) { lines_vec vlines; do { StringX line; std::getline(wss, line); if ( !line.empty() ) vlines.push_back(line); } while( !wss.eof() ); return vlines; }
void PasswordSafeFrame::DoCopyEmail(CItemData &item) { const StringX mailto = item.IsEmailEmpty()? (item.IsURLEmail()? item.GetURL(): StringX()) : item.GetEmail(); if (!mailto.empty()) { PWSclipboard::GetInstance()->SetData(mailto); UpdateAccessTime(item); } }
bool CRUEList::GetAllMenuItemStrings(vector<RUEntryData> &ListofAllMenuStrings) const { RUEntryData ruentrydata; bool retval = false; RUEListConstIter iter; for (iter = m_RUEList.begin(); iter != m_RUEList.end(); iter++) { ItemListConstIter pw_listpos = m_core.Find(*iter); if (pw_listpos == m_core.GetEntryEndIter()) { ruentrydata.string = L""; ruentrydata.image = -1; ruentrydata.pci = NULL; } else { const CItemData &ci = m_core.GetEntry(pw_listpos); StringX group = ci.GetGroup(); StringX title = ci.GetTitle(); StringX user = ci.GetUser(); if (group.empty()) group = L" "; if (title.empty()) title = L" "; if (user.empty()) user = L" "; // Looks similar to <g><t><u> ruentrydata.string = L"\xab" + group + L"\xbb " + L"\xab" + title + L"\xbb " + L"\xab" + user + L"\xbb"; ruentrydata.image = app.GetMainDlg()->GetEntryImage(ci); ruentrydata.pci = (CItemData *)&ci; } ListofAllMenuStrings.push_back(ruentrydata); retval = true; } return retval; }
wxTreeItemId PWSTreeCtrl::AddGroup(const StringX &group) { wxTreeItemId ti = GetRootItem(); if (!ti.IsOk()) ti=AddRoot(wxString()); // Add a group at the end of path wxTreeItemId si; if (!group.empty()) { StringX path = group; StringX s; do { s = GetPathElem(path); if (!ExistsInTree(ti, s, si)) { ti = AppendItem(ti, s.c_str()); wxTreeCtrl::SetItemImage(ti, NODE_II); } else ti = si; } while (!path.empty()); } return ti; }
inline wostream& print_field_value(wostream &os, wchar_t tag, const CItemData &item, CItemData::FieldType ft) { StringX fieldValue; switch (ft) { case CItemData::DCA: case CItemData::SHIFTDCA: { int16 dca = -1; if (item.GetDCA(dca) != -1) { LoadAString(fieldValue, dca2str(dca)); } break; } case CItemData::PWHIST: { const StringX pwh_str = item.GetPWHistory(); if (!pwh_str.empty()) { StringXStream value_stream; size_t ignored; PWHistList pwhl; const bool save_pwhistory = CreatePWHistoryList(pwh_str, ignored, ignored, pwhl, PWSUtil::TMC_LOCALE); value_stream << L"Save: " << (save_pwhistory? L"Yes" : L"No"); if ( !pwhl.empty() ) value_stream << endl; for( const auto &pwh: pwhl) value_stream << pwh.changedate << L": " << pwh.password << endl; fieldValue = value_stream.str(); } break; } case CItemData::POLICY: { PWPolicy policy; item.GetPWPolicy(policy); fieldValue = policy.GetDisplayString(); break; } default: fieldValue = item.GetFieldValue(ft); break; } const StringX sep1{L' '}, sep2{L": "}; StringXStream tmpStream; tmpStream << tag << L' ' << item.FieldName(ft) << L": " << fieldValue; const auto offset = 1 /*tag*/ + sep1.size() + sep2.size() + item.FieldName(ft).size(); lines_vec lines{ stream2vec(tmpStream)}; if ( lines.size() > 1) { std::for_each( lines.begin()+1, lines.end(), [offset](StringX &line) { line.insert(0, offset, L' '); }); } for( const auto &line: lines ) os << line << endl; return os; }
int PWSfile::CheckPasskey(const StringX &filename, const StringX &passkey, VERSION &version) { if (passkey.empty()) return WRONG_PASSWORD; int status; version = UNKNOWN_VERSION; status = PWSfileV3::CheckPasskey(filename, passkey); if (status == SUCCESS) version = V30; if (status == NOT_PWS3_FILE) { status = PWSfileV1V2::CheckPasskey(filename, passkey); if (status == SUCCESS) version = V20; // or V17? } return status; }
///////////////////////////////////////////////////////////////// // Context diff //////// inline wchar_t context_tag(CItem::FieldType ft, const CItemData::FieldBits &fields, const CItemData &item, const CItemData &otherItem) { // The two items were compared & found to be differing on this field // only show this tag for fields there were compared if (fields.test(ft)) return '!'; const StringX val{item.GetFieldValue(ft)}; // This field was not compared, it could be different. Print it only if // it is the same in both items if (val == otherItem.GetFieldValue(ft)) return L' '; if (val.empty()) return L'+'; // Don't print it return L'-'; }
bool PWSRun::issuecmd(const StringX &sxFile, const StringX &sxParameters, const bool &bAutotype) const { SHELLEXECUTEINFO si; ZeroMemory(&si, sizeof(SHELLEXECUTEINFO)); si.cbSize = sizeof(SHELLEXECUTEINFO); si.nShow = SW_SHOWNORMAL; si.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_DOENVSUBST; si.lpFile = sxFile.c_str(); if (!sxParameters.empty()) { si.lpParameters = sxParameters.c_str(); } BOOL bAT_init(FALSE); if (bAutotype && isValid()) { if (pImpl->pInit != NULL && pImpl->pUnInit != NULL && pImpl->hCBWnd != NULL) { // OK - try and make it tell us! Won't if another instance of // PWS is doing this at exactly the same time - silly user! bAT_init = pImpl->pInit(pImpl->hCBWnd); pws_os::Trace(_T("PWSRun::issuecmd - AT_HK_Initialise: %s\n"), bAT_init == TRUE ? _T("OK") : _T("FAILED")); } } BOOL shellExecStatus = ::ShellExecuteEx(&si); if (shellExecStatus != TRUE) { // ShellExecute writes its own message on failure! if (bAT_init) { bAT_init = pImpl->pUnInit(pImpl->hCBWnd); pws_os::Trace(_T("PWSRun::issuecmd - AT_HK_UnInitialise: %s\n"), bAT_init == TRUE ? _T("OK") : _T("FAILED")); } return false; } return true; }
bool CUTF8Conv::ToUTF8(const StringX &data, const unsigned char *&utf8, size_t &utf8Len) { // If we're not in Unicode, call MultiByteToWideChar to get from // current codepage to Unicode, and then WideCharToMultiByte to // get to UTF-8 encoding. if (data.empty()) { utf8Len = 0; return true; } wchar_t *wcPtr = const_cast<wchar_t *>(data.c_str()); size_t wcLen = data.length()+1; // first get needed utf8 buffer size size_t mbLen = pws_os::wcstombs(NULL, 0, wcPtr, wcLen); if (mbLen == 0) { // uh-oh ASSERT(0); m_utf8Len = 0; return false; } // Allocate buffer (if previous allocation was smaller) if (mbLen > m_utf8MaxLen) { if (m_utf8 != NULL) trashMemory(m_utf8, m_utf8MaxLen); delete[] m_utf8; m_utf8 = new unsigned char[mbLen]; m_utf8MaxLen = mbLen; } // Finally get result m_utf8Len = pws_os::wcstombs(reinterpret_cast<char *>(m_utf8), mbLen, wcPtr, wcLen); ASSERT(m_utf8Len != 0); m_utf8Len--; // remove unneeded null termination utf8 = m_utf8; utf8Len = m_utf8Len; return true; }
HTREEITEM CCWTreeCtrl::AddGroup(const CString &group) { // Add a group at the end of path HTREEITEM ti = TVI_ROOT; HTREEITEM si; if (!group.IsEmpty()) { StringX sxPath = group; StringX sxTemp, sxPath2Root(L""); do { sxTemp = GetFirstPathElem(sxPath); if (sxPath2Root.empty()) sxPath2Root = sxTemp; else sxPath2Root += GROUP_SEP2 + sxTemp; if (!ExistsInTree(ti, sxTemp, si)) { ti = InsertItem(sxTemp.c_str(), ti, TVI_SORT); SetItemImage(ti, CCWTreeCtrl::GROUP, CCWTreeCtrl::GROUP); } else ti = si; } while (!sxPath.empty()); } return ti; }
bool CUTF8Conv::ToUTF8(const StringX &data, const unsigned char *&utf8, size_t &utf8Len) { // If we're not in Unicode, call MultiByteToWideChar to get from // current codepage to Unicode, and then WideCharToMultiByte to // get to UTF-8 encoding. if (data.empty()) { utf8Len = 0; return true; } wchar_t *wcPtr; // to hide UNICODE differences size_t wcLen; // number of wide chars needed #ifndef UNICODE // first get needed wide char buffer size wcLen = pws_os::mbstowcs(NULL, 0, data.c_str(), size_t(-1), false); if (wcLen == 0) { // uh-oh ASSERT(0); m_utf8Len = 0; return false; } // Allocate buffer (if previous allocation was smaller) if (wcLen > m_wcMaxLen) { if (m_wc != NULL) trashMemory(m_wc, m_wcMaxLen * sizeof(m_wc[0])); delete[] m_wc; m_wc = new wchar_t[wcLen]; m_wcMaxLen = wcLen; } // next translate to buffer wcLen = pws_os::mbstowcs(m_wc, wcLen, data.c_str(), size_t(-1), false); ASSERT(wcLen != 0); wcPtr = m_wc; #else wcPtr = const_cast<wchar_t *>(data.c_str()); wcLen = data.length()+1; #endif // first get needed utf8 buffer size size_t mbLen = pws_os::wcstombs(NULL, 0, wcPtr, wcLen); if (mbLen == 0) { // uh-oh ASSERT(0); m_utf8Len = 0; return false; } // Allocate buffer (if previous allocation was smaller) if (mbLen > m_utf8MaxLen) { if (m_utf8 != NULL) trashMemory(m_utf8, m_utf8MaxLen); delete[] m_utf8; m_utf8 = new unsigned char[mbLen]; m_utf8MaxLen = mbLen; } // Finally get result m_utf8Len = pws_os::wcstombs(reinterpret_cast<char *>(m_utf8), mbLen, wcPtr, wcLen); ASSERT(m_utf8Len != 0); m_utf8Len--; // remove unneeded null termination utf8 = m_utf8; utf8Len = m_utf8Len; return true; }
// In following, char * is managed by caller. bool CUTF8Conv::FromUTF8(const unsigned char *utf8, size_t utf8Len, StringX &data) { // Call MultiByteToWideChar to get from UTF-8 to Unicode. // If we're not in Unicode, call WideCharToMultiByte to // get to current codepage. // // Due to a bug in pre-3.08 versions, data may be in ACP // instead of UTF-8. We try to detect and workaround this. if (utf8Len == 0 || (utf8Len == 1 && utf8[0] == '\0')) { data = _T(""); return true; } ASSERT(utf8 != NULL); // first get needed wide char buffer size size_t wcLen = pws_os::mbstowcs(NULL, 0, reinterpret_cast<const char *>(utf8), size_t(-1), !m_cp_acp); if (wcLen == 0) { // uh-oh // it seems that this always returns non-zero, even if encoding // broken. Therefore, we'll give a conservative value here, // and try to recover later pws_os::Trace0(_T("FromUTF8: Couldn't get buffer size - guessing!")); wcLen = sizeof(StringX::value_type) * (utf8Len + 1); } // Allocate buffer (if previous allocation was smaller) if (wcLen > m_wcMaxLen) { if (m_wc != NULL) trashMemory(m_wc, m_wcMaxLen); delete[] m_wc; m_wc = new wchar_t[wcLen]; m_wcMaxLen = wcLen; } // next translate to buffer wcLen = pws_os::mbstowcs(m_wc, wcLen, reinterpret_cast<const char *>(utf8), size_t(-1), !m_cp_acp); #ifdef _WIN32 if (wcLen == 0) { DWORD errCode = GetLastError(); switch (errCode) { case ERROR_INSUFFICIENT_BUFFER: pws_os::Trace0(_T("INSUFFICIENT BUFFER")); break; case ERROR_INVALID_FLAGS: pws_os::Trace0(_T("INVALID FLAGS")); break; case ERROR_INVALID_PARAMETER: pws_os::Trace0(_T("INVALID PARAMETER")); break; case ERROR_NO_UNICODE_TRANSLATION: // try to recover pws_os::Trace0(_T("NO UNICODE TRANSLATION")); wcLen = MultiByteToWideChar(CP_ACP, // code page 0, // character-type options LPSTR(utf8), // string to map -1, // -1 means null-terminated m_wc, // output buffer reinterpret_cast<int &>(wcLen)); // output buffer size if (wcLen > 0) { pws_os::Trace0(_T("FromUTF8: recovery succeeded!")); } break; default: ASSERT(0); } } ASSERT(wcLen != 0); #endif /* _WIN32 */ #ifdef UNICODE if (wcLen != 0) { m_wc[wcLen - 1] = TCHAR('\0'); data = m_wc; return true; } else return false; #else /* Go from Unicode to Locale encoding */ // first get needed utf8 buffer size size_t mbLen = pws_os::wcstombs(NULL, 0, m_wc, size_t(-1), false); if (mbLen == 0) { // uh-oh ASSERT(0); data = _T(""); return false; } // Allocate buffer (if previous allocation was smaller) if (mbLen > m_tmpMaxLen) { if (m_tmp != NULL) trashMemory(m_tmp, m_tmpMaxLen); delete[] m_tmp; m_tmp = new unsigned char[mbLen]; m_tmpMaxLen = mbLen; } // Finally get result size_t tmpLen = pws_os::wcstombs((char *)m_tmp, mbLen, m_wc, size_t(-1), false); ASSERT(tmpLen == mbLen); m_tmp[mbLen - 1] = '\0'; // char, no need to _T()... data = (char *)m_tmp; ASSERT(!data.empty()); return true; #endif /* !UNICODE */ }
StringX PWSAuxParse::GetAutoTypeString(const StringX &sx_in_autotype, const StringX &sx_group, const StringX &sx_title, const StringX &sx_user, const StringX &sx_pwd, const StringX &sx_notes, const StringX &sx_url, const StringX &sx_email, std::vector<size_t> &vactionverboffsets) { StringX sxtmp(_T("")); StringX sxNotes(sx_notes); TCHAR curChar; StringX sx_autotype(sx_in_autotype); StringX::size_type st_index; std::vector<StringX> vsxnotes_lines; vactionverboffsets.clear(); // If empty, try the database default if (sx_autotype.empty()) { sx_autotype = PWSprefs::GetInstance()-> GetPref(PWSprefs::DefaultAutotypeString); // If still empty, take this default if (sx_autotype.empty()) { // checking for user and password for default settings if (!sx_pwd.empty()){ if (!sx_user.empty()) sx_autotype = DEFAULT_AUTOTYPE; else sx_autotype = _T("\\p\\n"); } } } // No recursive substitution (e.g. \p or \u), although '\t' will be replaced by a tab if (!sx_notes.empty()) { // Use \n and \r to tokenise this line StringX::size_type st_start(0), st_end(0); const StringX sxdelim = _T("\r\n"); StringX sxline; while (st_end != StringX::npos) { st_end = sxNotes.find_first_of(sxdelim, st_start); sxline = (sxNotes.substr(st_start, (st_end == StringX::npos) ? StringX::npos : st_end - st_start)); st_index = 0; for (;;) { st_index = sxline.find(_T("\\t"), st_index); if (st_index == StringX::npos) break; sxline.replace(st_index, 2, _T("\t")); st_index += 1; } vsxnotes_lines.push_back(sxline); // If we just hit a "\r\n", move past it. Or else, it is a "\r" without // a following "\n" or a "\n", so just move past one single char if (st_end != StringX::npos) { st_start = st_end + (sxNotes.compare(st_end, 2, sxdelim) == 0 ? 2 : 1); if (st_start >= sxNotes.length()) break; } } // Now change '\n' to '\r' in the complete notes field st_index = 0; for (;;) { st_index = sxNotes.find(sxdelim, st_index); if (st_index == StringX::npos) break; sxNotes.replace(st_index, 2, _T("\r")); st_index += 1; } st_index = 0; for (;;) { st_index = sxNotes.find(_T("\\t"), st_index); if (st_index == StringX::npos) break; sxNotes.replace(st_index, 2, _T("\t")); st_index += 1; } } const size_t N = sx_autotype.length(); const StringX sxZeroes = _T("000"); int gNumIts; for (size_t n = 0; n < N; n++){ curChar = sx_autotype[n]; if (curChar == TCHAR('\\')) { n++; if (n < N) curChar = sx_autotype[n]; switch (curChar){ case TCHAR('\\'): sxtmp += TCHAR('\\'); break; case TCHAR('n'): case TCHAR('r'): sxtmp += TCHAR('\r'); break; case TCHAR('t'): sxtmp += TCHAR('\t'); break; case TCHAR('s'): sxtmp += TCHAR('\v'); break; case TCHAR('g'): sxtmp += sx_group; break; case TCHAR('i'): sxtmp += sx_title; break; case TCHAR('u'): sxtmp += sx_user; break; case TCHAR('p'): sxtmp += sx_pwd; break; case TCHAR('l'): sxtmp += sx_url; break; case TCHAR('m'): sxtmp += sx_email; break; case TCHAR('o'): { if (n == (N - 1)) { // This was the last character - send the lot! sxtmp += sxNotes; break; } size_t line_number(0); gNumIts = 0; for (n++; n < N && (gNumIts < 3); ++gNumIts, n++) { if (_istdigit(sx_autotype[n])) { line_number *= 10; line_number += (sx_autotype[n] - TCHAR('0')); } else break; // for loop } if (line_number == 0) { // Send the lot sxtmp += sx_notes; } else if (line_number <= vsxnotes_lines.size()) { // User specifies a too big a line number - ignore the lot sxtmp += vsxnotes_lines[line_number - 1]; } // Backup the extra character that delimited the \oNNN string n--; break; // case 'o' } // Action Verbs: // These are the only ones processed specially by the UI as they involve // actions it performs whilst doing the key sending. // Copy them to output string unchanged. case TCHAR('b'): // backspace! case TCHAR('z'): // Use older method vactionverboffsets.push_back(sxtmp.length()); sxtmp += _T("\\"); sxtmp += curChar; break; // case 'b' & 'z' case TCHAR('d'): // Delay case TCHAR('w'): // Wait milli-seconds case TCHAR('W'): // Wait seconds { // Need to ensure that the field length is 3, even if it wasn't vactionverboffsets.push_back(sxtmp.length()); sxtmp += _T("\\"); sxtmp += curChar; gNumIts = 0; size_t i = n; for (i++; i < N && (gNumIts < 3); ++gNumIts, i++) { if (!_istdigit(sx_autotype[i])) break; } // Insert sufficient zeroes to ensure field is 3 characters long sxtmp += sxZeroes.substr(0, 3 - gNumIts); break; // case 'd', 'w' & 'W' } // Also copy explicit control characters to output string unchanged. case TCHAR('a'): // bell (can't hear it during testing!) case TCHAR('v'): // vertical tab case TCHAR('f'): // form feed case TCHAR('e'): // escape case TCHAR('x'): // hex digits (\xNN) // and any others we have forgotten! // '\cC', '\uXXXX', '\OOO', '\<any other charatcer not recognised above>' default: sxtmp += L'\\'; sxtmp += curChar; break; } } else sxtmp += curChar; } vsxnotes_lines.clear(); return sxtmp; }
std::string PWSFilters::GetFilterXMLHeader(const StringX ¤tfile, const PWSfile::HeaderRecord &hdr) { CUTF8Conv utf8conv; const unsigned char *utf8 = NULL; size_t utf8Len = 0; ostringstream oss; stringT cs_tmp; time_t time_now; time(&time_now); const StringX now = PWSUtil::ConvertToDateTimeString(time_now, PWSUtil::TMC_XML); oss << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl; oss << endl; oss << "<filters version=\""; oss << PWS_XML_FILTER_VERSION; oss << "\"" << endl; if (!currentfile.empty()) { cs_tmp = currentfile.c_str(); Replace(cs_tmp, stringT(_T("&")), stringT(_T("&"))); utf8conv.ToUTF8(cs_tmp.c_str(), utf8, utf8Len); oss << "Database=\""; oss << reinterpret_cast<const char *>(utf8); oss << "\"" << endl; utf8conv.ToUTF8(now, utf8, utf8Len); oss << "ExportTimeStamp=\""; oss << reinterpret_cast<const char *>(utf8); oss << "\"" << endl; oss << "FromDatabaseFormat=\""; oss << hdr.m_nCurrentMajorVersion << "." << setw(2) << setfill('0') << hdr.m_nCurrentMinorVersion; oss << "\"" << endl; if (!hdr.m_lastsavedby.empty() || !hdr.m_lastsavedon.empty()) { stringT wls(_T("")); Format(wls, L"%ls on %ls", hdr.m_lastsavedby.c_str(), hdr.m_lastsavedon.c_str()); utf8conv.ToUTF8(wls.c_str(), utf8, utf8Len); oss << "WhoSaved=\""; oss << reinterpret_cast<const char *>(utf8); oss << "\"" << endl; } if (!hdr.m_whatlastsaved.empty()) { utf8conv.ToUTF8(hdr.m_whatlastsaved, utf8, utf8Len); oss << "WhatSaved=\""; oss << reinterpret_cast<const char *>(utf8); oss << "\"" << endl; } if (hdr.m_whenlastsaved != 0) { StringX wls = PWSUtil::ConvertToDateTimeString(hdr.m_whenlastsaved, PWSUtil::TMC_XML); utf8conv.ToUTF8(wls.c_str(), utf8, utf8Len); oss << "WhenLastSaved=\""; oss << reinterpret_cast<const char *>(utf8); oss << "\"" << endl; } CUUID huuid(*hdr.m_file_uuid.GetARep(), true); // true to print canonically oss << "Database_uuid=\"" << huuid << "\"" << endl; } oss << "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" << endl; oss << "xsi:noNamespaceSchemaLocation=\"pwsafe_filter.xsd\">" << endl; oss << endl; return oss.str().c_str(); }
int PWSfileV1V2::WriteRecord(const CItemData &item) { ASSERT(m_fd != NULL); ASSERT(m_curversion != UNKNOWN_VERSION); int status = SUCCESS; switch (m_curversion) { case V17: { // 1.x programs totally ignore the type byte, hence safe to write it // (no need for two WriteCBC functions) // Note that 2.0 format still requires that the header be in this format, // So that old programs reading new databases won't crash, // This introduces a small security issue, in that the header is known text, // making the password susceptible to a dictionary attack on the first block, // rather than the hash^n in the beginning of the file. // we can help minimize this here by writing a random byte in the "type" // byte of the first block. StringX name = item.GetName(); // If name field already exists - use it. This is for the 2.0 header, as well as for files // that were imported and re-exported. if (name.empty()) { // The name in 1.7 consists of title + SPLTCHR + username // DEFUSERNAME was used in previous versions, but 2.0 converts this upon import // so it is not an issue here. // Prepend 2.0 group field to name, if not empty // i.e. group "finances" name "broker" -> "finances.broker" StringX group = item.GetGroup(); StringX title = item.GetTitle(); if (!group.empty()) { group += _T("."); group += title; title = group; } name = title; name += SPLTCHR; name += item.GetUser(); } unsigned char dummy_type; PWSrand::GetInstance()->GetRandomData(&dummy_type, 1); WriteCBC(dummy_type, name); WriteCBC(CItemData::PASSWORD, item.GetPassword()); WriteCBC(CItemData::NOTES, ReMergeNotes(item)); break; } case V20: { { uuid_array_t uuid_array; item.GetUUID(uuid_array); PWSfile::WriteCBC(CItemData::UUID, uuid_array, sizeof(uuid_array_t)); } WriteCBC(CItemData::GROUP, item.GetGroup()); WriteCBC(CItemData::TITLE, item.GetTitle()); WriteCBC(CItemData::USER, item.GetUser()); WriteCBC(CItemData::PASSWORD, item.GetPassword()); WriteCBC(CItemData::NOTES, ReMergeNotes(item)); WriteCBC(CItemData::END, _T("")); break; } default: ASSERT(0); status = UNSUPPORTED_VERSION; } return status; }
//----------------------------------------------------------------- // Internal functions //----------------------------------------------------------------- static UINT ParseRunCommand(const StringX &sxInputString, std::vector<st_RunCommandTokens> &v_rctokens, bool &bDoAutoType, StringX &sxAutoType, stringT &serrmsg, StringX::size_type &st_column) { // tokenize into separate elements std::vector<st_RunCommandTokens>::iterator rc_iter; std::vector<size_t> v_pos; StringX::iterator str_Iter; st_RunCommandTokens st_rctoken; size_t st_num_quotes(0); UINT uierr(0); int var_index(0); const stringT alphanum = _T("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"); if (sxInputString.empty()) { // String is empty! uierr = IDSC_EXS_INPUTEMPTY; goto exit; } for (StringX::size_type l = 0; l < sxInputString.length(); l++) { if (sxInputString[l] == _T('"')) st_num_quotes++; } if (st_num_quotes % 2 != 0) { st_column = sxInputString.find(_T('"')); // Unmatched quotes uierr = IDSC_EXS_UNMATCHEDQUOTES; goto exit; } // tokenize into separate elements using $ as the field separator for (StringX::size_type st_startpos = 0; st_startpos < sxInputString.size(); /* st_startpos advanced in body */) { StringX::size_type st_next = sxInputString.find(_T('$'), st_startpos); if (st_next == StringX::npos) st_next = sxInputString.size(); if (st_next > 0) { st_rctoken.sxname = sxInputString.substr(st_startpos, st_next - st_startpos); st_rctoken.sxindex = _T(""); st_rctoken.index = 0; st_rctoken.is_variable = st_startpos == 0 ? false : true; st_rctoken.has_brackets = false; v_rctokens.push_back(st_rctoken); v_pos.push_back(st_startpos); } st_startpos = st_next + 1; // too complex for for statement } // tokenization for loop // Check if escaped - ending character of previous token == '\' // Make sure this '\' is not escaped itself! for (size_t st_idx = v_rctokens.size() - 1; st_idx > 0 ; st_idx--) { st_RunCommandTokens &st_rctokens = v_rctokens[st_idx - 1]; StringX::size_type name_len = st_rctokens.sxname.length(); if (name_len == 0 || (name_len >= 2 && st_rctokens.sxname.substr(name_len - 2, 2).compare(_T("\\\\")) == 0)) continue; if (st_rctokens.sxname.substr(name_len - 1, 1).compare(_T("\\")) == 0) { st_rctokens.sxname = st_rctokens.sxname.substr(0, name_len - 1) + _T("$") + v_rctokens[st_idx].sxname; v_rctokens.erase(v_rctokens.begin() + st_idx); } } // Check if variable enclosed in curly brackets for (size_t st_idx = 0; st_idx < v_rctokens.size(); st_idx++) { if (v_rctokens[st_idx].sxname.length() == 0) continue; str_Iter = v_rctokens[st_idx].sxname.begin(); // Does it start with a curly bracket? if (*str_Iter == _T('{')) { v_rctokens[st_idx].has_brackets = true; StringX sxvar, sxnonvar, sxindex(_T("")); // Yes - Find end curly bracket StringX::size_type st_end_cb = v_rctokens[st_idx].sxname.find(_T('}')); if (st_end_cb == StringX::npos) { st_column = v_pos[st_idx] + v_rctokens[st_idx].sxname.length(); // Missing end curly bracket uierr = IDSC_EXS_MISSINGCURLYBKT; goto exit; } // Now see if there is an Index here StringX::size_type st_start_sb = v_rctokens[st_idx].sxname.find(_T('[')); if (st_start_sb != StringX::npos) { // Yes - find end square bracket if (st_start_sb > st_end_cb) { // Square backet after end of variable sxvar = v_rctokens[st_idx].sxname.substr(1, st_end_cb - 1); sxnonvar = v_rctokens[st_idx].sxname.substr(st_end_cb + 1); v_rctokens[st_idx].sxname = sxvar; if (sxnonvar.length() > 0) { st_rctoken.sxname = sxnonvar; st_rctoken.sxindex = _T(""); st_rctoken.index = 0; st_rctoken.is_variable = false; st_rctoken.has_brackets = false; v_rctokens.insert(v_rctokens.begin() + st_idx + 1, st_rctoken); v_pos.insert(v_pos.begin() + st_idx + 1, v_pos[st_idx] + st_end_cb); } continue; } StringX::size_type st_end_sb = v_rctokens[st_idx].sxname.find(_T(']'), st_start_sb); if (st_end_sb == StringX::npos) { st_column = v_pos[st_idx] + 1; // Missing end square bracket uierr = IDSC_EXS_MISSINGSQUAREBKT; goto exit; } // The end-curly backet must immediately follow the end-square bracket if (st_end_cb != st_end_sb + 1) { st_column = v_pos[st_idx] + st_end_sb + 1; // Characters between ']' and ')' uierr = IDSC_EXS_INVALIDBRACKETS; goto exit; } sxindex = v_rctokens[st_idx].sxname.substr(st_start_sb + 1, st_end_sb - st_start_sb - 1); v_rctokens[st_idx].sxindex = sxindex; // Now check index uierr = ProcessIndex(sxindex, var_index, st_column); if (uierr > 0) { st_column += v_pos[st_idx]; goto exit; } v_rctokens[st_idx].index = var_index; sxvar = v_rctokens[st_idx].sxname.substr(1, st_start_sb - 1); sxnonvar = v_rctokens[st_idx].sxname.substr(st_end_cb + 1); } else { // No square bracket // Split current token into 'variable' and 'non-variable' parts sxvar = v_rctokens[st_idx].sxname.substr(1, st_end_cb - 1); sxnonvar = v_rctokens[st_idx].sxname.substr(st_end_cb + 1); } v_rctokens[st_idx].sxname = sxvar; if (sxnonvar.length() > 0) { st_rctoken.sxname = sxnonvar; st_rctoken.sxindex = _T(""); st_rctoken.index = 0; st_rctoken.is_variable = false; st_rctoken.has_brackets = false; v_rctokens.insert(v_rctokens.begin() + st_idx + 1, st_rctoken); v_pos.insert(v_pos.begin() + st_idx + 1, v_pos[st_idx] + st_end_cb); } } } // Now use rules of variables to get the real variable for (size_t st_idx = 0; st_idx < v_rctokens.size(); st_idx++) { if (!v_rctokens[st_idx].is_variable) continue; if (v_rctokens[st_idx].sxname.length() == 0) { st_column = v_pos[st_idx]; // Variable name is empty uierr = IDSC_EXS_VARNAMEEMPTY; goto exit; } str_Iter = v_rctokens[st_idx].sxname.begin(); if (!isalpha(*str_Iter)) { st_column = v_pos[st_idx]; // First character of variable is not alphabetic uierr = IDSC_EXS_FIRSTNOTALPHA; goto exit; } StringX::size_type st_next = v_rctokens[st_idx].sxname.find_first_not_of(alphanum.c_str()); if (st_next != StringX::npos) { // Split current token into 'variable' and 'non-variable' parts StringX sxvar = v_rctokens[st_idx].sxname.substr(0, st_next); StringX sxnonvar = v_rctokens[st_idx].sxname.substr(st_next); v_rctokens[st_idx].sxname = sxvar; // Before saving non-variable part - check if it is an Index e.g. var[i] if (sxnonvar.c_str()[0] == _T('[')) { // Find ending square bracket StringX::size_type st_end_sb = sxnonvar.find(_T(']')); if (st_end_sb == StringX::npos) { st_column = v_pos[st_idx] + sxvar.length() + 2; // Missing end square bracket uierr = IDSC_EXS_MISSINGSQUAREBKT; goto exit; } StringX sxindex = sxnonvar.substr(1, st_end_sb - 1); v_rctokens[st_idx].sxindex = sxindex; // Now check index uierr = ProcessIndex(sxindex, var_index, st_column); if (uierr > 0) { st_column += v_pos[st_idx] + sxvar.length(); goto exit; } v_rctokens[st_idx].index = var_index; sxnonvar = sxnonvar.substr(st_end_sb + 1); } else { // Not a square bracket if (v_rctokens[st_idx].has_brackets) { st_column = v_pos[st_idx] + st_next + 1; // Variable must be alphanumeric uierr = IDSC_EXS_VARNAMEINVALID; goto exit; } } if (!sxnonvar.empty()) { st_rctoken.sxname = sxnonvar; st_rctoken.sxindex = _T(""); st_rctoken.index = 0; st_rctoken.is_variable = false; st_rctoken.has_brackets = false; v_rctokens.insert(v_rctokens.begin() + st_idx + 1, st_rctoken); v_pos.insert(v_pos.begin() + st_idx + 1, v_pos[st_idx] + st_next); } } } // Special Autotype processing bDoAutoType = false; sxAutoType = _T(""); for (size_t st_idx = 0; st_idx < v_rctokens.size(); st_idx++) { if (!v_rctokens[st_idx].is_variable) continue; // Is it a autotype variable? if (v_rctokens[st_idx].sxname == _T("a") || v_rctokens[st_idx].sxname == _T("autotype")) { bDoAutoType = true; // Is the next token text and starts with '('? if (st_idx + 1 < v_rctokens.size() && !v_rctokens[st_idx + 1].is_variable && v_rctokens[st_idx + 1].sxname.c_str()[0] == _T('(')) { // Find ending round bracket StringX sx_autotype = v_rctokens[st_idx + 1].sxname; StringX::size_type st_end_rb = sx_autotype.find(_T(')')); if (st_end_rb == StringX::npos) { st_column = v_pos[st_idx + 1] + sx_autotype.length() + 2; // Missing end round bracket uierr = IDSC_EXS_MISSINGROUNDBKT; goto exit; } sxAutoType = sx_autotype.substr(1, st_end_rb - 1); v_rctokens[st_idx + 1].sxname = sx_autotype.substr(st_end_rb + 1); // Check if anything left in this text - none -> delete if (v_rctokens[st_idx + 1].sxname.length() == 0) v_rctokens.erase(v_rctokens.begin() + st_idx + 1); // Now delete Autotype variable v_rctokens.erase(v_rctokens.begin() + st_idx); break; } } } exit: if (uierr != 0) LoadAString(serrmsg, uierr); else serrmsg = _T(""); if (uierr > 0) { v_rctokens.clear(); } v_pos.clear(); return uierr; }
stringT PWScore::Merge(PWScore *pothercore, const bool &subgroup_bset, const stringT &subgroup_name, const int &subgroup_object, const int &subgroup_function, CReport *pRpt, bool *pbCancel) { std::vector<StringX> vs_added; std::vector<StringX> vs_AliasesAdded; std::vector<StringX> vs_ShortcutsAdded; std::vector<StringX> vs_PoliciesAdded; std::map<StringX, StringX> mapRenamedPolicies; const StringX sxMerge_DateTime = PWSUtil::GetTimeStamp(true).c_str(); stringT str_timestring; // To append to title if already in current database str_timestring = sxMerge_DateTime.c_str(); Remove(str_timestring, _T('/')); Remove(str_timestring, _T(':')); /* Purpose: Merge entries from otherCore to m_core Algorithm: Foreach entry in otherCore Find in m_core based on group/title/username if match found { if all other fields match { no merge } else { add to m_core with new title suffixed with -merged-YYYYMMDD-HHMMSS } } else { add to m_core directly } */ int numAdded = 0; int numConflicts = 0; int numAliasesAdded = 0; int numShortcutsAdded = 0; uuid_array_t base_uuid, new_base_uuid; bool bTitleRenamed(false); StringX sx_merged; LoadAString(sx_merged, IDSC_MERGED); MultiCommands *pmulticmds = MultiCommands::Create(this); Command *pcmd1 = UpdateGUICommand::Create(this, UpdateGUICommand::WN_UNDO, UpdateGUICommand::GUI_UNDO_MERGESYNC); pmulticmds->Add(pcmd1); ItemListConstIter otherPos; for (otherPos = pothercore->GetEntryIter(); otherPos != pothercore->GetEntryEndIter(); otherPos++) { // See if user has cancelled if (pbCancel != NULL && *pbCancel) { delete pmulticmds; return _T(""); } CItemData otherItem = pothercore->GetEntry(otherPos); CItemData::EntryType et = otherItem.GetEntryType(); // Need to check that entry keyboard shortcut not already in use! int32 iKBShortcut; otherItem.GetKBShortcut(iKBShortcut); CUUID kbshortcut_uuid = GetKBShortcut(iKBShortcut); bool bKBShortcutInUse = (iKBShortcut != 0&& kbshortcut_uuid != CUUID::NullUUID()); // Handle Aliases and Shortcuts when processing their base entries if (otherItem.IsDependent()) continue; if (subgroup_bset && !otherItem.Matches(subgroup_name, subgroup_object, subgroup_function)) continue; const StringX sx_otherGroup = otherItem.GetGroup(); const StringX sx_otherTitle = otherItem.GetTitle(); const StringX sx_otherUser = otherItem.GetUser(); StringX sxMergedEntry; Format(sxMergedEntry, GROUPTITLEUSERINCHEVRONS, sx_otherGroup.c_str(), sx_otherTitle.c_str(), sx_otherUser.c_str()); ItemListConstIter foundPos = Find(sx_otherGroup, sx_otherTitle, sx_otherUser); otherItem.GetUUID(base_uuid); memcpy(new_base_uuid, base_uuid, sizeof(new_base_uuid)); bTitleRenamed = false; if (foundPos != GetEntryEndIter()) { // Found a match, see if other fields also match CItemData curItem = GetEntry(foundPos); // Can't merge into a protected entry. If we were going to - add instead unsigned char ucprotected; curItem.GetProtected(ucprotected); stringT str_diffs(_T("")), str_temp; int diff_flags = 0; int32 cxtint, oxtint; time_t cxt, oxt; if (otherItem.GetPassword() != curItem.GetPassword()) { diff_flags |= MRG_PASSWORD; LoadAString(str_temp, IDSC_FLDNMPASSWORD); str_diffs += str_temp + _T(", "); } if (otherItem.GetNotes() != curItem.GetNotes()) { diff_flags |= MRG_NOTES; LoadAString(str_temp, IDSC_FLDNMNOTES); str_diffs += str_temp + _T(", "); } if (otherItem.GetURL() != curItem.GetURL()) { diff_flags |= MRG_URL; LoadAString(str_temp, IDSC_FLDNMURL); str_diffs += str_temp + _T(", "); } if (otherItem.GetAutoType() != curItem.GetAutoType()) { diff_flags |= MRG_AUTOTYPE; LoadAString(str_temp, IDSC_FLDNMAUTOTYPE); str_diffs += str_temp + _T(", "); } if (otherItem.GetPWHistory() != curItem.GetPWHistory()) { diff_flags |= MRG_HISTORY; LoadAString(str_temp, IDSC_FLDNMPWHISTORY); str_diffs += str_temp + _T(", "); } // Don't test policy or symbols if either entry is using a named policy // as these are meaningless to compare if (otherItem.GetPolicyName().empty() && curItem.GetPolicyName().empty()) { PWPolicy cur_pwp, oth_pwp; if (curItem.GetPWPolicy().empty()) cur_pwp = PWSprefs::GetInstance()->GetDefaultPolicy(); else curItem.GetPWPolicy(cur_pwp); if (otherItem.GetPWPolicy().empty()) oth_pwp = PWSprefs::GetInstance()->GetDefaultPolicy(true); else otherItem.GetPWPolicy(oth_pwp); if (cur_pwp != oth_pwp) { diff_flags |= MRG_POLICY; LoadAString(str_temp, IDSC_FLDNMPWPOLICY); str_diffs += str_temp + _T(", "); } } otherItem.GetXTime(oxt); curItem.GetXTime(cxt); if (oxt != cxt) { diff_flags |= MRG_XTIME; LoadAString(str_temp, IDSC_FLDNMXTIME); str_diffs += str_temp + _T(", "); } otherItem.GetXTimeInt(oxtint); curItem.GetXTimeInt(cxtint); if (oxtint != cxtint) { diff_flags |= MRG_XTIME_INT; LoadAString(str_temp, IDSC_FLDNMXTIMEINT); str_diffs += str_temp + _T(", "); } if (otherItem.GetRunCommand() != curItem.GetRunCommand()) { diff_flags |= MRG_EXECUTE; LoadAString(str_temp, IDSC_FLDNMRUNCOMMAND); str_diffs += str_temp + _T(", "); } // Must use integer values not compare strings short other_hDCA, cur_hDCA; otherItem.GetDCA(other_hDCA); curItem.GetDCA(cur_hDCA); if (other_hDCA != cur_hDCA) { diff_flags |= MRG_DCA; LoadAString(str_temp, IDSC_FLDNMDCA); str_diffs += str_temp + _T(", "); } if (otherItem.GetEmail() != curItem.GetEmail()) { diff_flags |= MRG_EMAIL; LoadAString(str_temp, IDSC_FLDNMEMAIL); str_diffs += str_temp + _T(", "); } if (otherItem.GetSymbols() != curItem.GetSymbols()) { diff_flags |= MRG_SYMBOLS; LoadAString(str_temp, IDSC_FLDNMSYMBOLS); str_diffs += str_temp + _T(", "); } otherItem.GetShiftDCA(other_hDCA); curItem.GetShiftDCA(cur_hDCA); if (other_hDCA != cur_hDCA) { diff_flags |= MRG_SHIFTDCA; LoadAString(str_temp, IDSC_FLDNMSHIFTDCA); str_diffs += str_temp + _T(", "); } PWPolicy st_to_pp, st_from_pp; StringX sxCurrentPolicyName = curItem.GetPolicyName(); StringX sxOtherPolicyName = otherItem.GetPolicyName(); bool bCurrent(false), bOther(false); if (!sxCurrentPolicyName.empty()) bCurrent = GetPolicyFromName(sxCurrentPolicyName, st_to_pp); if (!sxOtherPolicyName.empty()) bOther = pothercore->GetPolicyFromName(sxOtherPolicyName, st_from_pp); /* There will be differences if only one has a named password policy, or both have policies but the new entry's one is not in our database, or both have the same policy but they are different */ if ((bCurrent && !bOther) || (!bCurrent && bOther) || sxCurrentPolicyName != sxOtherPolicyName || (bCurrent && bOther && st_to_pp != st_from_pp)) { diff_flags |= MRG_POLICYNAME; LoadAString(str_temp, IDSC_FLDNMPWPOLICYNAME); str_diffs += str_temp + _T(", "); } if (diff_flags != 0) { // have a match on group/title/user, but not on other fields // add an entry suffixed with -merged-YYYYMMDD-HHMMSS StringX sx_newTitle; Format(sx_newTitle, L"%ls-%ls-%ls", sx_otherTitle.c_str(), sx_merged.c_str(), str_timestring.c_str()); // note it as an issue for the user stringT strWarnMsg; Format(strWarnMsg, IDSC_MERGECONFLICTS, sx_otherGroup.c_str(), sx_otherTitle.c_str(), sx_otherUser.c_str(), sx_otherGroup.c_str(), sx_newTitle.c_str(), sx_otherUser.c_str(), str_diffs.c_str()); // log it if (pRpt != NULL) pRpt->WriteLine(strWarnMsg.c_str()); // Check no conflict of unique uuid if (Find(base_uuid) != GetEntryEndIter()) { otherItem.CreateUUID(); otherItem.GetUUID(new_base_uuid); } // Special processing for password policies (default & named) bool bUpdated; // not needed for Merge Command *pPolicyCmd = ProcessPolicyName(pothercore, otherItem, mapRenamedPolicies, vs_PoliciesAdded, sxOtherPolicyName, bUpdated, sxMerge_DateTime, IDSC_MERGEPOLICY); if (pPolicyCmd != NULL) pmulticmds->Add(pPolicyCmd); // About to add entry - check keyboard shortcut if (bKBShortcutInUse) { // Remove it otherItem.SetKBShortcut(0); // Tell user via the report ItemListIter iter = Find(kbshortcut_uuid); if (iter != m_pwlist.end()) { StringX sxTemp, sxExistingEntry; Format(sxExistingEntry, GROUPTITLEUSERINCHEVRONS, iter->second.GetGroup().c_str(), iter->second.GetTitle().c_str(), iter->second.GetUser().c_str()); Format(sxTemp, IDSC_KBSHORTCUT_REMOVED, sx_merged.c_str(), sxMergedEntry.c_str(), sxExistingEntry.c_str(), sx_merged.c_str()); pRpt->WriteLine(sxTemp.c_str()); } } otherItem.SetTitle(sx_newTitle); otherItem.SetStatus(CItemData::ES_ADDED); Command *pcmd = AddEntryCommand::Create(this, otherItem); pcmd->SetNoGUINotify(); pmulticmds->Add(pcmd); // Update the Wizard page UpdateWizard(sxMergedEntry.c_str()); numConflicts++; } } else { // Didn't find any match...add it directly // Check no conflict of unique uuid if (Find(base_uuid) != GetEntryEndIter()) { otherItem.CreateUUID(); otherItem.GetUUID(new_base_uuid); } // Special processing for password policies (default & named) bool bUpdated; // Not needed for Merge StringX sxOtherPolicyName = otherItem.GetPolicyName(); Command *pPolicyCmd = ProcessPolicyName(pothercore, otherItem, mapRenamedPolicies, vs_PoliciesAdded, sxOtherPolicyName, bUpdated, sxMerge_DateTime, IDSC_MERGEPOLICY); if (pPolicyCmd != NULL) pmulticmds->Add(pPolicyCmd); // About to add entry - check keyboard shortcut if (bKBShortcutInUse) { // Remove it otherItem.SetKBShortcut(0); // Tell user via the report ItemListIter iter = Find(kbshortcut_uuid); if (iter != m_pwlist.end()) { StringX sxTemp, sxExistingEntry; Format(sxExistingEntry, GROUPTITLEUSERINCHEVRONS, iter->second.GetGroup().c_str(), iter->second.GetTitle().c_str(), iter->second.GetUser().c_str()); Format(sxTemp, IDSC_KBSHORTCUT_REMOVED, sx_merged.c_str(), sxMergedEntry.c_str(), sxExistingEntry.c_str(), sx_merged.c_str()); pRpt->WriteLine(sxTemp.c_str()); } } otherItem.SetStatus(CItemData::ES_ADDED); Command *pcmd = AddEntryCommand::Create(this, otherItem); pcmd->SetNoGUINotify(); pmulticmds->Add(pcmd); StringX sx_added; Format(sx_added, GROUPTITLEUSERINCHEVRONS, sx_otherGroup.c_str(), sx_otherTitle.c_str(), sx_otherUser.c_str()); vs_added.push_back(sx_added); // Update the Wizard page UpdateWizard(sx_added.c_str()); numAdded++; } if (et == CItemData::ET_ALIASBASE) numAliasesAdded += MergeDependents(pothercore, pmulticmds, base_uuid, new_base_uuid, bTitleRenamed, str_timestring, CItemData::ET_ALIAS, vs_AliasesAdded); if (et == CItemData::ET_SHORTCUTBASE) numShortcutsAdded += MergeDependents(pothercore, pmulticmds, base_uuid, new_base_uuid, bTitleRenamed, str_timestring, CItemData::ET_SHORTCUT, vs_ShortcutsAdded); } // iteration over other core's entries stringT str_results; if (numAdded > 0 && pRpt != NULL) { std::sort(vs_added.begin(), vs_added.end(), MergeSyncGTUCompare); stringT str_singular_plural_type, str_singular_plural_verb; LoadAString(str_singular_plural_type, numAdded == 1 ? IDSC_ENTRY : IDSC_ENTRIES); LoadAString(str_singular_plural_verb, numAdded == 1 ? IDSC_WAS : IDSC_WERE); Format(str_results, IDSC_MERGEADDED, str_singular_plural_type.c_str(), str_singular_plural_verb.c_str()); pRpt->WriteLine(str_results.c_str()); for (size_t i = 0; i < vs_added.size(); i++) { Format(str_results, L"\t%ls", vs_added[i].c_str()); pRpt->WriteLine(str_results.c_str()); } } if (numAliasesAdded > 0 && pRpt != NULL) { std::sort(vs_AliasesAdded.begin(), vs_AliasesAdded.end(), MergeSyncGTUCompare); stringT str_singular_plural_type, str_singular_plural_verb; LoadAString(str_singular_plural_type, numAliasesAdded == 1 ? IDSC_ENTRY : IDSC_ENTRIES); LoadAString(str_singular_plural_verb, numAliasesAdded == 1 ? IDSC_WAS : IDSC_WERE); Format(str_results, IDSC_MERGEADDED, str_singular_plural_type.c_str(), str_singular_plural_verb.c_str()); pRpt->WriteLine(str_results.c_str()); for (size_t i = 0; i < vs_AliasesAdded.size(); i++) { Format(str_results, _T("\t%ls"), vs_AliasesAdded[i].c_str()); pRpt->WriteLine(str_results.c_str()); } } if (numShortcutsAdded > 0 && pRpt != NULL) { std::sort(vs_ShortcutsAdded.begin(), vs_ShortcutsAdded.end(), MergeSyncGTUCompare); stringT str_singular_plural_type, str_singular_plural_verb; LoadAString(str_singular_plural_type, numShortcutsAdded == 1 ? IDSC_ENTRY : IDSC_ENTRIES); LoadAString(str_singular_plural_verb, numShortcutsAdded == 1 ? IDSC_WAS : IDSC_WERE); Format(str_results, IDSC_MERGEADDED, str_singular_plural_type.c_str(), str_singular_plural_verb.c_str()); pRpt->WriteLine(str_results.c_str()); for (size_t i = 0; i < vs_ShortcutsAdded.size(); i++) { Format(str_results, L"\t%ls", vs_ShortcutsAdded[i].c_str()); pRpt->WriteLine(str_results.c_str()); } } // See if user has cancelled if (pbCancel != NULL && *pbCancel) { delete pmulticmds; return _T(""); } Command *pcmd2 = UpdateGUICommand::Create(this, UpdateGUICommand::WN_REDO, UpdateGUICommand::GUI_REDO_MERGESYNC); pmulticmds->Add(pcmd2); Execute(pmulticmds); // See if user has cancelled too late - reset flag so incorrect information not given to user if (pbCancel != NULL && *pbCancel) { *pbCancel = false; } // Tell the user we're done & provide short merge report stringT str_entries, str_conflicts, str_aliases, str_shortcuts; int totalAdded = numAdded + numConflicts + numAliasesAdded + numShortcutsAdded; LoadAString(str_entries, totalAdded == 1 ? IDSC_ENTRY : IDSC_ENTRIES); LoadAString(str_conflicts, numConflicts == 1 ? IDSC_CONFLICT : IDSC_CONFLICTS); LoadAString(str_aliases, numAliasesAdded == 1 ? IDSC_ALIAS : IDSC_ALIASES); LoadAString(str_shortcuts, numShortcutsAdded == 1 ? IDSC_SHORTCUT : IDSC_SHORTCUTS); Format(str_results, IDSC_MERGECOMPLETED, totalAdded, str_entries.c_str(), numConflicts, str_conflicts.c_str(), numAliasesAdded, str_aliases.c_str(), numShortcutsAdded, str_shortcuts.c_str()); pRpt->WriteLine(str_results.c_str()); return str_results; }
bool PWSRun::runcmd(const StringX &run_command, const bool &bAutotype) const { // Get first parameter either enclosed by quotes or delimited by a space StringX full_string(run_command), first_part(_T("")), the_rest(_T("")); StringX env_var, sx_temp(_T("")); StringX::size_type end_delim; bool bfound(true); TrimLeft(full_string, _T(" ")); if (full_string.c_str()[0] == _T('"')) { end_delim = full_string.find(_T('"'), 1); first_part = full_string.substr(1, end_delim - 1); the_rest = full_string.substr(end_delim + 1); } else { end_delim = full_string.find(_T(' ')); if (end_delim != StringX::npos) { first_part = full_string.substr(0, end_delim); the_rest = full_string.substr(end_delim + 1); } else first_part = full_string; } // tokenize into separate elements using % as the field separator. // If this corresponds to a set envrionmental variable - replace it // and rebuild the command for (StringX::size_type st_startpos = 0; st_startpos < first_part.size(); /* st_startpos advanced in body */) { StringX::size_type st_next = first_part.find(_T('%'), st_startpos); if (st_next == StringX::npos) { sx_temp += first_part.substr(st_startpos); break; } if (st_next > 0) { env_var = first_part.substr(st_startpos, st_next - st_startpos); size_t mblen = pws_os::wcstombs(NULL, 0, env_var.c_str(), size_t(-1), false); unsigned char * mbtemp = new unsigned char[mblen + 1]; // Finally get result size_t tmplen = pws_os::wcstombs((char *)mbtemp, mblen, env_var.c_str(), size_t(-1), false); if (tmplen != mblen) { return false; } mbtemp[mblen - 1] = '\0'; StringX envar = (pws_os::getenv((char *)mbtemp, false)).c_str(); if (!envar.empty()) { sx_temp += envar; } else { sx_temp += StringX(_T("%")) + env_var + StringX(_T("%")); } } st_startpos = st_next + 1; // too complex for for statement } // tokenization for loop // Replace string by rebuilt string first_part = sx_temp; first_part = getruncmd(first_part, bfound); bool rc; if (bfound) rc = issuecmd(first_part, the_rest, bAutotype); else rc = issuecmd(full_string, _T(""), bAutotype); return rc; }
UINT CAddEdit_Basic::ExternalEditorThread(LPVOID me) // static method! { CAddEdit_Basic *self = (CAddEdit_Basic *)me; wchar_t szExecName[MAX_PATH + 1]; wchar_t lpPathBuffer[4096]; DWORD dwBufSize(4096); StringX sxEditor = PWSprefs::GetInstance()->GetPref(PWSprefs::AltNotesEditor); if (sxEditor.empty()) { // Find out the users default editor for "txt" files DWORD dwSize(MAX_PATH); HRESULT stat = ::AssocQueryString(0, ASSOCSTR_EXECUTABLE, L".txt", L"Open", szExecName, &dwSize); if (int(stat) != S_OK) { #ifdef _DEBUG CGeneralMsgBox gmb; gmb.AfxMessageBox(L"oops"); #endif // Send error return (WPARAM != 0) self->PostMessage(PWS_MSG_EXTERNAL_EDITOR_ENDED, 16, 0); return 16; } sxEditor = szExecName; } DWORD dwResult = ExpandEnvironmentStrings(sxEditor.c_str(), szExecName, MAX_PATH + 1); if (dwResult == 0 || dwResult > (MAX_PATH + 1)) { CGeneralMsgBox gmb; CString cs_msg, cs_title(MAKEINTRESOURCE(IDS_EDITEXTERNALLY)); cs_msg.Format(IDS_CANT_FIND_EXT_EDITOR, sxEditor.c_str()); gmb.MessageBox(cs_msg, cs_title, MB_OK | MB_ICONEXCLAMATION); // Send error return (WPARAM != 0) self->PostMessage(PWS_MSG_EXTERNAL_EDITOR_ENDED, 16, 0); return 0; } sxEditor = szExecName; if (!pws_os::FileExists(sxEditor.c_str())) { CGeneralMsgBox gmb; CString cs_msg, cs_title(MAKEINTRESOURCE(IDS_EDITEXTERNALLY)); cs_msg.Format(IDS_CANT_FIND_EXT_EDITOR, sxEditor.c_str()); gmb.MessageBox(cs_msg, cs_title, MB_OK | MB_ICONEXCLAMATION); // Send error return (WPARAM != 0) self->PostMessage(PWS_MSG_EXTERNAL_EDITOR_ENDED, 16, 0); return 0; } // Now we know the editor exists - go copy the data for it! // Get the temp path GetTempPath(dwBufSize, // length of the buffer lpPathBuffer); // buffer for path // Create a temporary file. GetTempFileName(lpPathBuffer, // directory for temp files L"NTE", // temp file name prefix 0, // create unique name self->m_szTempName); // buffer for name FILE *fd; if ((fd = pws_os::FOpen(self->m_szTempName, _T("w+b"))) == NULL) { return 0; } // Write BOM const unsigned int iBOM = 0xFEFF; putwc(iBOM, fd); // Write out text fwrite(reinterpret_cast<const void *>((LPCWSTR)self->M_realnotes()), sizeof(BYTE), self->M_realnotes().GetLength() * sizeof(TCHAR), fd); // Close file before invoking editor fclose(fd); // Create an Edit process STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(si); ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); DWORD dwCreationFlags(0); dwCreationFlags = CREATE_UNICODE_ENVIRONMENT; CString cs_CommandLine; // Make the command line = "<program>" "file" cs_CommandLine.Format(L"\"%s\" \"%s\"", sxEditor.c_str(), self->m_szTempName); int ilen = cs_CommandLine.GetLength(); LPWSTR pszCommandLine = cs_CommandLine.GetBuffer(ilen); if (!CreateProcess(NULL, pszCommandLine, NULL, NULL, FALSE, dwCreationFlags, NULL, lpPathBuffer, &si, &pi)) { pws_os::IssueError(L"External Editor CreateProcess", false); CGeneralMsgBox gmb; gmb.AfxMessageBox(IDS_CANT_FIND_EXT_EDITOR, MB_OK | MB_ICONEXCLAMATION); // Delete temporary file _wremove(self->m_szTempName); SecureZeroMemory(self->m_szTempName, sizeof(self->m_szTempName)); // Send error return (WPARAM != 0) self->PostMessage(PWS_MSG_EXTERNAL_EDITOR_ENDED, 16, 0); return 0; } pws_os::Trace(L"%d\n", sizeof(self->m_szTempName)); WaitForInputIdle(pi.hProcess, INFINITE); // Wait until child process exits. WaitForSingleObject(pi.hProcess, INFINITE); // Close process and thread handles. CloseHandle(pi.hProcess); CloseHandle(pi.hThread); cs_CommandLine.ReleaseBuffer(); self->PostMessage(PWS_MSG_EXTERNAL_EDITOR_ENDED, 0, 0); return 0; }
void PasswordSafeSearch::FindMatches(const StringX& searchText, bool fCaseSensitive, SearchPointer& searchPtr, const CItemData::FieldBits& bsFields, bool fUseSubgroups, const wxString& subgroupText, CItemData::FieldType subgroupObject, PWSMatch::MatchRule subgroupFunction, bool subgroupFunctionCaseSensitive, Iter begin, Iter end, Accessor afn) { if (searchText.empty()) return; searchPtr.Clear(); typedef StringX (CItemData::*ItemDataFuncT)() const; struct { CItemData::FieldType type; ItemDataFuncT func; } ItemDataFields[] = { {CItemData::GROUP, &CItemData::GetGroup}, {CItemData::TITLE, &CItemData::GetTitle}, {CItemData::USER, &CItemData::GetUser}, {CItemData::PASSWORD, &CItemData::GetPassword}, // {CItemData::NOTES, &CItemData::GetNotes}, {CItemData::URL, &CItemData::GetURL}, {CItemData::EMAIL, &CItemData::GetEmail}, {CItemData::RUNCMD, &CItemData::GetRunCommand}, {CItemData::AUTOTYPE, &CItemData::GetAutoType}, {CItemData::XTIME_INT, &CItemData::GetXTimeInt}, }; for ( Iter itr = begin; itr != end; ++itr) { const int fn = (subgroupFunctionCaseSensitive? -subgroupFunction: subgroupFunction); if (fUseSubgroups && !afn(itr).Matches(stringT(subgroupText.c_str()), subgroupObject, fn)) continue; bool found = false; for (size_t idx = 0; idx < NumberOf(ItemDataFields) && !found; ++idx) { if (bsFields.test(ItemDataFields[idx].type)) { const StringX str = (afn(itr).*ItemDataFields[idx].func)(); found = fCaseSensitive? str.find(searchText) != StringX::npos: FindNoCase(searchText, str); } } if (!found && bsFields.test(CItemData::NOTES)) { StringX str = afn(itr).GetNotes(); found = fCaseSensitive? str.find(searchText) != StringX::npos: FindNoCase(searchText, str); } if (!found && bsFields.test(CItemData::PWHIST)) { size_t pwh_max, err_num; PWHistList pwhistlist; CreatePWHistoryList(afn(itr).GetPWHistory(), pwh_max, err_num, pwhistlist, PWSUtil::TMC_XML); for (PWHistList::iterator iter = pwhistlist.begin(); iter != pwhistlist.end(); iter++) { PWHistEntry pwshe = *iter; found = fCaseSensitive? pwshe.password.find(searchText) != StringX::npos: FindNoCase(searchText, pwshe.password ); if (found) break; // break out of for loop } pwhistlist.clear(); } if (found) { uuid_array_t uuid; afn(itr).GetUUID(uuid); searchPtr.Add(pws_os::CUUID(uuid)); } } }
//----------------------------------------------------------------- // Externally visible functions //----------------------------------------------------------------- StringX PWSAuxParse::GetExpandedString(const StringX &sxRun_Command, const StringX &sxCurrentDB, const CItemData *pci, bool &bAutoType, StringX &sxAutotype, stringT &serrmsg, StringX::size_type &st_column, bool &bURLSpecial) { std::vector<st_RunCommandTokens> v_rctokens; std::vector<st_RunCommandTokens>::iterator rc_iter; StringX sxretval(_T("")), sxurl; stringT spath, sdrive, sdir, sfname, sextn; stringT sdbdir; bURLSpecial = false; UINT uierr = ParseRunCommand(sxRun_Command, v_rctokens, bAutoType, sxAutotype, serrmsg, st_column); // if called with NULL ci, then we just parse to validate if (uierr > 0 || pci == NULL || sxCurrentDB.empty()) { v_rctokens.clear(); return sxretval; } // derive current db's directory and basename: spath = sxCurrentDB.c_str(); pws_os::splitpath(spath, sdrive, sdir, sfname, sextn); sdbdir = pws_os::makepath(sdrive, sdir, _T(""), _T("")); for (rc_iter = v_rctokens.begin(); rc_iter < v_rctokens.end(); rc_iter++) { st_RunCommandTokens &st_rctoken = *rc_iter; if (!st_rctoken.is_variable) { sxretval += st_rctoken.sxname.c_str(); continue; } if (st_rctoken.sxname == _T("appdir")) { sxretval += pws_os::getexecdir().c_str(); } else if (st_rctoken.sxname == _T("dbdir")) { sxretval += sdbdir.c_str(); } else if (st_rctoken.sxname == _T("fulldb")) { sxretval += spath.c_str(); } else if (st_rctoken.sxname == _T("dbname")) { sxretval += sfname.c_str(); } else if (st_rctoken.sxname == _T("dbextn")) { sxretval += sextn.c_str(); } else if (st_rctoken.sxname == _T("g") || st_rctoken.sxname == _T("group")) { sxretval += pci->GetGroup(); } else if (st_rctoken.sxname == _T("G") || st_rctoken.sxname == _T("GROUP")) { StringX sxg = pci->GetGroup(); StringX::size_type st_index; st_index = sxg.rfind(_T(".")); if (st_index != StringX::npos) { sxg = sxg.substr(st_index + 1); } sxretval += sxg; } else if (st_rctoken.sxname == _T("t") || st_rctoken.sxname == _T("title")) { sxretval += pci->GetTitle(); } else if (st_rctoken.sxname == _T("u") || st_rctoken.sxname == _T("user")) { sxretval += pci->GetUser(); } else if (st_rctoken.sxname == _T("p") || st_rctoken.sxname == _T("password")) { sxretval += pci->GetPassword(); } else if (st_rctoken.sxname == _T("e") || st_rctoken.sxname == _T("email")) { sxretval += pci->GetEmail(); } else if (st_rctoken.sxname == _T("a") || st_rctoken.sxname == _T("autotype")) { // Do nothing - autotype variable handled elsewhere } else if (st_rctoken.sxname == _T("url")) { sxurl = pci->GetURL(); if (sxurl.length() > 0) { // Remove 'Browse to' specifics StringX::size_type ipos; ipos = sxurl.find(_T("[alt]")); if (ipos != StringX::npos) { bURLSpecial = true; sxurl.erase(ipos, 5); } ipos = sxurl.find(_T("[ssh]")); if (ipos != StringX::npos) { bURLSpecial = true; sxurl.erase(ipos, 5); } ipos = sxurl.find(_T("{alt}")); if (ipos != StringX::npos) { bURLSpecial = true; sxurl.erase(ipos, 5); } ipos = sxurl.find(_T("[autotype]")); if (ipos != StringX::npos) { sxurl.erase(ipos, 10); } ipos = sxurl.find(_T("[xa]")); if (ipos != StringX::npos) { sxurl.erase(ipos, 4); } sxretval += sxurl; } } else if (st_rctoken.sxname == _T("n") || st_rctoken.sxname == _T("notes")) { StringX sx_notes = pci->GetNotes(); if (st_rctoken.index == 0) { sxretval += sx_notes; } else { std::vector<StringX> vsxnotes_lines; ParseNotes(sx_notes, vsxnotes_lines); // If line there - use it; otherwise ignore it if (st_rctoken.index > 0 && st_rctoken.index <= static_cast<int>(vsxnotes_lines.size())) { sxretval += vsxnotes_lines[st_rctoken.index - 1]; } else if (st_rctoken.index < 0 && abs(st_rctoken.index) <= static_cast<int>(vsxnotes_lines.size())) { sxretval += vsxnotes_lines[vsxnotes_lines.size() + st_rctoken.index]; } } } else { // Unknown variable name - rebuild it sxretval += _T("$"); if (st_rctoken.has_brackets) sxretval += _T("("); sxretval += st_rctoken.sxname.c_str(); if (st_rctoken.index != 0) sxretval += st_rctoken.sxindex.c_str(); if (st_rctoken.has_brackets) sxretval += _T(")"); } } v_rctokens.clear(); return sxretval; }