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 (d09c6b07d48e)

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
/* -*- 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 = const_cast<char*>("");  // -Wwritable-strings

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