Merge branch 'master' of ssh+git://playfair.gnupg.org/git/gpgme
[gpgme.git] / src / engine-gpg.c
index dc0906d..3b9a6ff 100644 (file)
@@ -16,7 +16,7 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with this program; if not, see <http://www.gnu.org/licenses/>.
+   License along with this program; if not, see <https://www.gnu.org/licenses/>.
 */
 
 #if HAVE_CONFIG_H
@@ -74,6 +74,10 @@ struct fd_data_map_s
 };
 
 
+/* NB.: R_LINE is allocated an gpgrt function and thus gpgrt_free
+ * shall be used to release it.  This takes care of custom memory
+ * allocators and avoids problems on Windows with different runtimes
+ * used for libgpg-error/gpgrt and gpgme.  */
 typedef gpgme_error_t (*colon_preprocessor_t) (char *line, char **rline);
 
 struct engine_gpg
@@ -139,6 +143,10 @@ struct engine_gpg
 
   struct gpgme_io_cbs io_cbs;
   gpgme_pinentry_mode_t pinentry_mode;
+  char request_origin[10];
+
+  /* NULL or the data object fed to --override_session_key-fd.  */
+  gpgme_data_t override_session_key;
 };
 
 typedef struct engine_gpg *engine_gpg_t;
@@ -441,6 +449,8 @@ gpg_release (void *engine)
   if (gpg->cmd.keyword)
     free (gpg->cmd.keyword);
 
+  gpgme_data_release (gpg->override_session_key);
+
   free (gpg);
 }
 
