LCOV - code coverage report
Current view: top level - src/plugins/gpgme - gpgme.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 140 271 51.7 %
Date: 2022-05-21 16:19:22 Functions: 13 18 72.2 %

          Line data    Source code
       1             : /**
       2             :  * @file
       3             :  *
       4             :  * @brief filter plugin providing cryptographic operations using GPGME
       5             :  *
       6             :  * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
       7             :  *
       8             :  */
       9             : 
      10             : #ifndef HAVE_KDBCONFIG
      11             : #include "kdbconfig.h"
      12             : #endif
      13             : #include "gpgme.h"
      14             : #include "keylist.h"
      15             : #include <gpgme.h>
      16             : #include <kdb.h>
      17             : #include <kdberrors.h>
      18             : #include <kdbtypes.h>
      19             : #include <locale.h>
      20             : #include <stdlib.h>
      21             : #include <string.h>
      22             : 
      23             : /**
      24             :  * @brief checks if a Key has been marked for encryption by checking the Key's metadata.
      25             :  *
      26             :  * If the metakey ELEKTRA_CRYPTO_META_ENCRYPT has the value "1" it is considered to be true.
      27             :  * Every other value or the non-existence of the metakey is considered to be false.
      28             :  *
      29             :  * @param k the Key to be checked
      30             :  * @retval 0 if the Key has not been marked for encryption
      31             :  * @retval 1 if the Key has been marked for encryption
      32             :  */
      33          16 : static int isMarkedForEncryption (const Key * k)
      34             : {
      35          16 :         const Key * metaEncrypt = keyGetMeta (k, ELEKTRA_GPGME_META_ENCRYPT);
      36          16 :         if (metaEncrypt && strcmp (keyString (metaEncrypt), "1") == 0)
      37             :         {
      38          12 :                 return 1;
      39             :         }
      40             :         return 0;
      41             : }
      42             : 
      43             : /**
      44             :  * @brief checks if a Key contained a binary value before its value has been encrypted by the gpgme plugin.
      45             :  *
      46             :  * If the metakey ELEKTRA_GPGME_META_BINARY has the value "1" it is considered to be true.
      47             :  * Every other value or the non-existence of the metakey is considered to be false.
      48             :  *
      49             :  * @param k the Key to be checked
      50             :  * @retval 0 if the Key contained a string value before encryption
      51             :  * @retval 1 if the Key contained a binary value before encryption
      52             :  */
      53           4 : static int isOriginallyBinary (const Key * k)
      54             : {
      55           4 :         const Key * metaEncrypt = keyGetMeta (k, ELEKTRA_GPGME_META_BINARY);
      56           4 :         if (metaEncrypt && strcmp (keyString (metaEncrypt), "1") == 0)
      57             :         {
      58           2 :                 return 1;
      59             :         }
      60             :         return 0;
      61             : }
      62             : 
      63             : /**
      64             :  * @brief lookup if the test mode for unit testing is enabled.
      65             :  * @param conf KeySet holding the plugin configuration.
      66             :  * @retval 0 test mode is not enabled
      67             :  * @retval 1 test mode is enabled
      68             :  */
      69          39 : static int inTestMode (KeySet * conf)
      70             : {
      71          39 :         Key * k = ksLookupByName (conf, ELEKTRA_GPGME_UNIT_TEST, 0);
      72          39 :         if (k && !strcmp (keyString (k), "1"))
      73             :         {
      74           8 :                 return 1;
      75             :         }
      76             :         return 0;
      77             : }
      78             : 
      79             : /**
      80             :  * @brief checks if a given Key k is in the spec namespace.
      81             :  * @retval 0 if the Key k is in the spec namespace.
      82             :  * @retval 1 if the Key k is NOT in the spec namespace.
      83             :  */
      84             : static inline int isSpecNamespace (const Key * k)
      85             : {
      86           6 :         return (keyGetNamespace (k) == KEY_NS_SPEC);
      87             : }
      88             : 
      89             : /**
      90             :  * @brief checks if a given key holds a null value.
      91             :  * @retval 0 if the Key k does not hold a null value.
      92             :  * @retval 1 if the Key k holds a null value.
      93             :  */
      94             : static inline int isNullValue (const Key * k)
      95             : {
      96           6 :         return keyGetValueSize (k) == 0;
      97             : }
      98             : 
      99             : /**
     100             :  * @brief lookup if the text mode is disabled in the plugin config.
     101             :  * Text mode is enabled per default.
     102             :  * @param conf KeySet holding the plugin configuration.
     103             :  * @retval 0 text mode is not enabled
     104             :  * @retval 1 text mode is enabled
     105             :  */
     106           4 : static int isTextMode (KeySet * conf)
     107             : {
     108           4 :         Key * k = ksLookupByName (conf, ELEKTRA_GPGME_CONFIG_TEXTMODE, 0);
     109           4 :         if (k && !strcmp (keyString (k), "0"))
     110             :         {
     111           2 :                 return 0;
     112             :         }
     113             :         return 1;
     114             : }
     115             : 
     116             : /*
     117             :  * @brief invoke gpgme_key_unref on all keys and free the array.
     118             :  * @param recipients the array to be released.
     119             :  */
     120           4 : static void freeRecipientArray (gpgme_key_t * recipients)
     121             : {
     122           4 :         unsigned long index = 0;
     123           4 :         if (recipients)
     124             :         {
     125           4 :                 while (recipients[index])
     126             :                 {
     127           2 :                         gpgme_key_unref (recipients[index++]);
     128             :                 }
     129           2 :                 elektraFree (recipients);
     130             :         }
     131           4 : }
     132             : 
     133             : /**
     134             :  * @brief extract all GPG recipients that shall be used for encryption.
     135             :  * @param config holds the plugin configuration
     136             :  * @param ctx holds the gpgme context to be used
     137             :  * @return the recipients as NULL-terminated array of gpgme_key_t, or just NULL if no recipients is specified in config. Must be freed by
     138             :  * the caller.
     139             :  */
     140           4 : static gpgme_key_t * extractRecipientFromPluginConfig (KeySet * config, Key * errorKey, gpgme_ctx_t ctx)
     141             : {
     142           4 :         gpgme_error_t err;
     143           4 :         gpgme_key_t key;
     144             : 
     145           4 :         keylist_t list;
     146           4 :         Key * gpgRecipientRoot = ksLookupByName (config, ELEKTRA_RECIPIENT_KEY, 0);
     147             : 
     148           4 :         elektraGpgmeKeylistInit (&list);
     149             : 
     150             :         // append root (gpg/key) as recipient
     151           4 :         if (gpgRecipientRoot && strlen (keyString (gpgRecipientRoot)) > 0)
     152             :         {
     153           2 :                 err = gpgme_get_key (ctx, keyString (gpgRecipientRoot), &key, 0);
     154           2 :                 if (err)
     155             :                 {
     156           0 :                         ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (errorKey, "Failed to read the specified GPG key. Reason: %s",
     157             :                                                                 gpgme_strerror (err));
     158           0 :                         elektraGpgmeKeylistFree (&list);
     159           0 :                         return NULL;
     160             :                 }
     161             : 
     162           2 :                 if (key)
     163             :                 {
     164           2 :                         if (!elektraGpgmeKeylistAdd (&list, key))
     165             :                         {
     166           0 :                                 ELEKTRA_SET_OUT_OF_MEMORY_ERROR (errorKey);
     167           0 :                                 elektraGpgmeKeylistFree (&list);
     168           0 :                                 return NULL;
     169             :                         }
     170             :                 }
     171             :         }
     172             : 
     173             :         // append keys beneath root (crypto/key/#_) as recipients
     174           4 :         if (gpgRecipientRoot)
     175             :         {
     176           2 :                 Key * k;
     177             : 
     178           2 :                 ksRewind (config);
     179          10 :                 while ((k = ksNext (config)) != 0)
     180             :                 {
     181           6 :                         if (keyIsBelow (k, gpgRecipientRoot))
     182             :                         {
     183           0 :                                 err = gpgme_get_key (ctx, keyString (k), &key, 0);
     184           0 :                                 if (err)
     185             :                                 {
     186           0 :                                         ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (
     187             :                                                 errorKey, "Failed to read the specified GPG key. Reason: %s", gpgme_strerror (err));
     188           0 :                                         elektraGpgmeKeylistFree (&list);
     189           0 :                                         return NULL;
     190             :                                 }
     191             : 
     192           0 :                                 if (key)
     193             :                                 {
     194           0 :                                         if (!elektraGpgmeKeylistAdd (&list, key))
     195             :                                         {
     196           0 :                                                 ELEKTRA_SET_OUT_OF_MEMORY_ERROR (errorKey);
     197           0 :                                                 elektraGpgmeKeylistFree (&list);
     198           0 :                                                 return NULL;
     199             :                                         }
     200             :                                 }
     201             :                         }
     202             :                 }
     203             :         }
     204             : 
     205           4 :         if (list.size > 0)
     206             :         {
     207           2 :                 unsigned long index = 0;
     208           2 :                 gpgme_key_t tempKey;
     209             : 
     210             :                 // allocate one extra slot for the NULL-terminator
     211           2 :                 gpgme_key_t * keyArray = elektraMalloc ((list.size + 1) * sizeof (gpgme_key_t));
     212           2 :                 if (!keyArray)
     213             :                 {
     214           0 :                         ELEKTRA_SET_OUT_OF_MEMORY_ERROR (errorKey);
     215           0 :                         elektraGpgmeKeylistFree (&list);
     216           0 :                         return NULL;
     217             :                 }
     218             : 
     219           2 :                 elektraGpgmeKeylistRewind (&list);
     220           4 :                 while ((tempKey = elektraGpgmeKeylistNext (&list)))
     221             :                 {
     222           2 :                         keyArray[index++] = tempKey;
     223             :                 }
     224           2 :                 keyArray[index] = NULL;
     225             : 
     226           2 :                 elektraGpgmeKeylistFree (&list);
     227           2 :                 return keyArray;
     228             :         }
     229           2 :         elektraGpgmeKeylistFree (&list);
     230           2 :         return NULL;
     231             : }
     232             : 
     233             : /**
     234             :  * @brief read out the contents of src and place it to dst.
     235             :  * @param src the source of type gpgme_data_t
     236             :  * @param dst the Elektra key of type Key
     237             :  * @param errorKey will hold an error description in case of failure
     238             :  * @param textMode set to 1 if the text mode is enabled.
     239             :  * @retval 1 on success
     240             :  * @retval -1 on failure
     241             :  */
     242           8 : static int transferGpgmeDataToElektraKey (gpgme_data_t src, Key * dst, Key * errorKey, int textMode)
     243             : {
     244           8 :         int returnValue = 1; // success
     245           8 :         off_t ciphertextLen;
     246           8 :         ssize_t readCount;
     247           8 :         char * buffer = NULL;
     248             : 
     249           8 :         ciphertextLen = gpgme_data_seek (src, 0, SEEK_END);
     250           8 :         buffer = (char *) elektraMalloc (ciphertextLen);
     251           8 :         if (!buffer)
     252             :         {
     253           0 :                 ELEKTRA_SET_OUT_OF_MEMORY_ERROR (errorKey);
     254           0 :                 returnValue = -1; // failure
     255           0 :                 goto cleanup;
     256             :         }
     257             : 
     258           8 :         gpgme_data_seek (src, 0, SEEK_SET);
     259           8 :         readCount = gpgme_data_read (src, buffer, ciphertextLen);
     260           8 :         if (readCount != ciphertextLen)
     261             :         {
     262           0 :                 ELEKTRA_SET_INTERNAL_ERRORF (errorKey, "An error occurred during the en/decryption process. Reason: %s", strerror (errno));
     263           0 :                 returnValue = -1; // failure
     264           0 :                 goto cleanup;
     265             :         }
     266             : 
     267           8 :         if (textMode)
     268             :         {
     269           2 :                 keySetString (dst, buffer);
     270             :         }
     271             :         else
     272             :         {
     273           6 :                 keySetBinary (dst, buffer, ciphertextLen);
     274             :         }
     275             : 
     276           8 : cleanup:
     277           8 :         if (buffer)
     278             :         {
     279           8 :                 elektraFree (buffer);
     280             :         }
     281           8 :         return returnValue;
     282             : }
     283             : 
     284             : /**
     285             :  * @brief Concatenate the key IDs held by the argument invalidKeys.
     286             :  * @param result will hold a pointer to the allocated list of key IDs. Must be freed by the caller. Will be set to NULL if the memory
     287             :  * allocation fails.
     288             :  * @param invalidKeys the list of gpgme_invalid_key_t elements to concatenate.
     289             :  */
     290           0 : static void generateInvalidKeyErrorMsg (char ** result, gpgme_invalid_key_t invalidKeys)
     291             : {
     292           0 :         size_t length = 0;
     293           0 :         gpgme_invalid_key_t iterator = invalidKeys;
     294             : 
     295           0 :         while (iterator)
     296             :         {
     297             :                 // + 2 characters: coma and blank -> <keyID>, <keyID>, ...
     298           0 :                 length += strlen (iterator->fpr) + 2;
     299           0 :                 iterator = iterator->next;
     300             :         }
     301             : 
     302           0 :         if (length == 0)
     303             :         {
     304           0 :                 *result = NULL;
     305           0 :                 return;
     306             :         }
     307             : 
     308             :         // +1 for the NULL terminator
     309           0 :         *result = elektraMalloc (length + 1);
     310           0 :         if (!result)
     311             :         {
     312             :                 // memory allocation error must be handled by the caller
     313             :                 return;
     314             :         }
     315             : 
     316             :         iterator = invalidKeys;
     317           0 :         while (iterator)
     318             :         {
     319           0 :                 strncat (*result, iterator->fpr, length);
     320           0 :                 length -= strlen (iterator->fpr);
     321           0 :                 if (iterator->next)
     322             :                 {
     323           0 :                         strncat (*result, ", ", length);
     324           0 :                         length -= 2;
     325             :                 }
     326           0 :                 iterator = iterator->next;
     327             :         }
     328             : }
     329             : 
     330             : /**
     331             :  * @brief Encrypt all Keys in the KeySet "data" that have a meta-key "gpg/encrpyt" set.
     332             :  * @see isMarkedForEncryption (const Key * k)
     333             :  * @param handle holds the plugin configuration.
     334             :  * @param data the KeySet to be encrypted.
     335             :  * @param errorKey will hold and error description if an operation fails.
     336             :  * @retval 1 on success.
     337             :  * @retval -1 on failure. In this case errorKey will provide a description.
     338             :  */
     339           4 : static int gpgEncrypt (Plugin * handle, KeySet * data, Key * errorKey)
     340             : {
     341           4 :         int returnValue = 1; // success per default
     342           4 :         int textMode;
     343           4 :         Key * k;
     344             : 
     345           4 :         gpgme_key_t * recipients;
     346           4 :         gpgme_ctx_t ctx;
     347           4 :         gpgme_error_t err;
     348           4 :         gpgme_encrypt_flags_t encryptFlags = GPGME_ENCRYPT_NO_ENCRYPT_TO;
     349             : 
     350           4 :         err = gpgme_new (&ctx);
     351           4 :         if (err)
     352             :         {
     353           0 :                 ELEKTRA_SET_INSTALLATION_ERRORF (errorKey, "Failed to initialize gpgme. Reason: %s", gpgme_strerror (err));
     354           0 :                 return -1; // at this point nothing has been initialized
     355             :         }
     356             : 
     357           4 :         KeySet * pluginConfig = elektraPluginGetConfig (handle);
     358             : 
     359           4 :         textMode = isTextMode (pluginConfig);
     360           4 :         if (textMode)
     361             :         {
     362           2 :                 gpgme_set_armor (ctx, 1);
     363             :         }
     364             : 
     365           4 :         recipients = extractRecipientFromPluginConfig (pluginConfig, errorKey, ctx);
     366           4 :         if (!recipients)
     367             :         {
     368           2 :                 ELEKTRA_SET_VALIDATION_SEMANTIC_ERROR (errorKey, "No valid recipients were specified");
     369           2 :                 returnValue = -1;
     370           2 :                 goto cleanup;
     371             :         }
     372             : 
     373           2 :         if (inTestMode (pluginConfig))
     374             :         {
     375           2 :                 encryptFlags |= GPGME_ENCRYPT_ALWAYS_TRUST;
     376             :         }
     377             : 
     378           2 :         ksRewind (data);
     379          10 :         while ((k = ksNext (data)))
     380             :         {
     381           8 :                 gpgme_data_t input;
     382           8 :                 gpgme_data_t ciphertext;
     383           8 :                 gpgme_encrypt_result_t result;
     384           8 :                 gpgme_invalid_key_t invalidKey;
     385             : 
     386           8 :                 if (!isMarkedForEncryption (k) || isSpecNamespace (k) || isNullValue (k))
     387             :                 {
     388           4 :                         continue;
     389             :                 }
     390             : 
     391             :                 // preserve the data type of k (string, binary)
     392           4 :                 if (!keyIsBinary (k))
     393             :                 {
     394           2 :                         err = gpgme_data_new_from_mem (&input, keyString (k), strlen (keyString (k)) + 1, 0);
     395             :                 }
     396             :                 else
     397             :                 {
     398           2 :                         keySetMeta (k, ELEKTRA_GPGME_META_BINARY, "1");
     399           2 :                         err = gpgme_data_new_from_mem (&input, keyValue (k), keyGetValueSize (k), 0);
     400             :                 }
     401           4 :                 if (err)
     402             :                 {
     403           0 :                         returnValue = -1;
     404           0 :                         ELEKTRA_SET_INTERNAL_ERRORF (errorKey, "Internal error: %s", gpgme_strerror (err));
     405           0 :                         goto cleanup;
     406             :                 }
     407             : 
     408           4 :                 err = gpgme_data_new (&ciphertext);
     409           4 :                 if (err)
     410             :                 {
     411           0 :                         returnValue = -1;
     412           0 :                         ELEKTRA_SET_INTERNAL_ERRORF (errorKey, "Internal error: %s", gpgme_strerror (err));
     413           0 :                         gpgme_data_release (input);
     414           0 :                         goto cleanup;
     415             :                 }
     416             : 
     417           4 :                 err = gpgme_op_encrypt (ctx, recipients, encryptFlags, input, ciphertext);
     418           4 :                 if (err)
     419             :                 {
     420           0 :                         returnValue = -1;
     421           0 :                         ELEKTRA_SET_INTERNAL_ERRORF (errorKey, "Internal error: %s", gpgme_strerror (err));
     422           0 :                         gpgme_data_release (ciphertext);
     423           0 :                         gpgme_data_release (input);
     424           0 :                         goto cleanup;
     425             :                 }
     426             : 
     427           4 :                 result = gpgme_op_encrypt_result (ctx);
     428           4 :                 invalidKey = result->invalid_recipients;
     429           4 :                 if (invalidKey)
     430             :                 {
     431           0 :                         char * errorMsg = NULL;
     432           0 :                         returnValue = -1;
     433           0 :                         generateInvalidKeyErrorMsg (&errorMsg, invalidKey);
     434           0 :                         if (errorMsg)
     435             :                         {
     436           0 :                                 ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (errorKey, "Invalid key ID(s): %s", errorMsg);
     437           0 :                                 elektraFree (errorMsg);
     438             :                         }
     439             :                         else
     440             :                         {
     441           0 :                                 ELEKTRA_SET_OUT_OF_MEMORY_ERROR (errorKey);
     442             :                         }
     443           0 :                         gpgme_data_release (ciphertext);
     444           0 :                         gpgme_data_release (input);
     445           0 :                         goto cleanup;
     446             :                 }
     447             : 
     448             :                 // update Elektra key to encrypted value
     449           4 :                 if (transferGpgmeDataToElektraKey (ciphertext, k, errorKey, textMode) != 1)
     450             :                 {
     451             :                         // error description has been set by transferGpgmeDataToElektraKey()
     452           0 :                         returnValue = -1;
     453           0 :                         gpgme_data_release (ciphertext);
     454           0 :                         gpgme_data_release (input);
     455           0 :                         goto cleanup;
     456             :                 }
     457             : 
     458           4 :                 gpgme_data_release (ciphertext);
     459           4 :                 gpgme_data_release (input);
     460             :         }
     461             : 
     462           2 : cleanup:
     463           4 :         freeRecipientArray (recipients);
     464           4 :         gpgme_release (ctx);
     465           4 :         return returnValue;
     466             : }
     467             : 
     468             : /**
     469             :  * @brief Decrypt all Keys in the KeySet "data" that have a meta-key "gpg/encrpyt" set.
     470             :  * @see isMarkedForEncryption (const Key * k)
     471             :  * @param handle holds the plugin configuration.
     472             :  * @param data the KeySet to be decrypted.
     473             :  * @param errorKey will hold and error description if an operation fails.
     474             :  * @retval 1 on success.
     475             :  * @retval -1 on failure. In this case errorKey will provide a description.
     476             :  */
     477           0 : static int gpgDecrypt (ELEKTRA_UNUSED Plugin * handle, KeySet * data, Key * errorKey)
     478             : {
     479           0 :         int returnValue = 1; // success
     480           0 :         Key * k;
     481             : 
     482           0 :         gpgme_ctx_t ctx;
     483           0 :         gpgme_error_t err;
     484             : 
     485           0 :         err = gpgme_new (&ctx);
     486           0 :         if (err)
     487             :         {
     488           0 :                 ELEKTRA_SET_INSTALLATION_ERRORF (errorKey, "Failed to initialize gpgme. Reason: %s", gpgme_strerror (err));
     489           0 :                 return -1; // at this point nothing has been initialized
     490             :         }
     491             : 
     492           0 :         ksRewind (data);
     493           0 :         while ((k = ksNext (data)) != 0)
     494             :         {
     495           0 :                 if (!isMarkedForEncryption (k) || isSpecNamespace (k) || isNullValue (k))
     496             :                 {
     497           0 :                         continue;
     498             :                 }
     499             : 
     500           0 :                 gpgme_data_t ciphertext;
     501           0 :                 gpgme_data_t plaintext;
     502           0 :                 int originallyBinary = isOriginallyBinary (k);
     503             : 
     504           0 :                 err = gpgme_data_new_from_mem (&ciphertext, keyValue (k), keyGetValueSize (k), 0);
     505           0 :                 if (err)
     506             :                 {
     507           0 :                         ELEKTRA_SET_INTERNAL_ERRORF (errorKey, "Internal error: %s", gpgme_strerror (err));
     508           0 :                         returnValue = -1;
     509           0 :                         goto cleanup;
     510             :                 }
     511             : 
     512           0 :                 err = gpgme_data_new (&plaintext);
     513           0 :                 if (err)
     514             :                 {
     515           0 :                         ELEKTRA_SET_INTERNAL_ERRORF (errorKey, "Internal error: %s", gpgme_strerror (err));
     516           0 :                         returnValue = -1;
     517           0 :                         gpgme_data_release (ciphertext);
     518           0 :                         goto cleanup;
     519             :                 }
     520             : 
     521           0 :                 err = gpgme_op_decrypt (ctx, ciphertext, plaintext);
     522           0 :                 if (err)
     523             :                 {
     524           0 :                         ELEKTRA_SET_INTERNAL_ERRORF (errorKey, "Internal error: %s", gpgme_strerror (err));
     525           0 :                         returnValue = -1;
     526           0 :                         gpgme_data_release (plaintext);
     527           0 :                         gpgme_data_release (ciphertext);
     528           0 :                         goto cleanup;
     529             :                 }
     530             : 
     531           0 :                 if (transferGpgmeDataToElektraKey (plaintext, k, errorKey, !originallyBinary) != 1)
     532             :                 {
     533             :                         // error description has been set by transferGpgmeDataToElektraKey()
     534           0 :                         returnValue = -1;
     535           0 :                         gpgme_data_release (plaintext);
     536           0 :                         gpgme_data_release (ciphertext);
     537           0 :                         goto cleanup;
     538             :                 }
     539             : 
     540           0 :                 gpgme_data_release (plaintext);
     541           0 :                 gpgme_data_release (ciphertext);
     542             :         }
     543             : 
     544           0 : cleanup:
     545           0 :         gpgme_release (ctx);
     546           0 :         return returnValue;
     547             : }
     548             : 
     549          37 : int elektraGpgmeOpen (Plugin * handle, Key * errorKey)
     550             : {
     551          37 :         gpgme_error_t err;
     552             : 
     553             :         // if the plugin is used by the unit test, initialization of libgpgme is done by the test code
     554          37 :         KeySet * pluginConfig = elektraPluginGetConfig (handle);
     555          37 :         if (inTestMode (pluginConfig))
     556             :         {
     557             :                 return 1; // success
     558             :         }
     559             : 
     560             :         // initialize libgpgme
     561          31 :         gpgme_check_version (NULL);
     562             :         // NOTE the code below is recommended by the gpgme manual
     563             :         //      gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
     564             :         //#ifndef HAVE_W32_SYSTEM
     565             :         //      gpgme_set_locale (NULL, LC_MESSAGES, setlocale (LC_MESSAGES, NULL));
     566             :         //#endif
     567             : 
     568          31 :         err = gpgme_engine_check_version (GPGME_PROTOCOL_OpenPGP);
     569          31 :         if (err)
     570             :         {
     571           0 :                 ELEKTRA_SET_INTERNAL_ERRORF (errorKey, "Internal error: %s", gpgme_strerror (err));
     572           0 :                 return -1; // failure
     573             :         }
     574             :         return 1; // success
     575             : }
     576             : 
     577          39 : int elektraGpgmeClose (ELEKTRA_UNUSED Plugin * handle, ELEKTRA_UNUSED Key * errorKey)
     578             : {
     579             :         // at the moment there is nothing to do
     580          39 :         return 1; // success
     581             : }
     582             : 
     583          31 : int elektraGpgmeGet (Plugin * handle, KeySet * ks, Key * parentKey)
     584             : {
     585             :         // publish the module configuration to Elektra (establish the contract)
     586          31 :         if (!strcmp (keyName (parentKey), "system:/elektra/modules/" ELEKTRA_PLUGIN_NAME))
     587             :         {
     588          29 :                 KeySet * moduleConfig = ksNew (30,
     589             : #include "contract.h"
     590             :                                                KS_END);
     591          29 :                 ksAppend (ks, moduleConfig);
     592          29 :                 ksDel (moduleConfig);
     593          29 :                 return 1; // success
     594             :         }
     595             : 
     596           2 :         return gpgDecrypt (handle, ks, parentKey);
     597             : }
     598             : 
     599           4 : int elektraGpgmeSet (Plugin * handle, KeySet * ks, Key * parentKey)
     600             : {
     601           4 :         return gpgEncrypt (handle, ks, parentKey);
     602             : }
     603             : 
     604           0 : int elektraGpgmeCheckconf (Key * errorKey, KeySet * conf)
     605             : {
     606           0 :         gpgme_ctx_t ctx;
     607           0 :         gpgme_error_t err;
     608             : 
     609           0 :         err = gpgme_new (&ctx);
     610           0 :         if (err)
     611             :         {
     612           0 :                 ELEKTRA_SET_INSTALLATION_ERRORF (errorKey, "Failed to initialize gpgme. Reason: %s", gpgme_strerror (err));
     613           0 :                 return -1; // at this point nothing has been initialized
     614             :         }
     615             : 
     616           0 :         gpgme_key_t * recipients = extractRecipientFromPluginConfig (conf, errorKey, ctx);
     617           0 :         gpgme_release (ctx);
     618             : 
     619           0 :         if (recipients)
     620             :         {
     621           0 :                 freeRecipientArray (recipients);
     622             :         }
     623             :         else
     624             :         {
     625           0 :                 ELEKTRA_SET_VALIDATION_SEMANTIC_ERROR (errorKey, "No valid recipients were specified");
     626           0 :                 return -1; // failure
     627             :         }
     628           0 :         return 1; // success
     629             : }
     630             : 
     631          35 : Plugin * ELEKTRA_PLUGIN_EXPORT
     632             : {
     633             :         // clang-format off
     634          35 :         return elektraPluginExport(ELEKTRA_PLUGIN_NAME,
     635             :                         ELEKTRA_PLUGIN_OPEN,  &elektraGpgmeOpen,
     636             :                         ELEKTRA_PLUGIN_CLOSE, &elektraGpgmeClose,
     637             :                         ELEKTRA_PLUGIN_GET,   &elektraGpgmeGet,
     638             :                         ELEKTRA_PLUGIN_SET,   &elektraGpgmeSet,
     639             :                         ELEKTRA_PLUGIN_END);
     640             : }

Generated by: LCOV version 1.13