mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-03 12:11:33 +01:00
Add server option with-ephemeral-keys.
Extend SCD LEARN command.
This commit is contained in:
parent
370f841a01
commit
a3b63ac1dc
@ -1,3 +1,12 @@
|
|||||||
|
2009-03-18 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
|
* command.c (cmd_learn): Add option --keypairinfo.
|
||||||
|
* app.c (app_write_learn_status): Add arg FLAGS.
|
||||||
|
* app-common.h (struct app_ctx_s): Add arg FLAGS to LEARN_STATUS.
|
||||||
|
Change all implementors.
|
||||||
|
* app-p15.c (do_learn_status): Take care of flag bit 0.
|
||||||
|
* app-nks.c (do_learn_status, do_learn_status_core): Ditto.
|
||||||
|
|
||||||
2009-03-10 Werner Koch <wk@g10code.com>
|
2009-03-10 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
* app-openpgp.c (send_key_attr): New.
|
* app-openpgp.c (send_key_attr): New.
|
||||||
|
@ -67,7 +67,7 @@ struct app_ctx_s {
|
|||||||
struct app_local_s *app_local; /* Local to the application. */
|
struct app_local_s *app_local; /* Local to the application. */
|
||||||
struct {
|
struct {
|
||||||
void (*deinit) (app_t app);
|
void (*deinit) (app_t app);
|
||||||
gpg_error_t (*learn_status) (app_t app, ctrl_t ctrl);
|
gpg_error_t (*learn_status) (app_t app, ctrl_t ctrl, unsigned int flags);
|
||||||
gpg_error_t (*readcert) (app_t app, const char *certid,
|
gpg_error_t (*readcert) (app_t app, const char *certid,
|
||||||
unsigned char **cert, size_t *certlen);
|
unsigned char **cert, size_t *certlen);
|
||||||
gpg_error_t (*readkey) (app_t app, const char *certid,
|
gpg_error_t (*readkey) (app_t app, const char *certid,
|
||||||
@ -145,7 +145,8 @@ char *get_supported_applications (void);
|
|||||||
void release_application (app_t app);
|
void release_application (app_t app);
|
||||||
gpg_error_t app_munge_serialno (app_t app);
|
gpg_error_t app_munge_serialno (app_t app);
|
||||||
gpg_error_t app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp);
|
gpg_error_t app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp);
|
||||||
gpg_error_t app_write_learn_status (app_t app, ctrl_t ctrl);
|
gpg_error_t app_write_learn_status (app_t app, ctrl_t ctrl,
|
||||||
|
unsigned int flags);
|
||||||
gpg_error_t app_readcert (app_t app, const char *certid,
|
gpg_error_t app_readcert (app_t app, const char *certid,
|
||||||
unsigned char **cert, size_t *certlen);
|
unsigned char **cert, size_t *certlen);
|
||||||
gpg_error_t app_readkey (app_t app, const char *keyid,
|
gpg_error_t app_readkey (app_t app, const char *keyid,
|
||||||
|
@ -86,7 +86,7 @@
|
|||||||
|
|
||||||
|
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
do_learn_status (app_t app, ctrl_t ctrl)
|
do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
char ct_buf[100], id_buf[100];
|
char ct_buf[100], id_buf[100];
|
||||||
@ -97,6 +97,8 @@ do_learn_status (app_t app, ctrl_t ctrl)
|
|||||||
ksba_cert_t cert;
|
ksba_cert_t cert;
|
||||||
int fid;
|
int fid;
|
||||||
|
|
||||||
|
(void)flags;
|
||||||
|
|
||||||
/* Return the certificate of the card holder. */
|
/* Return the certificate of the card holder. */
|
||||||
fid = 0xC000;
|
fid = 0xC000;
|
||||||
len = app_help_read_length_of_cert (app->slot, fid, &certoff);
|
len = app_help_read_length_of_cert (app->slot, fid, &certoff);
|
||||||
|
@ -147,7 +147,7 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
|
|||||||
|
|
||||||
|
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
do_learn_status (app_t app, ctrl_t ctrl)
|
do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
|
||||||
{
|
{
|
||||||
static const char *names[] = {
|
static const char *names[] = {
|
||||||
"X-KBLZ",
|
"X-KBLZ",
|
||||||
@ -167,6 +167,8 @@ do_learn_status (app_t app, ctrl_t ctrl)
|
|||||||
gpg_error_t err = 0;
|
gpg_error_t err = 0;
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
|
(void)flags;
|
||||||
|
|
||||||
for (idx=0; names[idx] && !err; idx++)
|
for (idx=0; names[idx] && !err; idx++)
|
||||||
err = do_getattr (app, ctrl, names[idx]);
|
err = do_getattr (app, ctrl, names[idx]);
|
||||||
return err;
|
return err;
|
||||||
|
@ -309,7 +309,7 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
|
|||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
do_learn_status_core (app_t app, ctrl_t ctrl, int is_sigg)
|
do_learn_status_core (app_t app, ctrl_t ctrl, unsigned int flags, int is_sigg)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
char ct_buf[100], id_buf[100];
|
char ct_buf[100], id_buf[100];
|
||||||
@ -332,7 +332,7 @@ do_learn_status_core (app_t app, ctrl_t ctrl, int is_sigg)
|
|||||||
if (!!filelist[i].is_sigg != !!is_sigg)
|
if (!!filelist[i].is_sigg != !!is_sigg)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (filelist[i].certtype)
|
if (filelist[i].certtype && !(flags &1))
|
||||||
{
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
@ -377,7 +377,7 @@ do_learn_status_core (app_t app, ctrl_t ctrl, int is_sigg)
|
|||||||
|
|
||||||
|
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
do_learn_status (app_t app, ctrl_t ctrl)
|
do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
|
|
||||||
@ -385,13 +385,13 @@ do_learn_status (app_t app, ctrl_t ctrl)
|
|||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
do_learn_status_core (app, ctrl, 0);
|
do_learn_status_core (app, ctrl, flags, 0);
|
||||||
|
|
||||||
err = switch_application (app, 1);
|
err = switch_application (app, 1);
|
||||||
if (err)
|
if (err)
|
||||||
return 0; /* Silently ignore if we can't switch to SigG. */
|
return 0; /* Silently ignore if we can't switch to SigG. */
|
||||||
|
|
||||||
do_learn_status_core (app, ctrl, 1);
|
do_learn_status_core (app, ctrl, flags, 1);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1295,8 +1295,10 @@ send_keypair_info (app_t app, ctrl_t ctrl, int keyno)
|
|||||||
|
|
||||||
/* Handle the LEARN command for OpenPGP. */
|
/* Handle the LEARN command for OpenPGP. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
do_learn_status (app_t app, ctrl_t ctrl)
|
do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
|
||||||
{
|
{
|
||||||
|
(void)flags;
|
||||||
|
|
||||||
do_getattr (app, ctrl, "EXTCAP");
|
do_getattr (app, ctrl, "EXTCAP");
|
||||||
do_getattr (app, ctrl, "DISP-NAME");
|
do_getattr (app, ctrl, "DISP-NAME");
|
||||||
do_getattr (app, ctrl, "DISP-LANG");
|
do_getattr (app, ctrl, "DISP-LANG");
|
||||||
|
@ -2492,17 +2492,23 @@ send_keypairinfo (app_t app, ctrl_t ctrl, prkdf_object_t keyinfo)
|
|||||||
|
|
||||||
/* This is the handler for the LEARN command. */
|
/* This is the handler for the LEARN command. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
do_learn_status (app_t app, ctrl_t ctrl)
|
do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
|
|
||||||
err = send_certinfo (app, ctrl, "100", app->app_local->certificate_info);
|
if ((flags & 1))
|
||||||
if (!err)
|
err = 0;
|
||||||
err = send_certinfo (app, ctrl, "101",
|
else
|
||||||
app->app_local->trusted_certificate_info);
|
{
|
||||||
if (!err)
|
err = send_certinfo (app, ctrl, "100", app->app_local->certificate_info);
|
||||||
err = send_certinfo (app, ctrl, "102",
|
if (!err)
|
||||||
app->app_local->useful_certificate_info);
|
err = send_certinfo (app, ctrl, "101",
|
||||||
|
app->app_local->trusted_certificate_info);
|
||||||
|
if (!err)
|
||||||
|
err = send_certinfo (app, ctrl, "102",
|
||||||
|
app->app_local->useful_certificate_info);
|
||||||
|
}
|
||||||
|
|
||||||
if (!err)
|
if (!err)
|
||||||
err = send_keypairinfo (app, ctrl, app->app_local->private_key_info);
|
err = send_keypairinfo (app, ctrl, app->app_local->private_key_info);
|
||||||
|
|
||||||
|
@ -542,7 +542,7 @@ app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp)
|
|||||||
/* Write out the application specifig status lines for the LEARN
|
/* Write out the application specifig status lines for the LEARN
|
||||||
command. */
|
command. */
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
app_write_learn_status (app_t app, ctrl_t ctrl)
|
app_write_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
|
|
||||||
@ -553,13 +553,14 @@ app_write_learn_status (app_t app, ctrl_t ctrl)
|
|||||||
if (!app->fnc.learn_status)
|
if (!app->fnc.learn_status)
|
||||||
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
|
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
|
||||||
|
|
||||||
if (app->apptype)
|
/* We do not send APPTYPE if only keypairinfo is requested. */
|
||||||
|
if (app->apptype && !(flags & 1))
|
||||||
send_status_info (ctrl, "APPTYPE",
|
send_status_info (ctrl, "APPTYPE",
|
||||||
app->apptype, strlen (app->apptype), NULL, 0);
|
app->apptype, strlen (app->apptype), NULL, 0);
|
||||||
err = lock_reader (app->slot);
|
err = lock_reader (app->slot);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
err = app->fnc.learn_status (app, ctrl);
|
err = app->fnc.learn_status (app, ctrl, flags);
|
||||||
unlock_reader (app->slot);
|
unlock_reader (app->slot);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
104
scd/command.c
104
scd/command.c
@ -1,6 +1,6 @@
|
|||||||
/* command.c - SCdaemon command handler
|
/* command.c - SCdaemon command handler
|
||||||
* Copyright (C) 2001, 2002, 2003, 2004, 2005,
|
* Copyright (C) 2001, 2002, 2003, 2004, 2005,
|
||||||
* 2007, 2008 Free Software Foundation, Inc.
|
* 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
@ -184,7 +184,7 @@ update_card_removed (int slot, int value)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Check whether the option NAME appears in LINE */
|
/* Check whether the option NAME appears in LINE. Returns 1 or 0. */
|
||||||
static int
|
static int
|
||||||
has_option (const char *line, const char *name)
|
has_option (const char *line, const char *name)
|
||||||
{
|
{
|
||||||
@ -528,7 +528,7 @@ cmd_serialno (assuan_context_t ctx, char *line)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* LEARN [--force]
|
/* LEARN [--force] [--keypairinfo]
|
||||||
|
|
||||||
Learn all useful information of the currently inserted card. When
|
Learn all useful information of the currently inserted card. When
|
||||||
used without the force options, the command might do an INQUIRE
|
used without the force options, the command might do an INQUIRE
|
||||||
@ -538,8 +538,13 @@ cmd_serialno (assuan_context_t ctx, char *line)
|
|||||||
|
|
||||||
The client should just send an "END" if the processing should go on
|
The client should just send an "END" if the processing should go on
|
||||||
or a "CANCEL" to force the function to terminate with a Cancel
|
or a "CANCEL" to force the function to terminate with a Cancel
|
||||||
error message. The response of this command is a list of status
|
error message.
|
||||||
lines formatted as this:
|
|
||||||
|
With the option --keypairinfo only KEYPARIINFO lstatus lines are
|
||||||
|
returned.
|
||||||
|
|
||||||
|
The response of this command is a list of status lines formatted as
|
||||||
|
this:
|
||||||
|
|
||||||
S APPTYPE <apptype>
|
S APPTYPE <apptype>
|
||||||
|
|
||||||
@ -589,13 +594,14 @@ cmd_serialno (assuan_context_t ctx, char *line)
|
|||||||
|
|
||||||
The URL to be used for locating the entire public key.
|
The URL to be used for locating the entire public key.
|
||||||
|
|
||||||
Note, that this function may be even be used on a locked card.
|
Note, that this function may even be used on a locked card.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
cmd_learn (assuan_context_t ctx, char *line)
|
cmd_learn (assuan_context_t ctx, char *line)
|
||||||
{
|
{
|
||||||
ctrl_t ctrl = assuan_get_pointer (ctx);
|
ctrl_t ctrl = assuan_get_pointer (ctx);
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
int only_keypairinfo = has_option (line, "--keypairinfo");
|
||||||
|
|
||||||
if ((rc = open_card (ctrl, NULL)))
|
if ((rc = open_card (ctrl, NULL)))
|
||||||
return rc;
|
return rc;
|
||||||
@ -604,51 +610,53 @@ cmd_learn (assuan_context_t ctx, char *line)
|
|||||||
the card using a serial number and inquiring the client with
|
the card using a serial number and inquiring the client with
|
||||||
that. The client may choose to cancel the operation if he already
|
that. The client may choose to cancel the operation if he already
|
||||||
knows about this card */
|
knows about this card */
|
||||||
{
|
if (!only_keypairinfo)
|
||||||
char *serial_and_stamp;
|
{
|
||||||
char *serial;
|
char *serial_and_stamp;
|
||||||
time_t stamp;
|
char *serial;
|
||||||
|
time_t stamp;
|
||||||
rc = app_get_serial_and_stamp (ctrl->app_ctx, &serial, &stamp);
|
|
||||||
if (rc)
|
rc = app_get_serial_and_stamp (ctrl->app_ctx, &serial, &stamp);
|
||||||
return rc;
|
if (rc)
|
||||||
rc = estream_asprintf (&serial_and_stamp, "%s %lu", serial, (unsigned long)stamp);
|
return rc;
|
||||||
xfree (serial);
|
rc = estream_asprintf (&serial_and_stamp, "%s %lu",
|
||||||
if (rc < 0)
|
serial, (unsigned long)stamp);
|
||||||
return out_of_core ();
|
xfree (serial);
|
||||||
rc = 0;
|
if (rc < 0)
|
||||||
assuan_write_status (ctx, "SERIALNO", serial_and_stamp);
|
return out_of_core ();
|
||||||
|
rc = 0;
|
||||||
if (!has_option (line, "--force"))
|
assuan_write_status (ctx, "SERIALNO", serial_and_stamp);
|
||||||
{
|
|
||||||
char *command;
|
if (!has_option (line, "--force"))
|
||||||
|
{
|
||||||
rc = estream_asprintf (&command, "KNOWNCARDP %s", serial_and_stamp);
|
char *command;
|
||||||
if (rc < 0)
|
|
||||||
{
|
rc = estream_asprintf (&command, "KNOWNCARDP %s", serial_and_stamp);
|
||||||
xfree (serial_and_stamp);
|
if (rc < 0)
|
||||||
return out_of_core ();
|
{
|
||||||
}
|
xfree (serial_and_stamp);
|
||||||
rc = 0;
|
return out_of_core ();
|
||||||
rc = assuan_inquire (ctx, command, NULL, NULL, 0);
|
}
|
||||||
xfree (command);
|
rc = 0;
|
||||||
if (rc)
|
rc = assuan_inquire (ctx, command, NULL, NULL, 0);
|
||||||
{
|
xfree (command);
|
||||||
if (gpg_err_code (rc) != GPG_ERR_ASS_CANCELED)
|
if (rc)
|
||||||
log_error ("inquire KNOWNCARDP failed: %s\n",
|
{
|
||||||
gpg_strerror (rc));
|
if (gpg_err_code (rc) != GPG_ERR_ASS_CANCELED)
|
||||||
xfree (serial_and_stamp);
|
log_error ("inquire KNOWNCARDP failed: %s\n",
|
||||||
return rc;
|
gpg_strerror (rc));
|
||||||
}
|
xfree (serial_and_stamp);
|
||||||
/* not canceled, so we have to proceeed */
|
return rc;
|
||||||
}
|
}
|
||||||
xfree (serial_and_stamp);
|
/* Not canceled, so we have to proceeed. */
|
||||||
}
|
}
|
||||||
|
xfree (serial_and_stamp);
|
||||||
|
}
|
||||||
|
|
||||||
/* Let the application print out its collection of useful status
|
/* Let the application print out its collection of useful status
|
||||||
information. */
|
information. */
|
||||||
if (!rc)
|
if (!rc)
|
||||||
rc = app_write_learn_status (ctrl->app_ctx, ctrl);
|
rc = app_write_learn_status (ctrl->app_ctx, ctrl, only_keypairinfo);
|
||||||
|
|
||||||
TEST_CARD_REMOVAL (ctrl, rc);
|
TEST_CARD_REMOVAL (ctrl, rc);
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -1,3 +1,11 @@
|
|||||||
|
2009-03-18 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
|
* gpgsm.h (struct opt): Move field WITH_EPHEMERAL_KEYS to struct
|
||||||
|
server_control_s.
|
||||||
|
* gpgsm.c (main): Change accordingly.
|
||||||
|
* keylist.c (list_internal_keys): Ditto.
|
||||||
|
* server.c (option_handler): Add "with-ephemeral-keys".
|
||||||
|
|
||||||
2009-03-12 Werner Koch <wk@g10code.com>
|
2009-03-12 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
* certdump.c (gpgsm_dump_time): Remove.
|
* certdump.c (gpgsm_dump_time): Remove.
|
||||||
|
@ -1259,7 +1259,7 @@ main ( int argc, char **argv)
|
|||||||
case oWithKeyData: opt.with_key_data=1; /* fall thru */
|
case oWithKeyData: opt.with_key_data=1; /* fall thru */
|
||||||
case oWithColons: ctrl.with_colons = 1; break;
|
case oWithColons: ctrl.with_colons = 1; break;
|
||||||
case oWithValidation: ctrl.with_validation=1; break;
|
case oWithValidation: ctrl.with_validation=1; break;
|
||||||
case oWithEphemeralKeys: opt.with_ephemeral_keys=1; break;
|
case oWithEphemeralKeys: ctrl.with_ephemeral_keys=1; break;
|
||||||
|
|
||||||
case oSkipVerify: opt.skip_verify=1; break;
|
case oSkipVerify: opt.skip_verify=1; break;
|
||||||
|
|
||||||
|
@ -82,9 +82,6 @@ struct
|
|||||||
int with_md5_fingerprint; /* Also print an MD5 fingerprint for
|
int with_md5_fingerprint; /* Also print an MD5 fingerprint for
|
||||||
standard key listings. */
|
standard key listings. */
|
||||||
|
|
||||||
int with_ephemeral_keys; /* Include ephemeral flagged keys in the
|
|
||||||
keylisting. */
|
|
||||||
|
|
||||||
int armor; /* force base64 armoring (see also ctrl.with_base64) */
|
int armor; /* force base64 armoring (see also ctrl.with_base64) */
|
||||||
int no_armor; /* don't try to figure out whether data is base64 armored*/
|
int no_armor; /* don't try to figure out whether data is base64 armored*/
|
||||||
|
|
||||||
@ -176,6 +173,8 @@ struct server_control_s
|
|||||||
int with_colons; /* Use column delimited output format */
|
int with_colons; /* Use column delimited output format */
|
||||||
int with_chain; /* Include the certifying certs in a listing */
|
int with_chain; /* Include the certifying certs in a listing */
|
||||||
int with_validation;/* Validate each key while listing. */
|
int with_validation;/* Validate each key while listing. */
|
||||||
|
int with_ephemeral_keys; /* Include ephemeral flagged keys in the
|
||||||
|
keylisting. */
|
||||||
|
|
||||||
int autodetect_encoding; /* Try to detect the input encoding */
|
int autodetect_encoding; /* Try to detect the input encoding */
|
||||||
int is_pem; /* Is in PEM format */
|
int is_pem; /* Is in PEM format */
|
||||||
|
@ -1292,7 +1292,7 @@ list_internal_keys (ctrl_t ctrl, strlist_t names, estream_t fp,
|
|||||||
gpg_error_t rc = 0;
|
gpg_error_t rc = 0;
|
||||||
const char *lastresname, *resname;
|
const char *lastresname, *resname;
|
||||||
int have_secret;
|
int have_secret;
|
||||||
int want_ephemeral = opt.with_ephemeral_keys;
|
int want_ephemeral = ctrl->with_ephemeral_keys;
|
||||||
|
|
||||||
hd = keydb_new (0);
|
hd = keydb_new (0);
|
||||||
if (!hd)
|
if (!hd)
|
||||||
|
@ -296,6 +296,11 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
|
|||||||
}
|
}
|
||||||
else if (!strcmp (key, "allow-pinentry-notify"))
|
else if (!strcmp (key, "allow-pinentry-notify"))
|
||||||
ctrl->server_local->allow_pinentry_notify = 1;
|
ctrl->server_local->allow_pinentry_notify = 1;
|
||||||
|
else if (!strcmp (key, "with-ephemeral-keys"))
|
||||||
|
{
|
||||||
|
int i = *value? atoi (value) : 0;
|
||||||
|
ctrl->with_ephemeral_keys = i;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return gpg_error (GPG_ERR_UNKNOWN_OPTION);
|
return gpg_error (GPG_ERR_UNKNOWN_OPTION);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user