@@ -454,6 +464,7 @@ gpg_new (void **engine, const char *file_name, const char *home_dir,
   char *dft_display = NULL;
   char dft_ttyname[64];
   char *dft_ttytype = NULL;
+  char *env_tty = NULL;
 
   gpg = calloc (1, sizeof *gpg);
   if (!gpg)
@@ -543,6 +554,8 @@ gpg_new (void **engine, const char *file_name, const char *home_dir,
     rc = add_arg (gpg, "utf8");
   if (!rc)
     rc = add_arg (gpg, "--enable-progress-filter");
+  if (!rc && have_gpg_version (gpg, "2.1.11"))
+    rc = add_arg (gpg, "--exit-on-status-write-error");
   if (rc)
     goto leave;
 
@@ -560,11 +573,20 @@ gpg_new (void **engine, const char *file_name, const char *home_dir,
        goto leave;
     }
 
-  if (isatty (1))
+  rc = _gpgme_getenv ("GPG_TTY", &env_tty);
+  if (isatty (1) || env_tty || rc)
     {
-      int err;
+      int err = 0;
 
-      err = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
+      if (rc)
+        goto leave;
+      else if (env_tty)
+        {
+          snprintf (dft_ttyname, sizeof (dft_ttyname), "%s", env_tty);
+          free (env_tty);
+        }
+      else
+        err = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
 
       /* Even though isatty() returns 1, ttyname_r() may fail in many
         ways, e.g., when /dev/pts is not accessible under chroot.  */
@@ -607,6 +629,24 @@ gpg_new (void **engine, const char *file_name, const char *home_dir,
 }
 
 
+/* Copy flags from CTX into the engine object.  */
+static void
+gpg_set_engine_flags (void *engine, const gpgme_ctx_t ctx)
+{
+  engine_gpg_t gpg = engine;
+
+  if (ctx->request_origin && have_gpg_version (gpg, "2.2.6"))
+    {
+      if (strlen (ctx->request_origin) + 1 > sizeof gpg->request_origin)
+        strcpy (gpg->request_origin, "xxx"); /* Too long  - force error */
+      else
+        strcpy (gpg->request_origin, ctx->request_origin);
+    }
+  else
+    *gpg->request_origin = 0;
+}
+
+
 static gpgme_error_t
 gpg_set_locale (void *engine, int category, const char *value)
 {
@@ -835,7 +875,7 @@ build_argv (engine_gpg_t gpg, const char *pgmname)
     argc++;
   if (!gpg->cmd.used)
     argc++;    /* --batch */
-  argc += 1;   /* --no-sk-comments */
+  argc += 2;   /* --no-sk-comments, --request-origin */
 
   argv = calloc (argc + 1, sizeof *argv);
   if (!argv)
@@ -883,6 +923,20 @@ build_argv (engine_gpg_t gpg, const char *pgmname)
       argc++;
     }
 
+  if (*gpg->request_origin)
+    {
+      argv[argc] = _gpgme_strconcat ("--request-origin=",
+                                     gpg->request_origin, NULL);
+      if (!argv[argc])
+       {
+          int saved_err = gpg_error_from_syserror ();
+         free (fd_data_map);
+         free_argv (argv);
+         return saved_err;
+        }
+      argc++;
+    }
+
   if (gpg->pinentry_mode && have_gpg_version (gpg, "2.1.0"))
     {
       const char *s = NULL;
@@ -1095,13 +1149,14 @@ read_status (engine_gpg_t gpg)
       err = 0;
       gpg->status.eof = 1;
       if (gpg->status.mon_cb)
-        err = gpg->status.mon_cb (gpg->status.mon_cb_value,
-                                  GPGME_STATUS_EOF, "");
+        err = gpg->status.mon_cb (gpg->status.mon_cb_value, "", "");
       if (gpg->status.fnc)
         {
           char emptystring[1] = {0};
           err = gpg->status.fnc (gpg->status.fnc_value,
                                  GPGME_STATUS_EOF, emptystring);
+          if (gpg_err_code (err) == GPG_ERR_FALSE)
+            err = 0; /* Drop special error code.  */
         }
 
       return err;
@@ -1169,6 +1224,8 @@ read_status (engine_gpg_t gpg)
                        {
                          err = gpg->status.fnc (gpg->status.fnc_value,
                                                 r, rest);
+                          if (gpg_err_code (err) == GPG_ERR_FALSE)
+                            err = 0; /* Drop special error code.  */
                          if (err)
                            return err;
                         }
@@ -1326,7 +1383,7 @@ read_colon_line (engine_gpg_t gpg)
                         }
                       while (linep && *linep);
 
-                      free (line);
+                      gpgrt_free (line);
                     }
                   else
                     gpg->colon.fnc (gpg->colon.fnc_value, buffer);
@@ -1535,13 +1592,59 @@ add_input_size_hint (engine_gpg_t gpg, gpgme_data_t data)
 
 
 static gpgme_error_t
-gpg_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain)
+gpg_decrypt (void *engine,
+             gpgme_decrypt_flags_t flags,
+             gpgme_data_t ciph, gpgme_data_t plain,
+             int export_session_key, const char *override_session_key,
+             int auto_key_retrieve)
 {
   engine_gpg_t gpg = engine;
   gpgme_error_t err;
 
   err = add_arg (gpg, "--decrypt");
 
+  if (!err && (flags & GPGME_DECRYPT_UNWRAP))
+    {
+      if (!have_gpg_version (gpg, "2.1.12"))
+        err = gpg_error (GPG_ERR_NOT_SUPPORTED);
+      else
+        err = add_arg (gpg, "--unwrap");
+    }
+
+  if (!err && export_session_key)
+    err = add_arg (gpg, "--show-session-key");
+
+  if (!err && auto_key_retrieve)
+    err = add_arg (gpg, "--auto-key-retrieve");
+
+  if (!err && override_session_key && *override_session_key)
+    {
+      if (have_gpg_version (gpg, "2.1.16"))
+        {
+          gpgme_data_release (gpg->override_session_key);
+          TRACE2 (DEBUG_ENGINE, "override", gpg, "seskey='%s' len=%zu\n",
+                  override_session_key,
+                  strlen (override_session_key));
+
+          err = gpgme_data_new_from_mem (&gpg->override_session_key,
+                                         override_session_key,
+                                         strlen (override_session_key), 1);
+          if (!err)
+            {
+              err = add_arg (gpg, "--override-session-key-fd");
+              if (!err)
+                err = add_data (gpg, gpg->override_session_key, -2, 0);
+            }
+        }
+      else
+        {
+          /* Using that option may leak the session key via ps(1).  */
+          err = add_arg (gpg, "--override-session-key");
+          if (!err)
+            err = add_arg (gpg, override_session_key);
+        }
+    }
+
   /* Tell the gpg object about the data.  */
   if (!err)
     err = add_arg (gpg, "--output");
@@ -1562,13 +1665,18 @@ gpg_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain)
 }
 
 static gpgme_error_t
