diff --git a/doc/gpgme.texi b/doc/gpgme.texi --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -4016,6 +4016,58 @@ and all resources associated to it will be released. @end deftypefun +@c +@c gpgme_op_set_expire +@c +@deftypefun gpgme_error_t gpgme_op_set_expire@ + (@w{gpgme_ctx_t @var{ctx}}, @ + @w{const char *@var{fpr}}, @ + @w{unsigned long @var{expire}}, @ + @w{const char *@var{subfprs}}); + +@since{1.14.1} + +The function @code{gpgme_op_set_expire} sets the expiry date of +a key idefntified by the fingerprint fpr. +This function requires at least version 2.1.22 of GnuPG. + +@var{fpr} specifies the key to operate on. + +@var{expire} specifies the expiration time in seconds from now. +To be similar to other usages where expire dates are provided +in unsigned long this is similar to the key creation date +and so it is in seconds from NOW. + +The common case is to use 0 to not set an expiration date. +Note that this parameter takes an unsigned long value and not +a @code{time_t} to avoid problems on systems which use a signed +32 bit @code{time_t}. Note further that the OpenPGP protocol +uses 32 bit values for timestamps and thus can +only encode dates up to the year 2106. + +@var{subfprs} This is an optional parameter to identify subkeys +for which the expiration should be set. This can be an asterix +to change the expiry date of all subkeys or a space seperated +list of fingerprints. If this parameter is ommited only the +expiry of the primary key, provided by @var{fpr} is changed. + +@end deftypefun + +@deftypefun gpgme_error_t gpgme_op_revuid_start @ + (@w{gpgme_ctx_t @var{ctx}}, @ + @w{gpgme_key_t @var{key}}, @ + @w{const char *@var{userid}}, @ + @w{unsigned int @var{flags}}); + +@since{1.14.1} + +The function @code{gpgme_op_set_expire_start} initiates a +@code{gpgme_op_set_expire} operation; see there for details. It must +be completed by calling @code{gpgme_wait} on the context. +@xref{Waiting For Completion}. + +@end deftypefun + @node Generating Keys @subsection Generating Keys diff --git a/src/engine-assuan.c b/src/engine-assuan.c --- a/src/engine-assuan.c +++ b/src/engine-assuan.c @@ -828,6 +828,7 @@ NULL, /* sign */ NULL, /* verify */ NULL, /* getauditlog */ + NULL, /* setexpire */ llass_transact, /* opassuan_transact */ NULL, /* conf_load */ NULL, /* conf_save */ diff --git a/src/engine-backend.h b/src/engine-backend.h --- a/src/engine-backend.h +++ b/src/engine-backend.h @@ -120,6 +120,9 @@ gpgme_ctx_t ctx); gpgme_error_t (*getauditlog) (void *engine, gpgme_data_t output, unsigned int flags); + /* The setexpire command. */ + gpgme_error_t (*setexpire) (void *engine, const char *fpr, + unsigned long expire, const char *subfprs); gpgme_error_t (*opassuan_transact) (void *engine, const char *command, gpgme_assuan_data_cb_t data_cb, diff --git a/src/engine-g13.c b/src/engine-g13.c --- a/src/engine-g13.c +++ b/src/engine-g13.c @@ -808,6 +808,7 @@ NULL, /* sign */ NULL, /* verify */ NULL, /* getauditlog */ + NULL, /* setexpire */ g13_transact, NULL, /* conf_load */ NULL, /* conf_save */ diff --git a/src/engine-gpg.c b/src/engine-gpg.c --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -3426,6 +3426,41 @@ #undef MYBUFLEN } +static gpgme_error_t +gpg_setexpire (void *engine, + const char *fpr, + unsigned long expire, + const char *subfprs) +{ + gpgme_error_t err; + + engine_gpg_t gpg = (engine_gpg_t) (engine); + + if (!fpr) + return gpg_error (GPG_ERR_INV_ARG); + + err = add_arg (gpg, "--quick-set-expire"); + if (!err) + { + err = add_arg (gpg, fpr); + } + if (!err) + { + char tmpbuf[8+20]; + snprintf (tmpbuf, sizeof tmpbuf, "seconds=%lu", expire); + err = add_arg (gpg, tmpbuf); + } + + if (!err && subfprs) + { + err = add_arg (gpg, subfprs); + } + + if (!err) + err = start (gpg); + return err; +} + struct engine_ops _gpgme_engine_ops_gpg = @@ -3464,6 +3499,7 @@ gpg_sign, gpg_verify, gpg_getauditlog, + gpg_setexpire, NULL, /* opassuan_transact */ NULL, /* conf_load */ NULL, /* conf_save */ diff --git a/src/engine-gpgconf.c b/src/engine-gpgconf.c --- a/src/engine-gpgconf.c +++ b/src/engine-gpgconf.c @@ -1306,6 +1306,7 @@ NULL, /* sign */ NULL, /* verify */ NULL, /* getauditlog */ + NULL, /* setexpire */ NULL, /* opassuan_transact */ gpgconf_conf_load, gpgconf_conf_save, diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c --- a/src/engine-gpgsm.c +++ b/src/engine-gpgsm.c @@ -2326,6 +2326,7 @@ gpgsm_sign, gpgsm_verify, gpgsm_getauditlog, + NULL, /* setexpire */ NULL, /* opassuan_transact */ NULL, /* conf_load */ NULL, /* conf_save */ diff --git a/src/engine.h b/src/engine.h --- a/src/engine.h +++ b/src/engine.h @@ -210,6 +210,10 @@ gpgme_data_t dataout, gpgme_data_t dataerr, unsigned int flags); +gpgme_error_t _gpgme_engine_op_setexpire (engine_t engine, + const char *fpr, + unsigned long expire, + const char *subfprs); /* The available engine option flags. */ #define GPGME_ENGINE_FLAG_OFFLINE 1 diff --git a/src/engine.c b/src/engine.c --- a/src/engine.c +++ b/src/engine.c @@ -1128,3 +1128,18 @@ return (*engine->ops->opspawn) (engine->engine, file, argv, datain, dataout, dataerr, flags); } + +gpgme_error_t +_gpgme_engine_op_setexpire (engine_t engine, + const char *fpr, + unsigned long expire, + const char *subfprs) +{ + if (!engine) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!engine->ops->setexpire) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + return (*engine->ops->setexpire) (engine->engine, fpr, expire, subfprs); +} diff --git a/src/genkey.c b/src/genkey.c --- a/src/genkey.c +++ b/src/genkey.c @@ -663,3 +663,52 @@ { return set_uid_flag (ctx, 1, key, userid, name, value); } + +/* Set the expiry of a key and or subkeys. See --quick-set-expire + in the gnupg documentation. */ +static gpg_error_t +set_expire (gpgme_ctx_t ctx, int synchronous, + const char *fpr, + unsigned long expire, + const char *subfprs) +{ + gpgme_error_t err = 0; + + TRACE_BEG (DEBUG_CTX, "gpgme_op_set_expire", ctx, + "%d fpr='%s' subkeys: '%s' expiry: %lu", synchronous, + fpr, subfprs, expire); + + if (!ctx || !fpr) + return TRACE_ERR (gpg_error (GPG_ERR_INV_ARG)); + + err = _gpgme_op_reset (ctx, synchronous); + if (err) + return err; + + err = _gpgme_engine_op_setexpire (ctx->engine, fpr, expire, subfprs); + + if (synchronous && !err) + err = _gpgme_wait_one (ctx); + return TRACE_ERR (err); +} + +/* See set_expire. */ +gpgme_error_t +gpgme_op_set_expire_start (gpgme_ctx_t ctx, + const char *fpr, + unsigned long expire, + const char *subfprs) +{ + return set_expire (ctx, 0, fpr, expire, subfprs); +} + + +/* See set_expire. This is the synchronous variant. */ +gpgme_error_t +gpgme_op_set_expire (gpgme_ctx_t ctx, + const char *fpr, + unsigned long expire, + const char *subfprs) +{ + return set_expire (ctx, 1, fpr, expire, subfprs); +} diff --git a/src/gpgme.h.in b/src/gpgme.h.in --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -1868,6 +1868,15 @@ gpgme_key_t key, const char *userid, const char *name, const char *value); +/* Change the expiry of a key. */ +gpgme_error_t gpgme_op_set_expire_start (gpgme_ctx_t ctx, + const char *fpr, + unsigned long expire, + const char *subfprs); +gpgme_error_t gpgme_op_set_expire (gpgme_ctx_t ctx, + const char *fpr, + unsigned long expire, + const char *subfprs); /* Retrieve a pointer to the result of a genkey, createkey, or * createsubkey operation. */ diff --git a/src/gpgme.def b/src/gpgme.def --- a/src/gpgme.def +++ b/src/gpgme.def @@ -274,5 +274,8 @@ gpgme_data_new_from_estream @204 + gpgme_op_set_expire @205 + gpgme_op_set_expire_start @206 + ; END diff --git a/src/libgpgme.vers b/src/libgpgme.vers --- a/src/libgpgme.vers +++ b/src/libgpgme.vers @@ -273,6 +273,9 @@ gpgme_err_code_from_syserror; gpgme_err_set_errno; + gpgme_op_set_expire; + gpgme_op_set_expire_start; + local: *; diff --git a/tests/run-genkey.c b/tests/run-genkey.c --- a/tests/run-genkey.c +++ b/tests/run-genkey.c @@ -205,12 +205,14 @@ " for addkey: FPR [ALGO [USAGE [EXPIRESECONDS]]]\n" " for adduid: FPR USERID\n" " for revuid: FPR USERID\n" + " for set-expire: FPR EXPIRE [SUBFPRS]\n" " for set-primary: FPR USERID\n" "Options:\n" " --addkey add a subkey to the key with FPR\n" " --adduid add a user id to the key with FPR\n" " --revuid revoke a user id from the key with FPR\n" " --set-primary set the primary key flag on USERID\n" + " --set-expire set the expiry date of the key FPR\n" " --verbose run in verbose mode\n" " --status print status lines from the backend\n" " --progress print progress info\n" @@ -238,9 +240,12 @@ int adduid = 0; int revuid = 0; int setpri = 0; + int setexpire = 0; const char *userid; const char *algo = NULL; const char *newuserid = NULL; + const char *fpr = NULL; + const char *subfprs = NULL; unsigned int flags = 0; unsigned long expire = 0; gpgme_genkey_result_t result; @@ -258,6 +263,14 @@ } else if (!strcmp (*argv, "--help")) show_usage (0); + else if (!strcmp (*argv, "--set-expire")) + { + setexpire = 1; + adduid = 0; + revuid = 0; + setpri = 0; + argc--; argv++; + } else if (!strcmp (*argv, "--addkey")) { addkey = 1; @@ -341,6 +354,19 @@ userid = argv[0]; newuserid = argv[1]; } + else if (setexpire) + { + if (argc < 2) + { + show_usage (1); + } + fpr = argv[0]; + expire = parse_expire_string (argv[1]); + if (argc == 3) + { + subfprs = argv[2]; + } + } else { if (!argc || argc > 4) @@ -373,7 +399,18 @@ gpgme_set_passphrase_cb (ctx, passphrase_cb, NULL); } - if (addkey || adduid || revuid || setpri) + + if (setexpire) + { + err = gpgme_op_set_expire (ctx, fpr, expire, subfprs); + if (err) + { + fprintf (stderr, PGM ": gpgme_op_set_expire failed: %s\n", + gpg_strerror (err)); + exit (1); + } + } + else if (addkey || adduid || revuid || setpri) { gpgme_key_t akey; @@ -438,7 +475,7 @@ } } - if (!setpri) + if (!setpri && !setexpire) { result = gpgme_op_genkey_result (ctx); if (!result)