Exemplo n.º 1
0
void print_conflicting_item(const CItemData &item, const CItemData &otherItem,
                            const CItemData::FieldBits &fields, item_diff_func_t diff_fn)
{
  for( auto ft: diff_fields ) {
    switch(ft) {
      case CItem::GROUP:
      case CItem::TITLE:
      case CItem::USER:
        break;
      default:
        if (fields.test(ft)) {
            switch (ft) {
                case CItemData::POLICY:
                {
                    // Policy comparison compares default policies for the safes if the
                    // item's policy is empty. We just consider them to be same if empty.
                    if ( have_empty_policies(item, otherItem) ) {
                        continue;
                    }
                    break;
                }
                default:
                    break;
            }
            diff_fn(item, otherItem, fields, ft);
        }
        break;
    }
  }
}
static void CompareField(CItemData::FieldType field,
                         const CItemData::FieldBits &bsTest,
                         const CItemData &first, const CItemData &second,
                         CItemData::FieldBits &bsConflicts, bool bTreatWhiteSpaceasEmpty = false)
{
  if (bsTest.test(field)) {
    bool flip;
    if (bTreatWhiteSpaceasEmpty) {
      StringX a(first.GetFieldValue(field)), b(second.GetFieldValue(field));
      EmptyIfOnlyWhiteSpace(a); EmptyIfOnlyWhiteSpace(b);
      flip = a != b;
    } else {
      flip = first.GetFieldValue(field) != second.GetFieldValue(field);
    }
    if (flip)
      bsConflicts.flip(field);
  }
}
Exemplo n.º 3
0
void CAdvancedDlg::Set(CItemData::FieldBits bsFields)
{
    LVFINDINFO findinfo;
    CString cs_text;
    int iItem;
    DWORD_PTR dw_data;

    SecureZeroMemory(&findinfo, sizeof(LVFINDINFO));

    findinfo.flags = LVFI_PARAM;
    // Note: Mandatory fields have a ItemData value + 0x800 rather than 0x1000
    // and so will not be found and so not moved anywhere.
    for (int i = 0; i < CItem::LAST_DATA; i++) {
        // Don't move or allow non-allowed fields
        if (!m_bsAllowedFields.test(i))
            continue;

        if (bsFields.test(i)) {
            // Selected - find entry in list of available fields and move it
            findinfo.lParam = i | NORMALFIELD;
            iItem = m_pLC_List->FindItem(&findinfo);
            if (iItem == -1)
                continue;

            cs_text = m_pLC_List->GetItemText(iItem, 0);
            dw_data = m_pLC_List->GetItemData(iItem);
            m_pLC_List->DeleteItem(iItem);
            iItem = m_pLC_Selected->InsertItem(0, cs_text);
            m_pLC_Selected->SetItemData(iItem, dw_data);
        } else {
            // Not selected - find entry in list of selected fields and move it
            findinfo.lParam = i | NORMALFIELD;
            iItem = m_pLC_Selected->FindItem(&findinfo);
            if (iItem == -1)
                continue;

            cs_text = m_pLC_Selected->GetItemText(iItem, 0);
            dw_data = m_pLC_Selected->GetItemData(iItem);
            m_pLC_Selected->DeleteItem(iItem);
            iItem = m_pLC_List->InsertItem(0, cs_text);
            m_pLC_List->SetItemData(iItem, dw_data);
        }
    }
}
Exemplo n.º 4
0
/////////////////////////////////////////////////////////////////
// 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'-';
}
Exemplo n.º 5
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));
    }
  }
}
void PWScore::Synchronize(PWScore *pothercore,
                          const CItemData::FieldBits &bsFields, const bool &subgroup_bset,
                          const stringT &subgroup_name,
                          const int &subgroup_object, const int &subgroup_function,
                          int &numUpdated, CReport *pRpt, bool *pbCancel)
{
  /*
  Purpose:
    Synchronize entries from otherCore to m_core

  Algorithm:
    Foreach entry in otherCore
      Find in m_core
        if find a match
          update requested fields
  */

  std::vector<StringX> vs_updated;
  numUpdated = 0;

  MultiCommands *pmulticmds = MultiCommands::Create(this);
  Command *pcmd1 = UpdateGUICommand::Create(this, UpdateGUICommand::WN_UNDO,
                                            UpdateGUICommand::GUI_UNDO_MERGESYNC);
  pmulticmds->Add(pcmd1);

  // Make sure we don't add it multiple times
  std::map<StringX, StringX> mapRenamedPolicies;
  std::vector<StringX> vs_PoliciesAdded;
  const StringX sxSync_DateTime = PWSUtil::GetTimeStamp(true).c_str();

  ItemListConstIter otherPos;
  for (otherPos = pothercore->GetEntryIter();
       otherPos != pothercore->GetEntryEndIter();
       otherPos++) {
    // See if user has cancelled
    if (pbCancel != NULL && *pbCancel) {
      delete pmulticmds;
      return;
    }

    CItemData otherItem = pothercore->GetEntry(otherPos);
    CItemData::EntryType et = otherItem.GetEntryType();

    // Do not process Aliases and Shortcuts
    if (et == CItemData::ET_ALIAS || et == CItemData::ET_SHORTCUT)
      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 sx_mergedentry;
    Format(sx_mergedentry, GROUPTITLEUSERINCHEVRONS,
                sx_otherGroup.c_str(), sx_otherTitle.c_str(), sx_otherUser.c_str());

    ItemListConstIter foundPos = Find(sx_otherGroup, sx_otherTitle, sx_otherUser);

    if (foundPos != GetEntryEndIter()) {
      // found a match
      CItemData curItem = GetEntry(foundPos);

      // Don't update if entry is protected
      if (curItem.IsProtected())
        continue;

      CItemData updItem(curItem);
      updItem.SetDisplayInfo(NULL);

      if (curItem.GetUUID() != otherItem.GetUUID()) {
        pws_os::Trace(_T("Synchronize: Mis-match UUIDs for [%ls:%ls:%ls]\n"),
             sx_otherGroup.c_str(), sx_otherTitle.c_str(), sx_otherUser.c_str());
      }

      bool bUpdated(false);
      // Do not try and change GROUPTITLE = 0x00 (use GROUP & TITLE separately) or UUID = 0x01
      for (size_t i = 2; i < bsFields.size(); i++) {
        if (bsFields.test(i)) {
          StringX sxValue = otherItem.GetFieldValue(static_cast<CItemData::FieldType>(i));

          // Special processing for password policies (default & named)
          if (static_cast<CItemData::FieldType>(i) == CItemData::POLICYNAME) {
            Command *pPolicyCmd = ProcessPolicyName(pothercore, updItem,
                                   mapRenamedPolicies, vs_PoliciesAdded,
                                   sxValue, bUpdated,
                                   sxSync_DateTime, IDSC_SYNCPOLICY);
            if (pPolicyCmd != NULL)
              pmulticmds->Add(pPolicyCmd);
          } else {
            if (sxValue != updItem.GetFieldValue(static_cast<CItemData::FieldType>(i))) {
              bUpdated = true;
              updItem.SetFieldValue(static_cast<CItemData::FieldType>(i), sxValue);
            }
          }
        }
      }

      if (!bUpdated)
        continue;

      GUISetupDisplayInfo(updItem);
      updItem.SetStatus(CItemData::ES_MODIFIED);

      StringX sx_updated;
      Format(sx_updated, GROUPTITLEUSERINCHEVRONS,
                sx_otherGroup.c_str(), sx_otherTitle.c_str(), sx_otherUser.c_str());
      vs_updated.push_back(sx_updated);

      Command *pcmd = EditEntryCommand::Create(this, curItem, updItem);
      pcmd->SetNoGUINotify();
      pmulticmds->Add(pcmd);

      // Update the Wizard page
      UpdateWizard(sx_updated.c_str());

      numUpdated++;
    }  // Found match via [g:t:u]
  } // iteration over other core's entries

  stringT str_results;
  if (numUpdated > 0 && pRpt != NULL) {
    std::sort(vs_updated.begin(), vs_updated.end(), MergeSyncGTUCompare);
    stringT str_singular_plural_type, str_singular_plural_verb;
    LoadAString(str_singular_plural_type, numUpdated == 1 ? IDSC_ENTRY : IDSC_ENTRIES);
    LoadAString(str_singular_plural_verb, numUpdated == 1 ? IDSC_WAS : IDSC_WERE);
    Format(str_results, IDSC_SYNCHUPDATED, 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_updated.size(); i++) {
      Format(str_results, L"\t%ls", vs_updated[i].c_str());
      pRpt->WriteLine(str_results.c_str());
    }
  }

  // See if user has cancelled
  if (pbCancel != NULL && *pbCancel) {
    delete pmulticmds;
    return;
  }

  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;
    return;
  }

  // tell the user we're done & provide short Synchronize report
  stringT str_entries;
  LoadAString(str_entries, numUpdated == 1 ? IDSC_ENTRY : IDSC_ENTRIES);
  Format(str_results, IDSC_SYNCHCOMPLETED, numUpdated, str_entries.c_str());
  pRpt->WriteLine(str_results.c_str());
}
void PWScore::Compare(PWScore *pothercore,
                      const CItemData::FieldBits &bsFields, const bool &subgroup_bset,
                      const bool &bTreatWhiteSpaceasEmpty,  const stringT &subgroup_name,
                      const int &subgroup_object, const int &subgroup_function,
                      CompareData &list_OnlyInCurrent, CompareData &list_OnlyInComp,
                      CompareData &list_Conflicts, CompareData &list_Identical,
                      bool *pbCancel)
{
  /*
  Purpose:
    Compare entries from comparison database (compCore) with current database (m_core)

  Algorithm:
    Foreach entry in current database {
      Find in comparison database - subject to subgroup checking
      if found {
        Compare
        if match
          OK
       else
          There are conflicts; note them & increment numConflicts
      } else {
        save & increment numOnlyInCurrent
      }
    }

    Foreach entry in comparison database {
      Find in current database - subject to subgroup checking
      if not found
        save & increment numOnlyInComp
    }
  */

  CItemData::FieldBits bsConflicts(0);
  st_CompareData st_data;
  int numOnlyInCurrent(0), numOnlyInComp(0), numConflicts(0), numIdentical(0);

  ItemListIter currentPos;
  for (currentPos = GetEntryIter();
       currentPos != GetEntryEndIter();
       currentPos++) {
    // See if user has cancelled
    if (pbCancel != NULL && *pbCancel) {
      return;
    }

    st_data.Empty();
    const CItemData &currentItem = GetEntry(currentPos);

    if (!subgroup_bset ||
        currentItem.Matches(std::wstring(subgroup_name), subgroup_object,
                            subgroup_function)) {
      st_data.group = currentItem.GetGroup();
      st_data.title = currentItem.GetTitle();
      st_data.user = currentItem.GetUser();

      StringX sx_original;
      Format(sx_original, GROUPTITLEUSERINCHEVRONS,
                st_data.group.c_str(), st_data.title.c_str(), st_data.user.c_str());

      // Update the Wizard page
      UpdateWizard(sx_original.c_str());

      ItemListIter foundPos = pothercore->Find(st_data.group,
                                               st_data.title, st_data.user);
      if (foundPos != pothercore->GetEntryEndIter()) {
        // found a match, see if all other fields also match
        // Difference flags:
        /*
         First byte (values in square brackets taken from ItemData.h)
         1... ....  NAME       [0x00] - n/a - depreciated
         .1.. ....  UUID       [0x01] - n/a - unique
         ..1. ....  GROUP      [0x02] - not checked - must be identical
         ...1 ....  TITLE      [0x03] - not checked - must be identical
         .... 1...  USER       [0x04] - not checked - must be identical
         .... .1..  NOTES      [0x05]
         .... ..1.  PASSWORD   [0x06]
         .... ...1  CTIME      [0x07] - not checked by default

         Second byte
         1... ....  PMTIME     [0x08] - not checked by default
         .1.. ....  ATIME      [0x09] - not checked by default
         ..1. ....  XTIME      [0x0a] - not checked by default
         ...1 ....  RESERVED   [0x0b] - not used
         .... 1...  RMTIME     [0x0c] - not checked by default
         .... .1..  URL        [0x0d]
         .... ..1.  AUTOTYPE   [0x0e]
         .... ...1  PWHIST     [0x0f]

         Third byte
         1... ....  POLICY     [0x10] - not checked by default
         .1.. ....  XTIME_INT  [0x11] - not checked by default
         ..1. ....  RUNCMD     [0x12]
         ...1 ....  DCA        [0x13]
         .... 1...  EMAIL      [0x14]
         .... .1..  PROTECTED  [0x15]
         .... ..1.  SYMBOLS    [0x16]
         .... ...1  SHIFTDCA   [0x17]

         Fourth byte
         1... ....  POLICYNAME [0x18] - not checked by default
         .1.. ....  KBSHORTCUT [0x19] - not checked by default


        */
        bsConflicts.reset();
        StringX sxCurrentPassword, sxComparisonPassword;

        const CItemData &compItem = pothercore->GetEntry(foundPos);

        if (currentItem.IsDependent()) {
          CItemData *pci_base = GetBaseEntry(&currentItem);
          sxCurrentPassword = pci_base->GetPassword();
        } else
          sxCurrentPassword = currentItem.GetPassword();

        if (compItem.IsDependent()) {
          CItemData *pci_base = pothercore->GetBaseEntry(&compItem);
          sxComparisonPassword = pci_base->GetPassword();
        } else
          sxComparisonPassword = compItem.GetPassword();

        if (bsFields.test(CItemData::PASSWORD) &&
            sxCurrentPassword != sxComparisonPassword)
          bsConflicts.flip(CItemData::PASSWORD);

        CompareField(CItemData::NOTES, bsFields, currentItem, compItem,
                     bsConflicts, bTreatWhiteSpaceasEmpty);
        CompareField(CItemData::CTIME, bsFields, currentItem, compItem, bsConflicts);
        CompareField(CItemData::PMTIME, bsFields, currentItem, compItem, bsConflicts);
        CompareField(CItemData::ATIME, bsFields, currentItem, compItem, bsConflicts);
        CompareField(CItemData::XTIME, bsFields, currentItem, compItem, bsConflicts);
        CompareField(CItemData::RMTIME, bsFields, currentItem, compItem, bsConflicts);

        if (bsFields.test(CItemData::XTIME_INT)) {
          int32 current_xint, comp_xint;
          currentItem.GetXTimeInt(current_xint);
          compItem.GetXTimeInt(comp_xint);
          if (current_xint != comp_xint)
            bsConflicts.flip(CItemData::XTIME_INT);
        }

        CompareField(CItemData::URL, bsFields, currentItem, compItem,
                     bsConflicts, bTreatWhiteSpaceasEmpty);
        CompareField(CItemData::AUTOTYPE, bsFields, currentItem, compItem,
                     bsConflicts, bTreatWhiteSpaceasEmpty);
        CompareField(CItemData::PWHIST, bsFields, currentItem, compItem, bsConflicts);
        CompareField(CItemData::POLICYNAME, bsFields, currentItem, compItem, bsConflicts);

        // Don't test policy or symbols if either entry is using a named policy
        // as these are meaningless to compare
        if (currentItem.GetPolicyName().empty() && compItem.GetPolicyName().empty()) {
          if (bsFields.test(CItemData::POLICY)) {
            PWPolicy cur_pwp, cmp_pwp;
            if (currentItem.GetPWPolicy().empty())
              cur_pwp = PWSprefs::GetInstance()->GetDefaultPolicy();
            else
              currentItem.GetPWPolicy(cur_pwp);
            if (compItem.GetPWPolicy().empty())
              cmp_pwp = PWSprefs::GetInstance()->GetDefaultPolicy(true);
            else
              compItem.GetPWPolicy(cmp_pwp);
            if (cur_pwp != cmp_pwp)
              bsConflicts.flip(CItemData::POLICY);
          }
          CompareField(CItemData::SYMBOLS, bsFields, currentItem, compItem, bsConflicts);
        }

        CompareField(CItemData::RUNCMD, bsFields, currentItem, compItem, bsConflicts);
        CompareField(CItemData::DCA, bsFields, currentItem, compItem, bsConflicts);
        CompareField(CItemData::SHIFTDCA, bsFields, currentItem, compItem, bsConflicts);
        CompareField(CItemData::EMAIL, bsFields, currentItem, compItem, bsConflicts);
        CompareField(CItemData::PROTECTED, bsFields, currentItem, compItem, bsConflicts);

        if (bsFields.test(CItemData::KBSHORTCUT) &&
            currentItem.GetKBShortcut() != compItem.GetKBShortcut())
          bsConflicts.flip(CItemData::KBSHORTCUT);

        st_data.uuid0 = currentPos->first;
        st_data.uuid1 = foundPos->first;
        st_data.bsDiffs = bsConflicts;
        st_data.indatabase = BOTH;
        st_data.unknflds0 = currentItem.NumberUnknownFields() > 0;
        st_data.unknflds1 = compItem.NumberUnknownFields() > 0;
        st_data.bIsProtected0 = currentItem.IsProtected();

        if (bsConflicts.any()) {
          numConflicts++;
          st_data.id = numConflicts;
          list_Conflicts.push_back(st_data);
        } else {
          numIdentical++;
          st_data.id = numIdentical;
          list_Identical.push_back(st_data);
        }
      } else {
        // didn't find any match...
        numOnlyInCurrent++;
        st_data.uuid0 = currentPos->first;
        st_data.uuid1 = CUUID::NullUUID();
        st_data.bsDiffs.reset();
        st_data.indatabase = CURRENT;
        st_data.unknflds0 = currentItem.NumberUnknownFields() > 0;
        st_data.unknflds1 = false;
        st_data.id = numOnlyInCurrent;
        list_OnlyInCurrent.push_back(st_data);
      }
    }
  } // iteration over our entries

  ItemListIter compPos;
  for (compPos = pothercore->GetEntryIter();
       compPos != pothercore->GetEntryEndIter();
       compPos++) {
    // See if user has cancelled
    if (pbCancel != NULL && *pbCancel) {
      return;
    }

    st_data.Empty();
    CItemData compItem = pothercore->GetEntry(compPos);

    if (!subgroup_bset ||
        compItem.Matches(std::wstring(subgroup_name), subgroup_object,
                         subgroup_function)) {
      st_data.group = compItem.GetGroup();
      st_data.title = compItem.GetTitle();
      st_data.user = compItem.GetUser();

      StringX sx_compare;
      Format(sx_compare, GROUPTITLEUSERINCHEVRONS,
                st_data.group.c_str(), st_data.title.c_str(), st_data.user.c_str());

      // Update the Wizard page
      UpdateWizard(sx_compare.c_str());

      if (Find(st_data.group, st_data.title, st_data.user) ==
          GetEntryEndIter()) {
        // Didn't find any match...
        numOnlyInComp++;
        st_data.uuid0 = CUUID::NullUUID();
        st_data.uuid1 = compPos->first;
        st_data.bsDiffs.reset();
        st_data.indatabase = COMPARE;
        st_data.unknflds0 = false;
        st_data.unknflds1 = compItem.NumberUnknownFields() > 0;
        st_data.id = numOnlyInComp;
        list_OnlyInComp.push_back(st_data);
      }
    }
  } // iteration over other core's element

  // See if user has cancelled too late - reset flag so incorrect information not given to user
  if (pbCancel != NULL && *pbCancel) {
    *pbCancel = false;
  }
}