[PATCH 7/9] add a gpg_path value for notmuch_database_t

Daniel Kahn Gillmor dkg at fifthhorseman.net
Wed Dec 9 19:39:44 PST 2015


Exposing this to the user of the library lets the user point to
arbitrary gpg executables when trying to decrypt.
---
 lib/database-private.h |  3 ++
 lib/database.cc        | 93 +++++++++++++++++++++++++++++++++++++++++++-------
 lib/notmuch.h          | 31 +++++++++++++++++
 3 files changed, 115 insertions(+), 12 deletions(-)

diff --git a/lib/database-private.h b/lib/database-private.h
index 1bf76c5..9a35044 100644
--- a/lib/database-private.h
+++ b/lib/database-private.h
@@ -171,6 +171,9 @@ struct _notmuch_database {
      * notmuch_database_new_revision. */
     unsigned long revision;
     const char *uuid;
+
+    /* can be NULL, meaning "try to find gpg2 or gpg if possible" */
+    char *gpg_path;
     GMimeCryptoContext *gpg_crypto_ctx;
 
     Xapian::QueryParser *query_parser;
diff --git a/lib/database.cc b/lib/database.cc
index d0e8800..c40ce77 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -996,6 +996,7 @@ notmuch_database_open_verbose (const char *path,
 	    notmuch, notmuch->xapian_db->get_uuid ().c_str ());
 
 	notmuch->gpg_crypto_ctx = NULL;
+	notmuch->gpg_path = NULL;
 	
 	notmuch->query_parser = new Xapian::QueryParser;
 	notmuch->term_gen = new Xapian::TermGenerator;
@@ -1096,6 +1097,10 @@ notmuch_database_close (notmuch_database_t *notmuch)
 	g_object_unref (notmuch->gpg_crypto_ctx);
 	notmuch->gpg_crypto_ctx = NULL;
     }
+    if (notmuch->gpg_path) {
+	talloc_free(notmuch->gpg_path);
+	notmuch->gpg_path = NULL;
+    }
     
     return status;
 }
@@ -2393,17 +2398,6 @@ _notmuch_database_link_message (notmuch_database_t *notmuch,
     return status;
 }
 
-static const char*
-_notmuch_database_get_gpg_path (notmuch_database_t *notmuch)
-{
-#define try_gpg_path(z) if (!access(z, X_OK)) return z
-    try_gpg_path("/usr/bin/gpg2");
-    try_gpg_path("/bin/gpg2");
-    try_gpg_path("/usr/bin/gpg");
-    try_gpg_path("/bin/gpg");
-    return NULL;
-}
-
 notmuch_private_status_t
 _notmuch_database_get_crypto_for_protocol (notmuch_database_t *notmuch,
 					   const char *protocol,
@@ -2425,7 +2419,7 @@ _notmuch_database_get_crypto_for_protocol (notmuch_database_t *notmuch,
 	     * here? how would this config get into the library?  Is
 	     * this an option we can set on the database object?  Or
 	     * elsewhere?  */
-	    notmuch->gpg_crypto_ctx = g_mime_gpg_context_new (NULL, _notmuch_database_get_gpg_path(notmuch));
+	    notmuch->gpg_crypto_ctx = g_mime_gpg_context_new (NULL, notmuch_database_get_gpg_path(notmuch));
 	    if (! notmuch->gpg_crypto_ctx)
 		return NOTMUCH_PRIVATE_STATUS_FAILED_CRYPTO_CONTEXT_CREATION;
 
@@ -2752,3 +2746,78 @@ notmuch_database_status_string (const notmuch_database_t *notmuch)
 {
     return notmuch->status_string;
 }
+
+
+static notmuch_bool_t
+_find_in_path(const char* path)
+{
+    char *c = NULL, *save = NULL, *tok;
+    size_t n;
+    int dfd = -1;
+    notmuch_bool_t ret = FALSE;
+    
+    n = confstr(_CS_PATH, NULL, 0);
+    c = (char*)talloc_size(NULL, n);
+    if (!c)
+	return FALSE;
+    confstr(_CS_PATH, c, n);
+
+    tok = strtok_r(c, ":", &save);
+    while (tok) {
+	dfd = open(tok, O_DIRECTORY | O_RDONLY);
+	if (dfd != -1) {
+	    if (!faccessat(dfd, path, X_OK, 0)) {
+		ret = TRUE;
+		goto done;
+	    }
+	    close(dfd);
+	}
+	tok = strtok_r(NULL, ":", &save);
+    }
+done:
+    if (dfd != -1)
+	close(dfd);
+    if (c)
+	talloc_free(c);
+    return ret;
+}
+
+notmuch_status_t
+notmuch_database_set_gpg_path (notmuch_database_t *notmuch, const char* path)
+{
+    /* return success if this matches what is already configured */
+    if ((!path && !notmuch->gpg_path) ||
+	(path && notmuch->gpg_path && 0 == strcmp(path, notmuch->gpg_path)))
+	return NOTMUCH_STATUS_SUCCESS;
+    
+    if (!path && !_find_in_path(path))
+	return NOTMUCH_STATUS_FILE_ERROR;
+
+    /* clear any existing gpg_crypto_ctx, since things are changing */
+    if (notmuch->gpg_crypto_ctx) {
+	g_object_unref (notmuch->gpg_crypto_ctx);
+	notmuch->gpg_crypto_ctx = NULL;
+    }
+
+    if (notmuch->gpg_path) {
+	talloc_free(notmuch->gpg_path);
+	notmuch->gpg_path = NULL;
+    }
+
+    if (path)
+	notmuch->gpg_path = talloc_strdup (notmuch, path);
+    
+    return NOTMUCH_STATUS_SUCCESS;
+}
+
+const char*
+notmuch_database_get_gpg_path (const notmuch_database_t *notmuch)
+{
+    if (notmuch->gpg_path)
+	return notmuch->gpg_path;
+
+#define try_gpg_path(z) if (_find_in_path(z)) return z
+    try_gpg_path("gpg2");
+    try_gpg_path("gpg");
+    return NULL;
+}
diff --git a/lib/notmuch.h b/lib/notmuch.h
index 809a2ea..e9cfed3 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -591,6 +591,37 @@ notmuch_database_add_message_try_decrypt (notmuch_database_t *database,
 					  notmuch_message_t **message);
 
 /**
+ * Tell the notmuch database where to find GnuPG.
+ *
+ * This is only useful when notmuch might try to use GnuPG to decrypt
+ * MIME parts (see for example
+ * notmuch_database_add_message_try_decrypt).  The argument needs to
+ * be an executable version of gpg.
+ * 
+ * If this function has never been invoked, notmuch will try to find
+ * gpg in reasonable places.
+ *
+ * This value is not currently stored in the database on disk, it is
+ * only used for this notmuch_database_t while it exists.
+ *
+ * Return value:
+ *
+ * NOTMUCH_STATUS_SUCCESS: the path was accepted and will be used.
+ * 
+ * NOTMUCH_STATUS_FILE_ERROR: the path given either wasn't found or
+ *      wasn't executable.
+ */
+notmuch_status_t
+notmuch_database_set_gpg_path (notmuch_database_t *database, const char* path);
+			       
+/**
+ * Find out where the notmuch database will try to find gpg if it
+ * needs to use it.
+ */
+const char*
+notmuch_database_get_gpg_path (const notmuch_database_t *database);
+
+/**
  * Remove a message filename from the given notmuch database. If the
  * message has no more filenames, remove the message.
  *
-- 
2.6.2



More information about the notmuch mailing list