-gpg_delete (void *engine, gpgme_key_t key, int allow_secret)
+gpg_delete (void *engine, gpgme_key_t key, unsigned int flags)
 {
   engine_gpg_t gpg = engine;
-  gpgme_error_t err;
+  gpgme_error_t err = 0;
+  int allow_secret = flags & GPGME_DELETE_ALLOW_SECRET;
+  int force = flags & GPGME_DELETE_FORCE;
 
-  err = add_arg (gpg, allow_secret ? "--delete-secret-and-public-key"
-                : "--delete-key");
+  if (force)
+    err = add_arg (gpg, "--yes");
+  if (!err)
+    err = add_arg (gpg, allow_secret ? "--delete-secret-and-public-key"
+                  : "--delete-key");
   if (!err)
     err = add_arg (gpg, "--");
   if (!err)
@@ -1631,6 +1739,23 @@ append_args_from_signers (engine_gpg_t gpg, gpgme_ctx_t ctx /* FIXME */)
 
 
 static gpgme_error_t
+append_args_from_sender (engine_gpg_t gpg, gpgme_ctx_t ctx)
+{
+  gpgme_error_t err;
+
+  if (ctx->sender && have_gpg_version (gpg, "2.1.15"))
+    {
+      err = add_arg (gpg, "--sender");
+      if (!err)
+        err = add_arg (gpg, ctx->sender);
+    }
+  else
+    err = 0;
+  return err;
+}
+
+
+static gpgme_error_t
 append_args_from_sig_notations (engine_gpg_t gpg, gpgme_ctx_t ctx /* FIXME */)
 {
   gpgme_error_t err = 0;
@@ -1784,9 +1909,23 @@ gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
   if (!err && use_armor)
     err = add_arg (gpg, "--armor");
 
+  if (!err && (flags & GPGME_ENCRYPT_WRAP))
+    {
+      /* gpg is current not able to detect already compressed
+       * packets.  Thus when using
+       *   gpg --unwrap -d | gpg --no-literal -e
+       * the encryption would add an additional compression layer.
+       * We better suppress that.  */
+      flags |= GPGME_ENCRYPT_NO_COMPRESS;
+      err = add_arg (gpg, "--no-literal");
+    }
+
   if (!err && (flags & GPGME_ENCRYPT_NO_COMPRESS))
     err = add_arg (gpg, "--compress-algo=none");
 
+  if (!err && (flags & GPGME_ENCRYPT_THROW_KEYIDS))
+    err = add_arg (gpg, "--throw-keyids");
+
   if (gpgme_data_get_encoding (plain) == GPGME_DATA_ENCODING_MIME
       && have_gpg_version (gpg, "2.1.14"))
     err = add_arg (gpg, "--mimemode");
@@ -1856,6 +1995,9 @@ gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
   if (!err && (flags & GPGME_ENCRYPT_NO_COMPRESS))
     err = add_arg (gpg, "--compress-algo=none");
 
+  if (!err && (flags & GPGME_ENCRYPT_THROW_KEYIDS))
+    err = add_arg (gpg, "--throw-keyids");
+
   if (gpgme_data_get_encoding (plain) == GPGME_DATA_ENCODING_MIME
       && have_gpg_version (gpg, "2.1.14"))
     err = add_arg (gpg, "--mimemode");
@@ -1878,6 +2020,9 @@ gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
     err = append_args_from_signers (gpg, ctx);
 
   if (!err)
+    err = append_args_from_sender (gpg, ctx);
+
+  if (!err)
     err = append_args_from_sig_notations (gpg, ctx);
 
   /* Tell the gpg object about the data.  */
@@ -2000,7 +2145,8 @@ gpg_add_algo_usage_expire (engine_gpg_t gpg,
   /* This condition is only required to allow the use of gpg < 2.1.16 */
   if (algo
       || (flags & (GPGME_CREATE_SIGN | GPGME_CREATE_ENCR
-                   | GPGME_CREATE_CERT | GPGME_CREATE_AUTH))
+                   | GPGME_CREATE_CERT | GPGME_CREATE_AUTH
+                   | GPGME_CREATE_NOEXPIRE))
       || expires)
     {
       err = add_arg (gpg, algo? algo : "default");
@@ -2014,11 +2160,18 @@ gpg_add_algo_usage_expire (engine_gpg_t gpg,
                     (flags & GPGME_CREATE_AUTH)? " auth":"");
           err = add_arg (gpg, *tmpbuf? tmpbuf : "default");
         }
-      if (!err && expires)
+      if (!err)
         {
-          char tmpbuf[8+20];
-          snprintf (tmpbuf, sizeof tmpbuf, "seconds=%lu", expires);
-          err = add_arg (gpg, tmpbuf);
+          if ((flags & GPGME_CREATE_NOEXPIRE))
+            err = add_arg (gpg, "never");
+          else if (expires == 0)
+            err = add_arg (gpg, "-");
+          else
+            {
+              char tmpbuf[8+20];
+              snprintf (tmpbuf, sizeof tmpbuf, "seconds=%lu", expires);
+              err = add_arg (gpg, tmpbuf);
+            }
         }
     }
   else
