DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Header

Mercurial (409f3966645a)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "CredentialManagerSecret.h"

#include <wincred.h>
#include <windows.h>

#include "mozilla/Logging.h"
#include "mozilla/SyncRunnable.h"

// This is the implementation of CredentialManagerSecretSecret, an instantiation
// of OSKeyStore for Windows. It uses the system credential manager, hence the
// name.

using namespace mozilla;

LazyLogModule gCredentialManagerSecretLog("credentialmanagersecret");
struct ScopedDelete
{
  void operator()(CREDENTIALA* cred) { CredFree(cred); }
};

template<class T>
struct ScopedMaybeDelete
{
  void operator()(T* ptr)
  {
    if (ptr) {
      ScopedDelete del;
      del(ptr);
    }
  }
};
typedef std::unique_ptr<CREDENTIALA, ScopedMaybeDelete<CREDENTIALA>> ScopedCREDENTIALA;

CredentialManagerSecret::CredentialManagerSecret() {}

CredentialManagerSecret::~CredentialManagerSecret() {}

nsresult
CredentialManagerSecret::Lock()
{
  // The Windows credential manager can't be locked.
  return NS_OK;
}

nsresult
CredentialManagerSecret::Unlock()
{
  // The Windows credential manager is always unlocked when the user is logged
  // in.
  return NS_OK;
}

nsresult
CredentialManagerSecret::StoreSecret(const nsACString& aSecret,
                                     const nsACString& aLabel)
{
  if (aSecret.Length() > CRED_MAX_CREDENTIAL_BLOB_SIZE) {
    // Windows doesn't allow blobs larger than CRED_MAX_CREDENTIAL_BLOB_SIZE
    // bytes.
    MOZ_LOG(gCredentialManagerSecretLog,
            LogLevel::Debug,
            ("StoreSecret secret must not be larger than 512 bytes (got %d)",
             aSecret.Length()));
    return NS_ERROR_FAILURE;
  }
  CREDENTIALA cred = { 0 };
  cred.Type = CRED_TYPE_GENERIC;
  const nsCString& label = PromiseFlatCString(aLabel);
  cred.TargetName = const_cast<LPSTR>(label.get());
  cred.CredentialBlobSize = aSecret.Length();
  const nsCString& secret = PromiseFlatCString(aSecret);
  cred.CredentialBlob = (LPBYTE)secret.get();
  cred.Persist = CRED_PERSIST_LOCAL_MACHINE;
  cred.UserName = "";

  // https://docs.microsoft.com/en-us/windows/desktop/api/wincred/nf-wincred-credwritea
  BOOL ok = CredWriteA(&cred, 0);
  if (!ok) {
    MOZ_LOG(gCredentialManagerSecretLog,
            LogLevel::Debug,
            ("CredWriteW failed %d", GetLastError()));
    return NS_ERROR_FAILURE;
  }
  return NS_OK;
}

nsresult
CredentialManagerSecret::DeleteSecret(const nsACString& aLabel)
{
  // https://docs.microsoft.com/en-us/windows/desktop/api/wincred/nf-wincred-creddeletea
  const nsCString& label = PromiseFlatCString(aLabel);
  BOOL ok = CredDeleteA(label.get(), CRED_TYPE_GENERIC, 0);
  int error = GetLastError();
  if (!ok && error != ERROR_NOT_FOUND) {
    MOZ_LOG(gCredentialManagerSecretLog,
            LogLevel::Debug,
            ("CredDeleteA failed %d", error));
    return NS_ERROR_FAILURE;
  }
  return NS_OK;
}

nsresult
CredentialManagerSecret::RetrieveSecret(const nsACString& aLabel,
                                        /* out */ nsACString& aSecret)
{
  aSecret.Truncate();
  PCREDENTIALA pcred_raw = nullptr;
  const nsCString& label = PromiseFlatCString(aLabel);
  // https://docs.microsoft.com/en-us/windows/desktop/api/wincred/nf-wincred-credreada
  BOOL ok = CredReadA(label.get(), CRED_TYPE_GENERIC, 0, &pcred_raw);
  ScopedCREDENTIALA pcred(pcred_raw);
  if (!ok) {
    MOZ_LOG(gCredentialManagerSecretLog,
            LogLevel::Debug,
            ("CredReadA failed %d", GetLastError()));
    return NS_ERROR_FAILURE;
  }
  MOZ_ASSERT(pcred);
  aSecret.Assign(reinterpret_cast<const char*>(pcred->CredentialBlob),
                 pcred->CredentialBlobSize);
  return NS_OK;
}