/* password-cache.c - Password cache support.
   Copyright (C) 2015 g10 Code GmbH
   This file is part of PINENTRY.
   PINENTRY is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
   PINENTRY 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
   General Public License for more details.
   You should have received a copy of the GNU General Public License
   along with this program; if not, see .
 */
#ifdef HAVE_CONFIG_H
# include 
#endif
#include 
#include 
#include 
#ifdef HAVE_LIBSECRET
# include 
#endif
#include "password-cache.h"
#include "memory.h"
#ifdef HAVE_LIBSECRET
static const SecretSchema *
gpg_schema (void)
{
    static const SecretSchema the_schema = {
        "org.gnupg.Passphrase", SECRET_SCHEMA_NONE,
        {
	  { "stored-by", SECRET_SCHEMA_ATTRIBUTE_STRING },
	  { "keygrip", SECRET_SCHEMA_ATTRIBUTE_STRING },
	  { "NULL", 0 },
	}
    };
    return &the_schema;
}
static char *
keygrip_to_label (const char *keygrip)
{
  char const prefix[] = "GnuPG: ";
  char *label;
  label = malloc (sizeof (prefix) + strlen (keygrip));
  if (label)
    {
      memcpy (label, prefix, sizeof (prefix) - 1);
      strcpy (&label[sizeof (prefix) - 1], keygrip);
    }
  return label;
}
#endif
void
password_cache_save (const char *keygrip, const char *password)
{
#ifdef HAVE_LIBSECRET
  char *label;
  GError *error = NULL;
  if (! *keygrip)
    return;
  label = keygrip_to_label (keygrip);
  if (! label)
    return;
  if (! secret_password_store_sync (gpg_schema (),
				    SECRET_COLLECTION_DEFAULT,
				    label, password, NULL, &error,
				    "stored-by", "GnuPG Pinentry",
				    "keygrip", keygrip, NULL))
    {
      printf("Failed to cache password for key %s with secret service: %s\n",
	     keygrip, error->message);
      g_error_free (error);
    }
  free (label);
#else
  return;
#endif
}
char *
password_cache_lookup (const char *keygrip)
{
#ifdef HAVE_LIBSECRET
  GError *error = NULL;
  char *password;
  char *password2;
  if (! *keygrip)
    return NULL;
  password = secret_password_lookup_nonpageable_sync
    (gpg_schema (), NULL, &error,
     "keygrip", keygrip, NULL);
  if (error != NULL)
    {
      printf("Failed to lookup password for key %s with secret service: %s\n",
	     keygrip, error->message);
      g_error_free (error);
      return NULL;
    }
  if (! password)
    /* The password for this key is not cached.  Just return NULL.  */
    return NULL;
  /* The password needs to be returned in secmem allocated memory.  */
  password2 = secmem_malloc (strlen (password) + 1);
  if (password2)
    strcpy(password2, password);
  else
    printf("secmem_malloc failed: can't copy password!\n");
  secret_password_free (password);
  return password2;
#else
  return NULL;
#endif
}
/* Try and remove the cached password for key grip.  Returns -1 on
   error, 0 if the key is not found and 1 if the password was
   removed.  */
int
password_cache_clear (const char *keygrip)
{
#ifdef HAVE_LIBSECRET
  GError *error = NULL;
  int removed = secret_password_clear_sync (gpg_schema (), NULL, &error,
					    "keygrip", keygrip, NULL);
  if (error != NULL)
    {
      printf("Failed to clear password for key %s with secret service: %s\n",
	     keygrip, error->message);
      g_debug("%s", error->message);
      g_error_free (error);
      return -1;
    }
  if (removed)
    return 1;
  return 0;
#else
  return -1;
#endif
}