@@ -2047,19 +2200,6 @@ gpg_createkey_from_param (engine_gpg_t gpg,
 }
 
 
-/* This is used for gpg versions which do not support the quick-genkey
- * command to emulate the gpgme_op_createkey API.  */
-static gpgme_error_t
-gpg_createkey_legacy (engine_gpg_t gpg,
-               const char *userid, const char *algo,
-               unsigned long expires,
-               unsigned int flags,
-               unsigned int extraflags)
-{
-  return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
-}
-
-
 static gpgme_error_t
 gpg_createkey (engine_gpg_t gpg,
                const char *userid, const char *algo,
@@ -2077,6 +2217,8 @@ gpg_createkey (engine_gpg_t gpg,
       err = add_arg (gpg, "--passphrase");
       if (!err)
         err = add_arg (gpg, "");
+      if (!err)
+        err = add_arg (gpg, "--batch");
     }
   if (!err && (flags & GPGME_CREATE_FORCE))
     err = add_arg (gpg, "--yes");
@@ -2115,6 +2257,8 @@ gpg_addkey (engine_gpg_t gpg,
       err = add_arg (gpg, "--passphrase");
       if (!err)
         err = add_arg (gpg, "");
+      if (!err)
+        err = add_arg (gpg, "--batch");
     }
   if (!err)
     err = add_arg (gpg, "--");
@@ -2141,7 +2285,14 @@ gpg_adduid (engine_gpg_t gpg,
   if (!key || !key->fpr || !userid)
     return gpg_error (GPG_ERR_INV_ARG);
 
-  if ((extraflags & GENKEY_EXTRAFLAG_REVOKE))
+  if ((extraflags & GENKEY_EXTRAFLAG_SETPRIMARY))
+    {
+      if (!have_gpg_version (gpg, "2.1.20"))
+        err = gpg_error (GPG_ERR_NOT_SUPPORTED);
+      else
+        err = add_arg (gpg, "--quick-set-primary-uid");
+    }
+  else if ((extraflags & GENKEY_EXTRAFLAG_REVOKE))
     err = add_arg (gpg, "--quick-revuid");
   else
     err = add_arg (gpg, "--quick-adduid");
@@ -2181,7 +2332,7 @@ gpg_genkey (void *engine,
    *  USERID && !KEY          - Create a new keyblock.
    * !USERID &&  KEY          - Add a new subkey to KEY (gpg >= 2.1.14)
    *  USERID &&  KEY && !ALGO - Add a new user id to KEY (gpg >= 2.1.14).
-   *
+   *                            or set a flag on a user id.
    */
   if (help_data)
     {
@@ -2194,16 +2345,10 @@ gpg_genkey (void *engine,
       else
         err = gpg_createkey_from_param (gpg, help_data, extraflags);
     }
-  else if (userid && !key)
-    {
-      if (!have_gpg_version (gpg, "2.1.13"))
-        err = gpg_createkey_legacy (gpg, userid, algo, expires, flags,
-                                    extraflags);
-      else
-        err = gpg_createkey (gpg, userid, algo, expires, flags, extraflags);
-    }
   else if (!have_gpg_version (gpg, "2.1.13"))
     err = gpg_error (GPG_ERR_NOT_SUPPORTED);
+  else if (userid && !key)
+    err = gpg_createkey (gpg, userid, algo, expires, flags, extraflags);
   else if (!userid && key)
     err = gpg_addkey (gpg, algo, expires, key, flags, extraflags);
   else if (userid && key && !algo)
@@ -2456,7 +2601,7 @@ gpg_keylist_preprocess (char *line, char **r_line)
       n = strlen (field[1]);
       if (n > 16)
         {
-          if (asprintf (r_line,
+          if (gpgrt_asprintf (r_line,
                         "pub:o%s:%s:%s:%s:%s:%s::::::::\n"
                         "fpr:::::::::%s:",
                         field[6], field[3], field[2], field[1] + n - 16,
@@ -2465,7 +2610,7 @@ gpg_keylist_preprocess (char *line, char **r_line)
         }
       else
         {
-          if (asprintf (r_line,
+          if (gpgrt_asprintf (r_line,
                         "pub:o%s:%s:%s:%s:%s:%s::::::::",
                         field[6], field[3], field[2], field[1],
                         field[4], field[5]) < 0)
@@ -2482,6 +2627,9 @@ gpg_keylist_preprocess (char *line, char **r_line)
         as defined in 5.2. Machine Readable Indexes of the OpenPGP
         HTTP Keyserver Protocol (draft).
 
+         For an ldap keyserver the format is:
+         uid:<escaped uid string>
+
         We want:
         uid:o<flags>::::<creatdate>:<expdate>:::<c-coded uid>:
       */
@@ -2523,9 +2671,17 @@ gpg_keylist_preprocess (char *line, char **r_line)
          }
        *dst = '\0';
 
-       if (asprintf (r_line, "uid:o%s::::%s:%s:::%s:",
-                     field[4], field[2], field[3], uid) < 0)
-         return gpg_error_from_syserror ();
+        if (fields < 4)
+          {
+            if (gpgrt_asprintf (r_line, "uid:o::::::::%s:", uid) < 0)
+              return gpg_error_from_syserror ();
+          }
+        else
+          {
+            if (gpgrt_asprintf (r_line, "uid:o%s::::%s:%s:::%s:",
+                                field[4], field[2], field[3], uid) < 0)
+              return gpg_error_from_syserror ();
+          }
       }
       return 0;
 
@@ -2547,7 +2703,7 @@ gpg_keylist_build_options (engine_gpg_t gpg, int secret_only,
   err = add_arg (gpg, "--with-colons");
 
   /* Since gpg 2.1.15 fingerprints are always printed, thus there is
-   * no more need to explictly request them.  */
+   * no more need to explicitly request them.  */
   if (!have_gpg_version (gpg, "2.1.15"))
     {
       if (!err)
@@ -2662,6 +2818,38 @@ gpg_keylist_ext (void *engine, const char *pattern[], int secret_only,
 
 
 static gpgme_error_t
+gpg_keylist_data (void *engine, gpgme_data_t data)
+{
+  engine_gpg_t gpg = engine;
+  gpgme_error_t err;
+
+  if (!have_gpg_version (gpg, "2.1.14"))
+    return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
+  err = add_arg (gpg, "--with-colons");
+  if (!err)
+    err = add_arg (gpg, "--with-fingerprint");
+  if (!err)
+    err = add_arg (gpg, "--import-options");
+  if (!err)
+    err = add_arg (gpg, "import-show");
+  if (!err)
+    err = add_arg (gpg, "--dry-run");
+  if (!err)
+    err = add_arg (gpg, "--import");
+  if (!err)
+    err = add_arg (gpg, "--");
+  if (!err)
+    err = add_data (gpg, data, -1, 0);
+
+  if (!err)
+    err = start (gpg);
+
+  return err;
+}
+
+
+static gpgme_error_t
 gpg_keysign (void *engine, gpgme_key_t key, const char *userid,
              unsigned long expire, unsigned int flags,
              gpgme_ctx_t ctx)
@@ -2727,6 +2915,46 @@ gpg_keysign (void *engine, gpgme_key_t key, const char *userid,
 
 
 static gpgme_error_t
+gpg_tofu_policy (void *engine, gpgme_key_t key, gpgme_tofu_policy_t policy)
+{
+  engine_gpg_t gpg = engine;
+  gpgme_error_t err;
+  const char *policystr = NULL;
+
+  if (!key || !key->fpr)
+    return gpg_error (GPG_ERR_INV_ARG);
+
+  switch (policy)
+    {
+    case GPGME_TOFU_POLICY_NONE:                           break;
+    case GPGME_TOFU_POLICY_AUTO:    policystr = "auto";    break;
+    case GPGME_TOFU_POLICY_GOOD:    policystr = "good";    break;
+    case GPGME_TOFU_POLICY_BAD:     policystr = "bad";     break;
+    case GPGME_TOFU_POLICY_ASK:     policystr = "ask";     break;
+    case GPGME_TOFU_POLICY_UNKNOWN: policystr = "unknown"; break;
+    }
+  if (!policystr)
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  if (!have_gpg_version (gpg, "2.1.10"))
+    return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
+  err = add_arg (gpg, "--tofu-policy");
+  if (!err)
+    err = add_arg (gpg, "--");
+  if (!err)
+    err = add_arg (gpg, policystr);
+  if (!err)
+    err = add_arg (gpg, key->fpr);
+
+  if (!err)
+    err = start (gpg);
+
+  return err;
+}
+
+
+static gpgme_error_t
 gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
          gpgme_sig_mode_t mode, int use_armor, int use_textmode,
          int include_certs, gpgme_ctx_t ctx /* FIXME */)
@@ -2758,6 +2986,8 @@ gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
   if (!err)
     err = append_args_from_signers (gpg, ctx);
   if (!err)
+    err = append_args_from_sender (gpg, ctx);
+  if (!err)
     err = append_args_from_sig_notations (gpg, ctx);
 
   if (gpgme_data_get_file_name (in))
@@ -2809,12 +3039,18 @@ gpg_trustlist (void *engine, const char *pattern)
 
 static gpgme_error_t
 gpg_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
-           gpgme_data_t plaintext)
+           gpgme_data_t plaintext, gpgme_ctx_t ctx)
 {
   engine_gpg_t gpg = engine;
-  gpgme_error_t err = 0;
+  gpgme_error_t err;
+
+  err = append_args_from_sender (gpg, ctx);
+  if (!err && ctx->auto_key_retrieve)
+    err = add_arg (gpg, "--auto-key-retrieve");
 
-  if (plaintext)
+  if (err)
+    ;
+  else if (plaintext)
     {
       /* Normal or cleartext signature.  */
       err = add_arg (gpg, "--output");
@@ -2887,8 +3123,8 @@ struct engine_ops _gpgme_engine_ops_gpg =
     gpg_set_colon_line_handler,
     gpg_set_locale,
     NULL,                              /* set_protocol */
+    gpg_set_engine_flags,               /* set_engine_flags */
     gpg_decrypt,
-    gpg_decrypt,                       /* decrypt_verify */
     gpg_delete,
     gpg_edit,
     gpg_encrypt,
@@ -2899,7 +3135,9 @@ struct engine_ops _gpgme_engine_ops_gpg =
     gpg_import,
     gpg_keylist,
     gpg_keylist_ext,
+    gpg_keylist_data,
     gpg_keysign,
+    gpg_tofu_policy,    /* tofu_policy */
     gpg_sign,
     gpg_trustlist,
     gpg_verify,
@@ -2907,6 +3145,8 @@ struct engine_ops _gpgme_engine_ops_gpg =
     NULL,               /* opassuan_transact */
     NULL,              /* conf_load */
     NULL,              /* conf_save */
+    NULL,              /* conf_dir */
+    NULL,               /* query_swdb */
     gpg_set_io_cbs,
     gpg_io_event,
     gpg_cancel,